Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need virtual key codes #377

Open
laughinghan opened this issue May 16, 2024 · 3 comments
Open

Need virtual key codes #377

laughinghan opened this issue May 16, 2024 · 3 comments

Comments

@laughinghan
Copy link

laughinghan commented May 16, 2024

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).

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 and by WebKit 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; 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" (context, original)?

  • 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 or Shift with punctuation/symbols, only 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.
@oliviertassinari
Copy link

oliviertassinari commented Aug 18, 2024

Yes! We are facing the same problem in mui/mui-x#14220 (comment) to detect the copy-paste shortcuts.

Only event.keyCode seems to work to detect those. It's still the only solution working in https://stackoverflow.com/questions/2903991/how-to-detect-ctrlv-ctrlc-using-javascript too.

The problem is that this is deprecated in https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode:

SCR-20240818-qnxg

So the current state of things feels broken.

@masayuki-nakano
Copy link

First of all, .keyCode values cannot be changed on the browser side because the values are just arbitrary values, i.e., do not have meaning. Therefore, web apps handle .keyCode values with checking UA etc. So, even if all browsers start using exactly same rules to map .keyCode values, existing web apps using .keyCode values will be broken. So, if .key and .code are not enough, there should be new API.

In my experience at implementing the shortcut key handling rules of Firefox, completely compatible behavior between browsers and/or platforms may be impossible. Especially when Shift key is required, there are some open bugs in Firefox with some keyboard layouts which map punctuation to numeric keys. E.g., Ctrl + Shift + 1 may be conflict with Ctrl + ! if ! is mapped to Digit1 key.

Additionally, some keyboard layout users use 2 keyboard layouts, one is ASCII capable and the other is not so. Then, even if the ASCII capable keyboard layout is not selected, the user wants to work shortcut keys as the ASCII capable keyboard layout is selected. So, this additional information requires to store in keydown events.

Similarly, some keyboard layout may switch ASCII character mapping when it works with some modifiers. E.g., a keyboard layout may be Dvorak layout, but QWERTY if Ctrl or something is pressed. This is also fixable with the above approach.

Finally, using punctuation with Shift and/or AltGr for shortcut may make specific keyboard layout users inaccessible. For avoiding this issue completely, it might be better to make new API work only when the key combination matches only with [a-z0-9 ].

@laughinghan
Copy link
Author

@masayuki-nakano

web apps handle .keyCode values with checking UA etc

Actually, .keyCode behaves consistently across browsers for alphanumeric and functional keys, it's only punctuation/symbol keys that differ wildly, according to this comprehensive table of keyCode values across browsers (see section 3.3. Key Code Values): https://unixpapa.com/js/key.html

That's why in my "Recommended Workaround" section I recommended that shortcuts that use Alt should only be used with alphanumeric and functional keys. In retrospect, that's true of Shift as well.

In my experience at implementing the shortcut key handling rules of Firefox, completely compatible behavior between browsers and/or platforms may be impossible. Especially when Shift key is required, there are some open bugs in Firefox with some keyboard layouts which map punctuation to numeric keys. E.g., Ctrl + Shift + 1 may be conflict with Ctrl + ! if ! is mapped to Digit1 key.

I don't understand this paragraph. On a US QWERTY keyboard, Ctrl + Shift + 1 and Ctrl + ! are inherently conflicting. That doesn't seem like a Firefox bug? That seems like that would be true in every browser and on every platform, and wouldn't be an obstacle to cross-browser compatibility at all?

This is also fixable with the above approach.

What approach?

it might be better to make new API work only when the key combination matches only with [a-z0-9 ]

If you accept this constraint, .keyCode is actually already does what you want, as noted above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants