A proposal to provide an API to return the |key| value for a given |code|.
DRAFT: garykac@
Provide an API to convert from a given code
value to a key
value that can be shown to
the user to identify the given key.
- Being able to convert from a
code
value (with no modifiers) into akey
value that can be shown to the user to identify the key. - Adding an event when the active keyboard layout changes.
- Identifying a keyboard layout or locale
- Being able to convert from a
code
value + modifiers into thekey
value that would be generated by the current locale and layout with those modifiers present. - Being able to convert from a
key
value into the set ofcode
values required to generate that value, given the current locale and layout.
On a KeyboardEvent,
the code
attribute encodes
a value that represents the physical location of the key that was pressed. This value ignores
the current locale (e.g., "en-US"), layout (e.g., "dvorak") and modifier state (e.g., "Shift + Control"),
so it is ideally suited for applications (like games) that want to use the keyboard as a set of
generic buttons. The idea behind the code
attribute is that it provides a platform-neutral
scancode for each physical key.
The key
attribute, on the other hand,
contains the value that is generated by the key press, accounting for the locale, layout, and modifier
keys. Almost every Unicode character is a valid key
attribute, along with a number of special
named values (see KeyboardEvent key attribute values),
so there are thousands of possible key
values.
As a simple example of how code
and key
are related, consider the key which is located immediately
to the right of the Tab key. The code
for this key is "KeyQ"
, and when this key is pressed on a
standard en-US layout with no modifiers, the key
value is "q"
. On the same layout, but with the
Shift key held down, the key
value is "Q"
. However, on a standard French keyboard, the key
values
would be "a"
and "A"
, respectively; for Russian, "й"
and "Й"
.
A simple way of obtaining this basic code
to key
mapping is what we are trying to accomplish with this API.
Applications (like games) that use the KeyboardEvent code
attribute to handle key events will often
need to present a message to the user that references a particular key.
E.g., If a game supports the standard WASD keys (to move up/left/down/right), then the instructions for the game need to be able to tell the user which keys to press. On a US-English keyboard, they are 'W', 'A', 'S', 'D', but for French (AZERTY) layout they are 'Z', 'Q', 'S', 'D'.
Some applications make use of keyboard shortcuts that are based on the position of the key rather than the symbol that is generated.
E.g., For Undo/Cut/Copy/Paste, an application may support the 'Z', 'X', 'C' and 'V' keys
along the bottom of the keyboard because they are easy to type with one hand in conjunction
with the (left) control key. This is easily done using the code
values "KeyZ"
, "KeyX"
,
"KeyC"
and "KeyV"
. However, in order to have the UI display the shortcuts, the app needs to know
which key
value will be generated by that key. On a US-English keyboard, the "KeyZ"
key is labeled "Z", but on a French keyboard it is "W" and on a German keyboard it is
labeled "Y".
E.g., a drawing app may have a number of drawing modes arranged from left to right on the screen and may wish to have keyboard shortcuts that correspond to the screen position.
Note the assumption that the labels on the keyboard match the currently active keyboard locale. This is not always true, but since there is no way to know that the actual labels are, this is the best surrogate.
This API returns the mapping for each key:
var dictKeyMap = navigator.keyboard.getKeyboardMap();
where dictKeyMap
is a dictionary where code
maps to key
, e.g.:
{
'KeyA': 'a',
'KeyB': 'b',
...
}
This section provides more details about the proposed API.
This proposal would have a navigator.keyboard
object (already proposed as part of the
Keyboard Lock API).
A static getKeyboardMap()
would return the current keyboard map.
var dictKeyMap = navigator.keyboard.getKeyboardMap();
var keyUp = dictKeyMap.KeyW;
var keyLeft = dictKeyMap.KeyA;
var keyDown = dictKeyMap.KeyS;
var keyRight = dictKeyMap.KeyD;
code
values that correspond to "dead" keys in the current layout should return the corresponding
combining accent character.
To detect when the keyboard layout has changed, pages can listen for the keyboardchange
event,
which will fire whenever the current keyboard layout changes.
Requests for this feature have come up a number of times in the past, and various proposals have been discussed.
- Proposal A - Add a
locale
attribute to each KeyboardEvent. - Proposal B - Add a way to query the set of installed keyboard layouts, and/or get the current layout.
- Proposal C (in conjunction with A or B) - Add
queryKeyCap()
, which would return akey
given acode
and alocale
.
One problem with these proposals is that they rely on being able to enumerate the different keyboard layouts or locales. [BCP47] is the obvious way of encoding this information, but is not ideally suited for this particular application:
- There are a large number of different language/layout combinations. It is probably unreasonable to expect all UAs recognize all of them consistently unless we also provide mapping data.
- Special layouts like Dvorak are supported as extensions and have an odd representation ("en-t-k0-dvorak").
- Encoding the locale like this doesn't give a way to indicate that the user has overridden the default behavior of a key.
Fingerprinting based on the locale was raised as a concern during previous discussions about exposing locale or keyboard layout. This has been made slightly more difficult with the new API, although it is still possible if a site is willing to check each key and use a lookup table or heuristic to determine the locale/layout. Users with custom key overrides would also be identifiable.
Note that this sort of identification can be attempted today, but it requires that the user interact with
the site by typing on the keyboard. Examining the key
and code
attributes on the KeyboardEvent can
sometimes reveal the locale or layout.
Require [SecureContext]
for this feature.
Thanks to…
[BCP47] Tags for Identifying Languages. A. Phillips; M. Davis. IETF. September 2009. IETF Best Current Practice. URL: https://tools.ietf.org/html/bcp47
[UIEvents] UI Events. G. Kacmarcik; T. Leithead. W3C Working Draft, 28 November 2017. URL: https://w3c.github.io/uievents/
[UIEventsCode]
UI Events KeyboardEvent code
Values.
G. Kacmarcik; T. Leithead. W3C Working Draft, 5 October 2017.
URL: https://w3c.github.io/uievents-code/
[UIEventsKey]
UI Events KeyboardEvent key
Values.
G. Kacmarcik; T. Leithead. W3C Working Draft, 4 October 2017.
URL: https://w3c.github.io/uievents-key/