Capture Keys with the Keyboard Lock API

Provide an immersive, full screen experience for a variety of use cases including interactive websites, games, and remote desktop or application streaming.

With more and more users spending most of their time in the browser, richly interactive websites, games, remote desktop streaming, and application streaming strive to provide an immersive, full screen experience. To accomplish this, sites need access to special keys and keyboard shortcuts while they are in full screen mode, so that they can be used for navigation, menus, or gaming. Some examples of the keys that may be required are Esc, Alt + Tab, Cmd + `, and Ctrl + N.

By default, these keys are not available to the web application because they are captured by the browser or the underlying operating system. The Keyboard Lock API enables websites to use all available keys allowed by the host OS (see Browser compatibility).

Ubuntu Linux streamed to a browser tab in macOS Chrome (not running in full screen mode yet).
The problem: a streamed Ubuntu Linux remote desktop not running in full screen mode and without active keyboard lock, so system keys are still captured by the macOS host operating system and the experience is not immersive yet.

Using the Keyboard Lock API

The Keyboard interface of the Keyboard API provides functions that toggle capturing of key presses from the physical keyboard as well as getting information about the user's keyboard layout.

Prerequisite

There are two types of full screen available in modern browsers: JavaScript-initiated via the Fullscreen API and user-initiated via a keyboard shortcut. The Keyboard Lock API is only available when JavaScript-initiated full screen is active. Here's an example of JavaScript-initiated full screen:

await document.documentElement.requestFullscreen();

Feature detection

You can use the following pattern to check if the Keyboard Lock API is supported:

if ('keyboard' in navigator && 'lock' in navigator.keyboard) {
  // Supported!
}

Locking the keyboard

The lock() method of the Keyboard interface returns a promise after enabling the capture of key presses for any or all of the keys on the physical keyboard. This method can only capture keys that are granted access by the underlying operating system. The lock() method takes an array of one or more key codes to lock. If no key codes are provided, all keys will be locked. A list of valid key code values is available in the UI Events KeyboardEvent code Values spec.

Capturing all keys

The following example captures all key presses.

navigator.keyboard.lock();

Capturing specific keys

The following example captures the W, A, S, and D keys. It captures these keys regardless of which modifiers are used with the key press. Assuming a US QWERTY layout, registering "KeyW" ensures that W, Shift + W, Control + W, Control + Shift + W, and all other key modifier combinations with W are sent to the app. The same applies to "KeyA", "KeyS", and "KeyD".

await navigator.keyboard.lock([
  "KeyW",
  "KeyA",
  "KeyS",
  "KeyD",
]);

You can respond to captured key presses using keyboard events. For example this code uses the onkeydown event:

document.addEventListener('keydown', (event) => {
  if ((event.code === 'KeyA') && !(event.ctrlKey || event.metaKey)) {
    // Do something when the 'A' key was pressed, but only
    // when not in combination with the command or control key.
  }
});

Unlocking the keyboard

The unlock() method unlocks all keys captured by the lock() method and returns synchronously.

navigator.keyboard.unlock();

When a document is closed, the browser always implicitly calls unlock().

Demo

You can test the Keyboard Lock API by running the demo on Glitch. Be sure to check out the source code. Clicking the Enter full screen button below launches the demo in a new window so it can enter full screen mode.

Security Considerations

One concern with this API is that it could be used to grab all of the keys and (in conjunction with the Fullscreen API and the PointerLock API) prevent the user from exiting the web page. To prevent this, the spec requires the browser to provide a way for the user to exit from keyboard lock even if all of the keys are requested by the API. In Chrome, this escape hatch is a long (two second) Esc key press to trigger an exit from Keyboard Lock.

Acknowledgements

This article was reviewed by Joe Medley and Kayce Basques. The Keyboard Lock spec is authored by Gary Kacmarcik and Jamie Walch. Hero image by Ken Suarez on Unsplash.