The why:
The reason you can't get the shift key state from stdin is because the shift key is not a byte that goes into stdin, which is just a stream of bytes and doesn't directly interact with the keyboard.
What's actually input:
For example if you were to run the following code and press Shift+Enter (then Ctrl+C):
process.stdin.on('data', d => {
console.log([d]);
});
You would see something like the following echoed back:
$ node main.mjs
[ <Buffer 0a> ]
^C
As you can see, there is only a single 0x0A
or \n
character with no indication the Shift key was pressed.
You can repeat this process with other tools, to confirm it's not just a node thing.
$ cat > stdin.txt
^C
$ xxd stdin.txt
00000000: 0a .
Here cat
read a single newline character from stdin and wrote it to a file.
Why node stdin keypress events can have shift
= true
:
If we take a look at emitKeys
in lib/internal/readline/utils.js
we can see how the shift key is inferred based on certain input. For example, you can see that for alpha-numeric characters, the shift state is inferred based on if the character is upper-case or not. It doesn't actually know what the state of the shift key is, and if you were to paste in a capital A
it would assume that shift
is true
, but not meta
or ctrl
.
} else if (RegExpPrototypeExec(/^[0-9A-Za-z]$/, ch) !== null) {
// Letter, number, shift+letter
key.name = StringPrototypeToLowerCase(ch);
key.shift = RegExpPrototypeExec(/^[A-Z]$/, ch) !== null;
key.meta = escaped;
Essentially it's faking an event that resembles what you might see in the browser.
What you would have to do:
To know the actual state of the shift key you would have to query that information from the OS. You would likely need a native code library with implementations for every OS you wish to support, using whatever system API's are available in each OS to query this information. I don't know of any existing 3rd party modules and didn't find one in a search. Also keep in mind this would not work over ssh.
This is why multiline input into command prompts typically require escaping the newline character, or have some way of detecting the expression was incomplete.
As I understand it some terminal apps like iTerm apps can also detect the pasting of multiline input and buffer it together in a single write to stdin, but those apps have access to more than just stdin to achieve this.