3

I'm working on this special input and I need to allow / disallow some keys from being typed by the user.

I'm doing the validation on the onKeyDown handler.

This is what I was doing at first:

const ALLOWED_KEYS = [
  "Ctrl", "Meta", "Shift","Home", "End", 
  "Backspace", "Delete", "ArrowLeft", "ArrowRight", "Tab", 
  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 
  ".", ","
];

function onKeyDown(event) {
  if (ALLOWED_KEYS.indexOf(event.key) === -1) {
    event.preventDefault();
  }
}

But I was worried that the string names of the keys were not consistent across browsers, so someone here on SO told me that I should change to event.keyCode instead of event.key.

And on this link I could check each key code: https://www.w3.org/2002/09/tests/keys.html

const DIGITS_COMMA_POINT_KEY_CODES = [
  48,49,50,51,52,53,54,55,56,57,        // 0-9 NORMAL KEYBOARD
  96,97,98,99,100,101,102,103,104,105,  // 0-9 NUMERIC KEYPAD
  110,188,                              // COMMA NORMAL AND NUMERIC KEYPAD
  190,194                               // POINT NORMAL AND NUMERIC KEYPAD
];

function onKeyDown(event) {
  if (DIGITS_COMMA_POINT_KEY_CODES.indexOf(event.keyCode) === -1) {
    event.preventDefault();
  }
}

Anyway, both options were working on Chrome Desktop, but failing in Chrome Mobile.

When I test the keyCodes from my Android mobile device I get completely different numbers:

Example:

KEY CODES FOR THE CHAR "0"

DESKTOP NORMAL KEYBOARD : 48
DESKTOP NUMERIC KEYPAD : 96
ANDROID MOBILE KEYBOARD : 229  (EVERY DIGIT SHOW AS 229)

-----------------

KEY CODES FOR THE CHAR "," (COMMA)

DESKTOP NORMAL KEYBOARD : 188
DESKTOP NUMERIC KEYPAD : 110
ANDROID MOBILE KEYBOARD : 229   (EVERY DIGIT, COMMA AND POINT SHOW AS 229)

PS: On Android Mobile, all the digits, comma and point seem to return keyCode as 229 on https://www.w3.org/2002/09/tests/keys.html

UPDATE1:

Just tested with event.charCode but every key logs as charCode: 0

UPDATE2:

On this link: https://javascript.info/keyboard-events Every key from my Android Chrome Mobile shows up as Unidentified. This is weird.

UPDATE3:

This is an issue with Chrome Mobile. Firefox Mobile handles it perfectly. Haven't tested on other browsers.

Keycode is always zero in Chrome for Android

And this bug was reported in Chromium in 2012:

https://bugs.chromium.org/p/chromium/issues/detail?id=118639

QUESTION

What is the universal way to detect the typed key that should work on every keyboard, browser or system?

cbdeveloper
  • 27,898
  • 37
  • 155
  • 336
  • @stacks Nothing works. There's a work around this. I got to keep track of the `caretPosition` and react the `char` at that position to get the `charCode`. And be aware that `charCode` might not be the same as the `keyCode`. – cbdeveloper Apr 16 '20 at 11:44
  • Nice work! Yes I know that. This is quite strange but at least we learnt together about key events! I upvoted your post before so somebody could answer you but unluckily nobody came at the right time. – stacks Apr 16 '20 at 12:09
  • Did you find a solution for this? I'm also facing this issue and not being able to detect Backspace on custom android keyboards. The native android keyboard works though. – Nuwan Karunarathna May 18 '21 at 11:07

2 Answers2

2

From all the research that I did, here is the answer:

If you plan to support Chrome Mobile on Android, DO NOT use onKeyDown (and probably other KeyboardEvents such as onKeyPres and onKeyUp) because you will not be able to read the keys that are being typed.

This is a Chromium bug. The same happens on my Samsung Internet, since it's also Chromium-based.

There's an issue opened about this topic on Chromium since 2012. And I'm writing this in 2020.

https://bugs.chromium.org/p/chromium/issues/detail?id=118639

And there are heated discussions going on in there for the past 8 years.

This problem does not happen in Android Firefox, but somehow this is not a trivial thing to fix in Chromium. Don't know why.


I was looking for a solution for this, because when you call event.preventDefault inside the onKeyDown handler, you do not get a caret jump (at least on Mobile Chrome you don't). While if you are fixing the input value in the onChange handler you will need to deal with caret jumps.

I've ended up dealing with the caret jumps.

EDIT: It is not a bug anymore, as in the status of the bug you shared is wontFix

BalB
  • 107
  • 1
  • 13
cbdeveloper
  • 27,898
  • 37
  • 155
  • 336
1

I used beforeInput handler which works with both textarea and input tags. You can read more about this handler here. I found the inputType to vary across devices -- it was insertText on Mac Chrome browser and insertCompositionalText on Chrome Android Browser. To test on various devices, I played around with this JSFiddle beforeInput example - https://jsfiddle.net/mq5b9v0n/4/

Regardless, it seemed to work for me. Here's an updated version of your code:

function beforeInput(event) {
  if (ALLOWED_KEYS.indexOf(event.data) === -1) {
    event.preventDefault();
  }
}

stbv
  • 11
  • 1