Mit der WebHID API können Websites auf alternative Tastaturen und exotische Gamepads zugreifen.
Veröffentlicht am 15. September 2020
Es gibt viele Human Interface Devices (HIDs), z. B. alternative Tastaturen oder exotische Gamepads, die zu neu, zu alt oder zu ungewöhnlich sind, um von den Gerätetreibern der Systeme erkannt zu werden. Die WebHID API löst dieses Problem, indem sie eine Möglichkeit bietet, gerätespezifische Logik in JavaScript zu implementieren.
Empfohlene Anwendungsfälle
Ein HID-Gerät empfängt Eingaben von Menschen oder gibt Ausgaben an Menschen aus. Beispiele für Geräte sind Tastaturen, Zeigegeräte (Mäuse, Touchscreens usw.) und Gamepads. Das HID-Protokoll ermöglicht den Zugriff auf diese Geräte auf Desktopcomputern über Betriebssystemtreiber. Die Webplattform unterstützt HID-Geräte mithilfe dieser Treiber.
Der fehlende Zugriff auf ungewöhnliche HID-Geräte ist besonders ärgerlich, wenn es um alternative Hilfstastaturen (z. B. Elgato Stream Deck, Jabra-Headsets, X-Keys) und exotische Gamepads geht. Gamepads für Desktop-Computer verwenden häufig HID für Gamepad-Eingaben (Schaltflächen, Joysticks, Trigger) und -Ausgaben (LEDs, Vibration).
Leider sind Gamepad-Ein- und ‑Ausgaben nicht gut standardisiert und Webbrowser benötigen oft benutzerdefinierte Logik für bestimmte Geräte. Das ist nicht nachhaltig und führt zu einem schlechten Support für ältere und ungewöhnliche Geräte. Außerdem ist der Browser dann von Eigenheiten im Verhalten bestimmter Geräte abhängig.
Terminologie
Ein Human Interface Device (HID) kann Eingaben von Menschen entgegennehmen oder Ausgaben für Menschen bereitstellen. Es gibt ein HID-Protokoll, einen Standard für die bidirektionale Kommunikation zwischen einem Host und einem Gerät, das die Installation vereinfachen soll.
HID besteht aus zwei grundlegenden Konzepten: Berichten und Berichtsdeskriptoren. Berichte sind die Daten, die zwischen einem Gerät und einem Softwareclient ausgetauscht werden. Der Berichtsdeskriptor beschreibt das Format und die Bedeutung der Daten, die das Gerät unterstützt.
Anwendungen und HID-Geräte tauschen binäre Daten über drei Berichtstypen aus:
| Berichtstyp | Beschreibung |
|---|---|
| Eingabebericht | Daten, die vom Gerät an die Anwendung gesendet werden (z. B. wenn eine Taste gedrückt wird) |
| Ausgabebericht | Daten, die von der Anwendung an das Gerät gesendet werden (z.B. eine Anfrage zum Einschalten der Tastaturbeleuchtung). |
| Funktionsbericht | Daten, die in beide Richtungen gesendet werden können. Das Format ist gerätespezifisch. |
Ein Berichtsdeskriptor beschreibt das binäre Format der vom Gerät unterstützten Berichte. Die Struktur ist hierarchisch und Berichte können als separate Sammlungen in der Sammlung der obersten Ebene gruppiert werden. Das Format des Deskriptors wird durch die HID-Spezifikation definiert.
Eine HID-Verwendung ist ein numerischer Wert, der sich auf eine standardisierte Eingabe oder Ausgabe bezieht. Mit Nutzungswerten kann ein Gerät die beabsichtigte Verwendung des Geräts und den Zweck der einzelnen Felder in seinen Berichten beschreiben. Eine ist beispielsweise für die linke Maustaste definiert. Die Verwendungen sind auch auf Nutzungsseiten organisiert, die eine Angabe der allgemeinen Kategorie des Geräts oder Berichts enthalten.
WebHID API verwenden
So prüfen Sie, ob die WebHID API unterstützt wird:
if ("hid" in navigator) {
// The WebHID API is supported.
}
HID-Verbindung öffnen
Die WebHID API ist asynchron, um zu verhindern, dass die Website-UI blockiert wird, wenn auf Eingaben gewartet wird. Das ist wichtig, da HID-Daten jederzeit empfangen werden können und daher eine Möglichkeit zum Abhören erforderlich ist.
Um eine HID-Verbindung zu öffnen, müssen Sie zuerst auf ein HIDDevice-Objekt zugreifen. Dazu können Sie den Nutzer entweder auffordern, ein Gerät auszuwählen, indem Sie navigator.hid.requestDevice() aufrufen, oder ein Gerät aus navigator.hid.getDevices() auswählen. Diese Funktion gibt eine Liste der Geräte zurück, auf die die Website zuvor Zugriff hatte.
Für die Funktion navigator.hid.requestDevice() ist ein obligatorisches Objekt erforderlich, das Filter definiert. Diese werden verwendet, um Geräte abzugleichen, die mit einer USB-Anbieter-ID (vendorId), einer USB-Produkt-ID (productId), einem Nutzungspagewert (usagePage) und einem Nutzungswert (usage) verbunden sind. Sie finden diese Werte im USB ID Repository und im Dokument zu HID-Nutzungstabellen.
Die von dieser Funktion zurückgegebenen HIDDevice-Objekte stellen mehrere HID-Schnittstellen auf demselben physischen Gerät dar.
// Filter on devices with the Nintendo Switch Joy-Con USB Vendor/Product IDs.
const filters = [
{
vendorId: 0x057e, // Nintendo Co., Ltd
productId: 0x2006 // Joy-Con Left
},
{
vendorId: 0x057e, // Nintendo Co., Ltd
productId: 0x2007 // Joy-Con Right
}
];
// Prompt user to select a Joy-Con device.
const [device] = await navigator.hid.requestDevice({ filters });
// Get all devices the user has previously granted the website access to.
const devices = await navigator.hid.getDevices();
Sie können auch den optionalen exclusionFilters-Schlüssel in navigator.hid.requestDevice() verwenden, um einige Geräte, die bekanntermaßen nicht richtig funktionieren, aus der Browserauswahl auszuschließen.
// Request access to a device with vendor ID 0xABCD. The device must also have
// a collection with usage page Consumer (0x000C) and usage ID Consumer
// Control (0x0001). The device with product ID 0x1234 is malfunctioning.
const [device] = await navigator.hid.requestDevice({
filters: [{ vendorId: 0xabcd, usagePage: 0x000c, usage: 0x0001 }],
exclusionFilters: [{ vendorId: 0xabcd, productId: 0x1234 }],
});
Ein HIDDevice-Objekt enthält USB-Anbieter- und Produktkennungen zur Geräteidentifizierung. Das Attribut collections wird mit einer hierarchischen Beschreibung der Berichtsformate des Geräts initialisiert.
for (let collection of device.collections) {
// An HID collection includes usage, usage page, reports, and subcollections.
console.log(`Usage: ${collection.usage}`);
console.log(`Usage page: ${collection.usagePage}`);
for (let inputReport of collection.inputReports) {
console.log(`Input report: ${inputReport.reportId}`);
// Loop through inputReport.items
}
for (let outputReport of collection.outputReports) {
console.log(`Output report: ${outputReport.reportId}`);
// Loop through outputReport.items
}
for (let featureReport of collection.featureReports) {
console.log(`Feature report: ${featureReport.reportId}`);
// Loop through featureReport.items
}
// Loop through subcollections with collection.children
}
Die HIDDevice-Geräte werden standardmäßig im Status „geschlossen“ zurückgegeben und müssen durch Aufrufen von open() geöffnet werden, bevor Daten gesendet oder empfangen werden können.
// Wait for the HID connection to open before sending/receiving data.
await device.open();
Eingabeberichte erhalten

Sobald die HID-Verbindung hergestellt ist, können Sie eingehende Eingabeberichte verarbeiten, indem Sie auf die "inputreport"-Ereignisse des Geräts warten. Diese Ereignisse enthalten die HID-Daten als DataView-Objekt (data), das zugehörige HID-Gerät (device) und die mit dem Eingabebericht verknüpfte 8‑Bit-Berichts-ID (reportId).
Dieser Code setzt das vorherige Beispiel fort und hilft Ihnen, zu erkennen, welche Taste der Nutzer auf einem Joy-Con Right-Gerät gedrückt hat. So können Sie ihn zu Hause ausprobieren.
device.addEventListener("inputreport", event => {
const { data, device, reportId } = event;
// Handle only the Joy-Con Right device and a specific report ID.
if (device.productId !== 0x2007 && reportId !== 0x3f) return;
const value = data.getUint8(0);
if (value === 0) return;
const someButtons = { 1: "A", 2: "X", 4: "B", 8: "Y" };
console.log(`User pressed button ${someButtons[value]}.`);
});
Ausgabeberichte senden
Wenn Sie einen Ausgabebereicht an ein HID-Gerät senden möchten, übergeben Sie die 8‑Bit-Berichts-ID, die dem Ausgabebereicht zugeordnet ist (reportId), und die Bytes als BufferSource (data) an device.sendReport(). Das zurückgegebene Promise wird aufgelöst, sobald der Bericht gesendet wurde. Wenn das HID-Gerät keine Berichts-IDs verwendet, setzen Sie reportId auf 0.
Das nächste Beispiel bezieht sich auf ein Joy-Con-Gerät und zeigt, wie es mit Ausgabemeldungen zum Vibrieren gebracht wird.
// First, send a command to enable vibration.
// Magical bytes come from https://github.com/mzyy94/joycon-toolweb
const enableVibrationData = [1, 0, 1, 64, 64, 0, 1, 64, 64, 0x48, 0x01];
await device.sendReport(0x01, new Uint8Array(enableVibrationData));
// Then, send a command to make the Joy-Con device rumble.
// Actual bytes are available in the sample.
const rumbleData = [ /* ... */ ];
await device.sendReport(0x10, new Uint8Array(rumbleData));
Funktionsberichte senden und empfangen

Funktionsberichte sind die einzigen HID-Datenberichte, die in beide Richtungen übertragen werden können. Sie ermöglichen den Austausch nicht standardisierter HID-Daten zwischen HID-Geräten und ‑Anwendungen. Im Gegensatz zu Eingabe- und Ausgabedaten werden Funktionsberichte nicht regelmäßig von der Anwendung empfangen oder gesendet.
Wenn Sie einen Funktionsbericht an ein HID-Gerät senden möchten, übergeben Sie die 8‑Bit-Berichts-ID, die dem Funktionsbericht zugeordnet ist (reportId), und Bytes als BufferSource (data) an device.sendFeatureReport(). Das zurückgegebene Promise wird aufgelöst, sobald der Bericht gesendet wurde. Wenn das HID-Gerät keine Berichts-IDs verwendet, setzen Sie reportId auf 0.
In diesem Beispiel wird die Verwendung von Funktionsberichten veranschaulicht. Es wird gezeigt, wie Sie ein Apple-Tastatur-Hintergrundbeleuchtungsgerät anfordern, es öffnen und es blinken lassen.
const waitFor = duration => new Promise(r => setTimeout(r, duration));
// Prompt user to select an Apple Keyboard Backlight device.
const [device] = await navigator.hid.requestDevice({
filters: [{ vendorId: 0x05ac, usage: 0x0f, usagePage: 0xff00 }]
});
// Wait for the HID connection to open.
await device.open();
// Blink!
const reportId = 1;
for (let i = 0; i < 10; i++) {
// Turn off
await device.sendFeatureReport(reportId, Uint32Array.from([0, 0]));
await waitFor(100);
// Turn on
await device.sendFeatureReport(reportId, Uint32Array.from([512, 0]));
await waitFor(100);
}
Wenn Sie einen Funktionsbericht von einem HID-Gerät erhalten möchten, übergeben Sie die 8‑Bit-Berichts-ID, die dem Funktionsbericht zugeordnet ist (reportId), an device.receiveFeatureReport(). Das zurückgegebene Promise wird mit einem DataView-Objekt aufgelöst, das den Inhalt des Funktionsberichts enthält. Wenn das HID-Gerät keine Berichts-IDs verwendet, setzen Sie reportId auf 0.
// Request feature report.
const dataView = await device.receiveFeatureReport(/* reportId= */ 1);
// Read feature report contents with dataView.getInt8(), getUint8(), etc...
Verbindungen und Trennungen anhören
Wenn der Website die Berechtigung zum Zugriff auf ein HID-Gerät erteilt wurde, kann sie Verbindungs- und Trennungsereignisse aktiv empfangen, indem sie auf "connect"- und "disconnect"-Ereignisse wartet.
navigator.hid.addEventListener("connect", event => {
// Automatically open event.device or warn user a device is available.
});
navigator.hid.addEventListener("disconnect", event => {
// Remove |event.device| from the UI.
});
Zugriff auf ein HID-Gerät widerrufen
Die Website kann Berechtigungen für den Zugriff auf ein HID-Gerät, das sie nicht mehr benötigt, entfernen, indem sie forget() für die HIDDevice-Instanz aufruft. Wenn beispielsweise eine Bildungs-Webanwendung auf einem gemeinsam genutzten Computer mit vielen Geräten verwendet wird, führt eine große Anzahl von angesammelten nutzergenerierten Berechtigungen zu einer schlechten Nutzererfahrung.
Wenn Sie forget() für eine einzelne HIDDevice-Instanz aufrufen, wird der Zugriff auf alle HID-Schnittstellen auf demselben physischen Gerät widerrufen.
// Voluntarily revoke access to this HID device.
await device.forget();
Da forget() in Chrome 100 oder höher verfügbar ist, prüfen Sie, ob diese Funktion mit den folgenden Elementen unterstützt wird:
if ("hid" in navigator && "forget" in HIDDevice.prototype) {
// forget() is supported.
}
Tipps für Entwickler

Sie können HID in Chrome mit der internen Seite about://device-log debuggen. Dort finden Sie alle Ereignisse im Zusammenhang mit HID- und USB-Geräten an einem Ort.
Mit dem HID-Explorer können Sie Informationen zu HID-Geräten in ein für Menschen lesbares Format ausgeben. Sie ordnet jedem HID-Verwendungszweck Verwendungszweckwerte zu Namen zu.
Auf den meisten Linux-Systemen werden HID-Geräte standardmäßig mit schreibgeschützten Berechtigungen zugeordnet. Damit Chrome ein HID-Gerät öffnen kann, müssen Sie eine neue udev-Regel hinzufügen. Erstellen Sie eine Datei unter /etc/udev/rules.d/50-yourdevicename.rules mit folgendem Inhalt:
KERNEL=="hidraw*", ATTRS{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
In diesem Code ist [yourdevicevendor] beispielsweise 057e, wenn es sich bei Ihrem Gerät um einen Nintendo Switch-Joy-Con handelt. ATTRS{idProduct} kann für eine genauere Regel hinzugefügt werden. Achten Sie darauf, dass Ihr user ein Mitglied der Gruppe plugdev ist. Verbinde dein Gerät dann einfach wieder.
Demos
Einige WebHID-Demos finden Sie unter web.dev/hid-examples.
Sicherheit und Datenschutz
Die Autoren der Spezifikation haben die WebHID API gemäß den in Controlling Access to Powerful Web Platform Features definierten Kernprinzipien entwickelt und implementiert, darunter Nutzerkontrolle, Transparenz und Ergonomie. Die Verwendung dieser API wird hauptsächlich durch ein Berechtigungsmodell eingeschränkt, das jeweils nur den Zugriff auf ein einzelnes HID-Gerät ermöglicht. Als Reaktion auf eine Nutzeraufforderung muss der Nutzer aktiv ein bestimmtes HID-Gerät auswählen.
Informationen zu den Sicherheitsrisiken finden Sie im Abschnitt Security and Privacy Considerations der WebHID-Spezifikation.
Außerdem prüft Chrome die Verwendung jeder Sammlung auf oberster Ebene. Wenn eine Sammlung auf oberster Ebene eine geschützte Verwendung hat (z. B. generische Tastatur, Maus), kann eine Website keine Berichte senden und empfangen, die in dieser Sammlung definiert sind. Die vollständige Liste der geschützten Verwendungen ist öffentlich verfügbar.
Beachten Sie, dass sicherheitssensible HID-Geräte (z. B. FIDO-HID-Geräte, die für eine stärkere Authentifizierung verwendet werden) ebenfalls in Chrome blockiert werden. Weitere Informationen finden Sie in den Dateien USB-Sperrliste und HID-Sperrliste.
Feedback
Das Chrome-Team würde sich über Ihr Feedback zur WebHID API freuen.
Informationen zum API-Design
Gibt es etwas an der API, das nicht wie erwartet funktioniert? Oder fehlen Methoden oder Properties, die Sie für die Umsetzung Ihrer Idee benötigen?
Melden Sie ein Spezifikationsproblem im GitHub-Repository der WebHID API oder fügen Sie Ihre Gedanken zu einem bestehenden Problem hinzu.
Problem mit der Implementierung melden
Haben Sie einen Fehler in der Chrome-Implementierung gefunden? Oder weicht die Implementierung von der Spezifikation ab?
Informationen zum Einreichen von WebHID-Fehlern Geben Sie so viele Details wie möglich an, beschreiben Sie, wie der Fehler reproduziert werden kann, und legen Sie Components auf Blink>HID fest.
Nützliche Links
- Spezifikation
- Tracking-Fehler
- ChromeStatus.com-Eintrag
- Blink-Komponente:
Blink>HID
Danksagungen
Vielen Dank an Matt Reynolds und Joe Medley für ihre Rezensionen.