navigator.keyboard.lock()
(from the original explainer)
Richly interactive web sites, games and remote desktop/application streaming experiences want to provide an immersive, full screen experience. Sites need access to special keys and keyboard shortcuts in full screen, such as Escape, Alt+Tab, Cmd+`, Ctrl+N, for easily or efficiently navigating through windows, tabs, applications, menus and gaming functionality. Without access to these keys, it can be challending for developers to embrace the web for these types of applications.
The current Lock API allows developers to specify a set of keys, but if no keys are specified it will by default capture all keys at both the Browser and System level. Feedback from developers indicates that they would prefer the default to capture only the Browser Keys. This document describes our proposal for updating the Lock API.
There are two groups of keys that can be captured, based on where they are currently being handled.
-
Browser Keys are keys that are currently handled by the user agent (the "browser"). Examples of Browser Keys are Ctrl-S or Ctrl-T.
-
System Keys are keys that are handled by the underlying operating sytesm. Examples of System Keys are Alt-Tab (Windows) and Command-Tab (Mac).
Based on API usage so far, users of this API fall into 3 groups:
-
(I) Give me all the Browser Keys
-
E.g., Remote access where browser keys are sent to the remote machine, but the user can still use OS shortcuts to switch between virtual desktops locally.
-
E.g., Playing a game (local or streaming), where browser shortcuts are used in-game, but the player can Alt-Tab to quickly switch to another (e.g., a chat) application.
-
-
(II) Give me some of the Browser Keys (I'll tell you which ones)
-
E.g., Playing a game (local or streaming), where some, but not all, of the browser shortcuts are handled by the game and the others are handled by the browser.
-
E.g., Remote access where most browser keys are sent to the remote machine, but a few are handled by the local machine. OS shortcuts are handled by the local machine.
-
-
(III) Give me all the keys (Browser and System)
-
E.g., Remote access where all Browser and System keys are sent to the remote machine. A concrete example is the need for the Escape key to be sent to the remote machine so that a developer can effectively use VI or emacs.
-
E.g., Playing a web-based fullscreen game that makes use of Alt-Tab in game and doesn't want the OS to handle that combination to switch away from the game.
-
Almost everything.
Fullscreen must still be active for the API. Interaction with Pointer Lock and the Escape key does not change.
There are still only two methods: lock()
and unlock()
, and the lock()
method returns a Promise.
The current API defaults to capturing all keys (Browser and System). The proposal changes the default to just capture Browser Keys.
The lock()
method accepts an array of DomKeys to lock/capture. These keys can be a mix of Browser and
System level keys. If an array is not specified, then all keys (Browser and System) are captured
lock()
returns a promise which either resolves w/o a return value or rejects with an error.
Subsequent calls to lock()
override the previous parameters passed.
For example, if lock(['KeyA'])
was called and then lock(['KeyB'])
was called, only KeyB
would be locked.
Modify the lock()
so that
- 'lock` With no arguments means the developer is only requesting Browser keys (cf. the current API which captures both Browser and System keys).
lock
with arguments means the developer wants a subset of Browser keys.- A special argument value may be passed to indicate that System keys are desired.
Overall, the method signature stays the same, but the default behavior and the method for capturing System keys changes.
While only Chromium-based browsers currently implement this API, making Browser Keys the default simplifies the minimum implementation requirements.
Supporting Browser Keys requires only changes to the user agent's input pipeline, whereas supporting System Keys requires that the user agent registers an OS level input hook to get access to these keys. Thus, supporting System key capture is significantly more complex to implement that supporting only Browser keys.
Recognizing this additional complexity, we can split the specification into 2 levels:
- Level 1 support:
Lock()
captures all Browser KeysLock(<list of keys>)
captures just the specified Browser Keys
- Level 2 support:
Lock(<special value>)
captures all Browser Keys + all supported System Keys
While no other browser has expressed interest in supporting this API, simplifying the implementation requirements makes it more likely to be considered. We are actively seeking feedback from other browser vendors on this matter.
There are only a few users of the API currently, so making this change shouldn't be a large burden.
The common use case is for applications that want to capture all Browser Keys. This change makes it easier for this use case.
The only current users who will be "broken" by this change are those that need both Browser and System Keys. This is the more rare use case (typically for remote access or remote shell application) so there are few application that need to be transitioned. These apps will need to be updated to explicitly request System keys.
Currently, we propose providing a special value (like "System Keys") to request System key capture:
Lock() <- All Browser keys
Lock(['KeyA']) <- Only Browser keys that involve 'a'
Lock("SystemKeys") <- All System (and browser) keys
However, the exact definition of that special value is still under consideration.
We also considered the following alternate approaches:
-
Adding new methods to the API
- We could add new methods to the API (like
lockBrowserKeys()
andlockAllKeys()
) instead of changing the implementation of thelock()
method. - This would make feature detection (to detect old vs. new version) easier, but it means that we would need to define the behavior when both the old and new APIs were used at the same time.
- We could add new methods to the API (like
-
Adding version info
- Alternately we could add a version number somewhere (e.g., on
navigator.keyboard
) that could be queried to determine iflock()
was the old or new version. - This would make it easy to distinguish the old vs new version, but this is not a typical pattern for web platform APIs.
- Alternately we could add a version number somewhere (e.g., on
In the end, we felt that it was better to propose simply fixing the current API rather than making the API description more complicated than it needs to be.
Privacy and security considerations are covered in the current draft specification. The changes proposed here do not change any of the assumptions that would impact privacy or security.