Skip to content

Latest commit

 

History

History
192 lines (137 loc) · 7.96 KB

proposal.md

File metadata and controls

192 lines (137 loc) · 7.96 KB

Keyboard Map

A proposal to provide an API to return the |key| value for a given |code|.

DRAFT: garykac@

Overview

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.

Goals include:

  • Being able to convert from a code value (with no modifiers) into a key value that can be shown to the user to identify the key.
  • Adding an event when the active keyboard layout changes.

Non-goals include:

  • Identifying a keyboard layout or locale
  • Being able to convert from a code value + modifiers into the key 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 of code values required to generate that value, given the current locale and layout.

Background

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.

User Scenarios

Keypress instructions in Games

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

Describe keyboard shortcuts

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.

Examples

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',
  ...
}

Keyboard Map API

This section provides more details about the proposed API.

navigator.keyboard

This proposal would have a navigator.keyboard object (already proposed as part of the Keyboard Lock API).

Requesting the keyboard map

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.

keyboardchange Event

To detect when the keyboard layout has changed, pages can listen for the keyboardchange event, which will fire whenever the current keyboard layout changes.

Alternative Proposals

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 a key given a code and a locale.

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.

Privacy Concerns

Fingerprinting

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.

Mitigations

Require [SecureContext] for this feature.

Acknowledgements

Thanks to…

References

[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/