This document describes an API for providing access to devices that support the Human Interface Device (HID) protocol.

Introduction

This section is non-normative.

A HID (Human Interface Device) is a type of device that takes input from or provides output to humans. It also refers to the HID protocol, a standard for bi-directional communication between a host and a device that is designed to simplify the installation procedure. The HID protocol was originally developed for USB devices but has since been implemented over many other protocols, including Bluetooth.

The web platform already supports input from many HID devices. Keyboards, pointing devices, and gamepads are all typically implemented using the HID protocol. However, this support relies on the operating system's HID drivers that transform the HID input into high-level input APIs. Devices that are not well supported by the host's HID driver are often inaccessible to web pages. Similarly, the outputs on most devices that are not supported by the host's HID driver are inaccessible.

See also the related Explainer document.

Motivating Applications

This section is non-normative.

Niche devices

The most common classes of HID input devices are already well-supported on the web platform through existing high-level input APIs. For instance, mouse input is accessible through the PointerEvent API and keyboard input is accessible through the Keyboard API. Input from these devices is handled using the host's native HID driver and typically does not require device-specific drivers or configuration to work correctly. WebHID is not intended for devices like these that are already well-supported through high-level input APIs.

For some classes of HID devices, the web platform supports some features of the device but limits access to other features. For instance, the Gamepad API supports the input capabilities of most game controllers but does not support less common capabilities like LED indicators or audio. These features are often not well-supported by host APIs and adding support within the user agent can lead to significant complexity. WebHID would give applications an alternative when the functionality provided by the high-level API is incomplete.

Many HID devices are not supported through any web platform API. The HID specification describes a wide array of devices that could be supported through HID, including virtual reality controls, flight simulators, medical equipment, and more. WebHID would allow these devices to be used without requiring additional drivers or modification to the user agent.

Prototyping, hobbyists, and educational devices

HID is attractive for prototyping and hobbyist applications because it allows devices to use the host's generic HID driver instead of requiring a driver for each host where the device will be used. The simplified installation procedure also makes it easier for educators to deploy a device to a classroom of students without modifying the system configuration on each host. Providing access to HID devices through the web platform would further reduce installation requirements, particularly for devices that are currently only supported through host-specific applications.

Security and Privacy Considerations

This section is non-normative.

Abusing Access to a Device

HID peripherals may expose powerful functionality that should not be made accessible to the page without explicit consent from the user. For instance, a HID peripheral may have sensors that allow it to collect information about its surroundings. A device may store private information that should not be revealed or overwritten. Many devices expose functionality that allow the device firmware to be upgraded. Operating systems typically do not restrict access to HID devices from applications, and this access can occasionally be abused to damage the device or corrupt the data stored on it.

In some cases, a device may expose functionality that should not be accessible at all from a web page. Specific devices may be blocked by recognizing the device by its vendor and product ID and hiding such devices during enumeration. The HID report descriptor allows a device to describe its own capabilities, and this information can be used to block classes of devices even when the vendor and product ID cannot be known in advance. This can be accomplished by inspecting the usage values assigned to collections within the report descriptor; for instance, access to keyboard-like devices can be denied by denying access to devices that include a top-level collection with the Keyboard usage ID.

To mitigate abuse, a device will not be made available to the page until the user has granted explicit access. Access must first be requested by the page and will be granted once the user has selected the device from a chooser displaying all available devices. Once a page has been granted access, an indicator will be displayed to indicate the device is in use.

Attacking a Device

The HID protocol is extremely versatile, and a wide variety of devices have been designed that take advantage of this versatility. As a result, there are many possibilities for how access to a device could allow a malicious page to damage the device itself. It is relatively common for HID peripherals to allow firmware updates to be sent using custom HID reports. Device manufacturers must take care to design the firmware upgrade mechanism to verify that the firmware binary is authentic, and should also protect against downgrades that could reduce the security of a device. Untrusted upgrades could be used to add new capabilities to a device or cause it to masquerade as an entirely different type of device.

Some devices may be damaged when inputs are provided outside of the expected range. For instance, the rumble feature on a gamepad could become damaged if a page sends an invalid rumble command.

In general, these types of attacks are device-specific and cannot be mitigated at the API level.

Attacking the Host

If a malicious page gains access to a device, in some cases this access can be used to attack the host. A major concern is whether the device can be used to generate trusted input events. These events serve as a proxy for user intent and can be used to access more powerful web platform features.

Mice and keyboards are typically implemented as HID peripherals, and are also capable of generating trusted input. A HID keyboard or mouse may contain advanced features like programmable macros, which store a sequence of inputs and allow the sequence to be played back at a later time. Device manufacturers must take care to design such features in a way that would prevent a malicious app from reprogramming the device with an unexpected input sequence, and must also protect against triggering macro playback without the user's explicit consent.

Device Enumeration

dictionary HIDDeviceFilter {
    unsigned long vendorId;
    unsigned short productId;
    unsigned short usagePage;
    unsigned short usage;
};

dictionary HIDDeviceRequestOptions {
    required sequence<HIDDeviceFilter> filters;
};

[
    Exposed=Window,
    SecureContext
]
interface HID : EventTarget {
    attribute EventHandler onconnect;
    attribute EventHandler ondisconnect;
    Promise<sequence<HIDDevice>> getDevices();
    Promise<sequence<HIDDevice>> requestDevice(
        HIDDeviceRequestOptions options);
};

[SecureContext] partial interface Navigator {
    [SameObject] readonly attribute HID hid;
};
      

A {{HIDDevice}} |device| is a matching device for a {{HIDDeviceFilter}} |filter| if the following steps return match:

  1. If |filter|.{{HIDDeviceFilter/vendorId}} is present and |device|.{{HIDDevice/vendorId}} does not equal |filter|.{{HIDDeviceFilter/vendorId}}, return mismatch.
  2. If |filter|.{{HIDDeviceFilter/productId}} is present and |device|.{{HIDDevice/productId}} does not equal |filter|.{{HIDDeviceFilter/productId}}, return mismatch.
  3. If |filter|.{{HIDDeviceFilter/usagePage}} is present, iterate over the {{HIDCollectionInfo}} collections in |device|.{{HIDDevice/collections}}. If there is no [=matching collection=], return mismatch.
  4. Return match.

A {{HIDCollectionInfo}} |collection| is a matching collection for a {{HIDDeviceFilter}} |filter| if the following steps return match:

  1. If |filter|.{{HIDDeviceFilter/usagePage}} is present and |device|.{{HIDCollectionInfo/usagePage}} does not equal |filter|.{{HIDDeviceFilter/usagePage}}, return mismatch.
  2. If |filter|.{{HIDDeviceFilter/usage}} is present and |device|.{{HIDCollectionInfo/usage}} does not equal |filter|.{{HIDDeviceFilter/usage}}, return mismatch.
  3. Return match.

A {{HIDDeviceFilter}} |filter| is valid if the following steps return valid:

  1. If |filter|.{{HIDDeviceFilter/productId}} is present and |filter|.{{HIDDeviceFilter/vendorId}} is not present, return invalid.
  2. If |filter|.{{HIDDeviceFilter/usage}} is present and |filter|.{{HIDDeviceFilter/usagePage}} is not present, return invalid.
  3. Return valid.

The UA MUST be able to enumerate all devices attached to the system. It is not required to perform this work each time an algorithm requests an enumeration. The UA MAY cache the result of the first enumeration it performs and then begin monitoring for device connection and disconnection events, adding connected devices to its cached enumeration and removing disconnected devices. This mode of operation is preferred as it reduces the number of operating system calls.

Events

dictionary HIDConnectionEventInit : EventInit {
    required HIDDevice device;
};

[
    Exposed=Window,
    SecureContext
] interface HIDConnectionEvent : Event {
    constructor(DOMString type, HIDConnectionEventInit eventInitDict);
    [SameObject] readonly attribute HIDDevice device;
};

dictionary HIDInputReportEventInit : EventInit {
    required HIDDevice device;
    required octet reportId;
    required DataView data;
};

[
    Exposed=Window,
    SecureContext
] interface HIDInputReportEvent : Event {
    constructor(DOMString type, HIDInputReportEventInit eventInitDict);
    [SameObject] readonly attribute HIDDevice device;
    readonly attribute octet reportId;
    readonly attribute DataView data;
};
        

HID Collection and Report Information

enum HIDUnitSystem {
    "none", "si-linear", "si-rotation", "english-linear",
    "english-rotation", "vendor-defined", "reserved"
};

dictionary HIDReportItem {
    boolean isAbsolute;
    boolean isArray;
    boolean isRange;
    boolean hasNull;
    sequence<unsigned long> usages;
    unsigned long usageMinimum;
    unsigned long usageMaximum;
    unsigned short reportSize;
    unsigned short reportCount;
    byte unitExponent;
    HIDUnitSystem unitSystem;
    byte unitFactorLengthExponent;
    byte unitFactorMassExponent;
    byte unitFactorTimeExponent;
    byte unitFactorTemperatureExponent;
    byte unitFactorCurrentExponent;
    byte unitFactorLuminousIntensityExponent;
    long logicalMinimum;
    long logicalMaximum;
    long physicalMinimum;
    long physicalMaximum;
    sequence<DOMString> strings;
};

dictionary HIDReportInfo {
    octet reportId;
    sequence<HIDReportItem> items;
};

dictionary HIDCollectionInfo {
    unsigned short usagePage;
    unsigned short usage;
    sequence<HIDCollectionInfo> children;
    sequence<HIDReportInfo> inputReports;
    sequence<HIDReportInfo> outputReports;
    sequence<HIDReportInfo> featureReports;
};
        

Device Usage

[
    Exposed=Window,
    SecureContext
] interface HIDDevice : EventTarget {
    attribute EventHandler oninputreport;
    readonly attribute boolean opened;
    readonly attribute unsigned short vendorId;
    readonly attribute unsigned short productId;
    readonly attribute DOMString productName;
    readonly attribute FrozenArray<HIDCollectionInfo> collections;
    Promise<undefined> open();
    Promise<undefined> close();
    Promise<undefined> sendReport([EnforceRange] octet reportId, BufferSource data);
    Promise<undefined> sendFeatureReport([EnforceRange] octet reportId, BufferSource data);
    Promise<DataView> receiveFeatureReport([EnforceRange] octet reportId);
};
      

Integrations

Permissions Policy

This specification defines a feature that controls whether the {{Navigator/hid}} attribute is exposed on the {{Navigator}} object.

The feature name for this feature is "hid".

The [=default allowlist=] for this feature is ["self"].