MDN states that KeyboardEvent.which
is deprecated. How can I substitute it for a non-deprecated version?
For example, I have the following:
window.onkeydown = (event) => { console.log(event.which); }
I thought event.key.charCodeAt()
could substitute event.which
, but this won't work for keys such as ALT, CTRL or ENTER, and it only works if event.key.length === 1
:
window.onkeydown = (event) => { console.log(event.key.charCodeAt()); }
To recap, event.which != event.code
and event.which != event.key
, therefore I am unable to simply use event.key
.
Is there a substitute for event.which
which detects combination keypresses including ALT, CTRL or ENTER?
You should avoid using this if possible; it's been deprecated for some time. Instead, you should use KeyboardEvent. code , if it's implemented. Unfortunately, some browsers still don't have it, so you'll have to be careful to make sure you use one which is supported on all target browsers.
Deprecated: This feature is no longer recommended. Though some browsers might still support it, it may have already been removed from the relevant web standards, may be in the process of being dropped, or may only be kept for compatibility purposes.
KeyboardEvent objects describe a user interaction with the keyboard; each event describes a single interaction between the user and a key (or combination of a key with modifier keys) on the keyboard. The event type ( keydown , keypress , or keyup ) identifies what kind of keyboard activity occurred.
TL;DR: These are the rules you should follow:
keypress
event along with e.key
keydown
/keyup
and check the various modifier keys. If you need to detect chords, you may need to build a state machine. Keyboard input is split into two phases - keydown/keyup pairs, which track physical keys being pressed, and composed characters that combines multiple sequences of keys to compute a character.
If you want to know what the operating system thinks the composed sequence is, you should use KeyboardEvent.key
Sample code:
document.getElementById('a').addEventListener('keypress', e => console.log(e.key));
<input id="a" type="text" placeholder="type here">
The reason you want to do this most of the time is because many languages compose characters with several keypresses. The easiest for US-101 keyboards to understand is pressing the shift
key + a
is A
, compared to just pressing a
. For languages like Russian, with the altgr dead key, this becomes especially important.
The point I am trying to make is that doing all of this work yourself - detecting key sequences and determining the correct text output is a hard problem™. It is the job of the operating system for a reason.
Now, for older browsers, you may not want to use e.key
for lack of older support. Then you can fall back to things like which
, or other non-standard approaches.
At some point in the future, keypress may be removed by browsers. The beforeinput event is supposed to be the replacement. However, that event is only supported in chrome, so I'm omitting in here for brevity's sake.
Now then, suppose you are not tracking text, but rather key sequences. This is for things like games, or listening to ctrl-c
etc. In this case, the correct thing to do is to listen to keydown
/keyup
events. For modifier keys, you can simply listen to the ctrlKey
, shiftKey
, and metaKey
properties of the event. See below:
document.getElementById('a').addEventListener('keydown', (e) => { const states = { alt: e.altKey, ctrl: e.ctrlKey, meta: e.metaKey, shift: e.shiftKey, }; const key = e.key; const code = e.code; console.log(`keydown key: ${key}, code: ${code}`, states); });
<input id="a" type="text" placeholder="press ctrl">
As an example, when pressing shift-o on my keyboard, I get the following:
keydown key: Shift, code: ShiftLeft { "alt": false, "ctrl": false, "meta": false, "shift": true } keydown key: O, code: KeyS { "alt": false, "ctrl": false, "meta": false, "shift": true }
Hopefully the states
part is pretty self-evident. They say whether that modifier key was pressed while the other key is down.
The difference between key
and code
has to do with keyboard layouts. I am using the software dvorak layout. Thus when I type the s
key, the scan code that goes to the operating system says s
, but then the OS converts that to o
because it's dvorak. Code in this case always refers to the scan code (physical key being pressed), while the key corresponds to the operating system's best-effort to figure out what the "text" will be. This isn't always possible, especially with other languages. Again, this is why using the key for the keypress
is the right way to go about it.
If this doesn't sound particularly easy, that's because it's not. The last time I was looking at this, I came across the mousetrap library, although I'm not sure I would recommend it, given some of the issues I found. It does, however, show an example of building a state machine to track key chords.
This is also why you need to track keydown
/keyup
if you want to eat keystrokes. Since there is no "text" for ctrl+c, you won't get a proper keypress, and thus the browser will natively handle it. If you want to run your own behavior, you need to e.preventDefault()
on the keydown itself. (Some of the followup events like copy
can also be cancelled, but that's not universally true)
If you also just need to track keys inserted after-the-fact into an input field (or contenteditable div), see the input event.
History: Updated 8/2019 to change keypress->beforeinput
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With