[w3c/uievents] Need virtual key codes (Issue #377)

## The Problem

So in this new world (since ~2020), we're supposed to use `.key` (printable character) and `.code` (scancode) instead of `.keyCode`/`.charCode`/`.which`. This has a big problem:

* Suppose my webapp wants to listen for Ctrl-A and do Select All
* I don't want to use `.code === "KeyA"` because on an AZERTY (eg French) keyboard, that key is labeled `Q`, and my shortcut is for Select All not Select Qll
* I don't want to use `.key === "a"` because on eg a Russian keyboard, the `A` key will have `.key === "ф"`
  * Also if I wanted to listen for Ctrl-Alt-A, then `.key === "å"` for US English on Macs (in every browser), which is annoying

The closest to what I want is actually sad, old, deprecated `.keyCode === 65`! Because `.keyCode` was a kind of cross-platform version of OS virtual key codes (and was cross-browser compatible [at least for alphanumeric keys](https://unixpapa.com/js/key.html)).

## Severity

It seems obvious to me that this is affects almost every webapp with keyboard shortcuts. Indeed, this seems like a much more common use case than games that want physical WASD controls. Even this obscure repo has 3 open tickets on it: #229, #247, #267

## Non-Solutions

In #229, #247, and #267, @garykac offers `Keyboard.getLayoutMap()` as a solution, which shipped to GA in Chrome in 2018. It has since been rejected both [by Mozilla](https://github.com/mozilla/standards-positions/issues/300) and [by WebKit](https://github.com/WICG/keyboard-map/issues/30) for privacy reasons, but to be clear it also doesn't solve the problem in the first place:
* for Ctrl-A, I believe that with a Russian keyboard layout, `keyboardLayoutMap.get("KeyA")` is specced to return `ф` (altho this [doesn't work for me in Chrome on Mac](https://issues.chromium.org/u/1/issues/340949926); instead it has an unreliable return value, see link for details)
  * by contrast, `.keyCode === 65`, same as `A` on US English QWERTY
* for Ctrl-2, `.code === "Digit2"`, but with French AZERTY, `keyboardLayoutMap.get("Digit2") === "é"`, not `2`
  * by contrast, `.keyCode === 50`, same as `2` on US English QWERTY

## Proposed Solution

Rather than the hardware scancode that `.code` is based on, `.keyCode` is supposed to be based on the OS "virtual key code". In my testing, for alphanumeric keys, it's pretty cross-compatible, however for punctuation/symbols it's pretty inconsistent across browsers and reputedly platforms. Can we standardize a cross-platform "virtual key code" using the `KeyA` etc names that respects, rather than ignores, the keyboard layout (QWERTY vs AZERTY vs Dvorak), but doesn't map to character input (`ф`)?

To me, unifying 2 or 3 OS virtual key code tables sounds much simpler than mucking with keyboard layout priority lists.

### Open Questions

Punctuation/symbols are inconsistent because it's pretty unclear what they should do. For example, instead of a `/?` key, French AZERTY has a `:/` key. Should that map to ANSI QWERTY `/?` or `;:`? Or some other universal-ish ["reference keyboard"](https://hacks.mozilla.org/wp-content/uploads/2017/02/keyboard-codes-alphanum1.png) ([context](https://hacks.mozilla.org/2017/03/internationalize-your-keyboard-controls/), [original](https://w3c.github.io/uievents-code/#key-alphanumeric-writing-system))?
* The most interesting question is what do OS platform APIs do for these—and how consistent are they with each other? A sensible mapping to ANSI QWERTY is nice but cross-platform & cross-browser is good enough
* I'm also curious what Java does

## Recommended Workaround

In the meantime, the situation for web devs appears to be:
* First, stick to ASCII for hotkeys, and don't use Alt with punctuation/symbols, only be used with alphanumeric, functional, arrow etc keys.
  * Even if you don't care about international keyboard layouts now, hotkeys are painful to change later.
  * For Alt-alphanumeric, beware that Windows treats Ctrl+Alt as AltGr.
* If, for now, you don't care about international layouts, it's easiest to just look at `.code` and ignore `.key`, because of the Ctrl-Alt-A `.key === "å"` problem
  * There are a bunch of non-Latin languages whose standard layouts are based on QWERTY that this should kinda just work for, actually
* If you start caring about international layouts, then I think you actually want to start ignoring `.code`, instead first looking at `.keyCode`, which for alphanumeric keys should sensibly map back to standard ANSI QWERTY; and if `.keyCode` indicates non-alphanumeric, then look at `.key`.
  * I think for functional, arrow, numpad etc keys, `.key` should be the same as `.code`; and otherwise for punctuation/symbols, in general there may not be a sensible mapping to an ANSI QWERTY/reference layout, but at least it'll tell you the actual punctuation typed, which hopefully is marked on the physical keycaps or understood by the end-user.

-- 
Reply to this email directly or view it on GitHub:
https://github.com/w3c/uievents/issues/377
You are receiving this because you are subscribed to this thread.

Message ID: <w3c/uievents/issues/377@github.com>

Received on Thursday, 16 May 2024 17:59:41 UTC