Debugging Javascript KeyboardEvent Properites

Stumble across this bug when try to move some old code from jQuery to vanilla JS.

To response "Done" button in text input:

1
2
3
4
document.querySelector('#queryInput').addEventListener('keydown', e => { 
if (e.code == 'Enter')
doQuery();
});

Old code with e.which == 13 works fine, as e.which property is depreciated, I tried to use e.code. This works everywhere except Android Chrome.

KeyboardEvent

To identify a keypress with KeyboardEvent, we have:

  • keyCode
  • which
  • code
  • key

keyCode and which are all depreciated and the later isn't even on the document page. So officially we have only code and key. And the code property is a tricky one.

which and keyCode return a numeric value, and they're always the same in my limited test. code and key returns different string value and code give some more "precise" result.

Things get interesting with mobile device and IME.

Here is the document for code

If the input device isn't a physical keyboard, but is instead a virtual keyboard or accessibility device, the returned value will be set by the browser to match as closely as possible to what would happen with a physical keyboard, to maximize compatibility between physical and virtual input devices.

Or in other words, on soft keyboard , don't expect anything for code.

Test Result

PC(Windows 10) Chrome keyCode/which code key
A(upper case,holding shift or caps lock on) 65 keyA A
a(lower case) 65 keyA a
Left Shift 16 ShiftLeft Shift
Enter 13 Enter Enter
Numberpad Enter 13 NumberpadEnter Enter
A with IME* 229 KeyA Process
PC with onscreen keyboard
Same result as hardware keyboard
Android 11 Chrome w/GBoard
A 229 ""(empty string) Unidentified
a 229 ""(empty string) Unidentified
Done 13 ""(empty string) Enter
A with Pinyin IME* N/A N/A N/A
iOS 17 Safari default IME
A 65 KeyA A
a 65 KeyA a
Shift 16 ShiftLeft Shift
Done 13 Enter Enter
A with Pinyin IME* 229 KeyA A

Note:

  • PC and iOS get all key events with IME. on PC, even word selection is logged(as "229/Space" or "229/Digit1" etc.). Nothing on Android during composing at all, and a generic 229/""/Unidentified is sent after word selection.

Also worth noting, while keycode 229 is a special char for composing, Android did a poor job handling it comparing to PC and iOS.

And that's why e.code == 'Enter' fails. I don't know if it's addressed in latest Android but e.code is definitely not a reliable way to get the key pressed. Use either keyCode or key.