Mit der WebHID API können Websites auf alternative Hilfstastaturen und exotische Gamepads zugreifen.
Es gibt eine große Anzahl von Human Interface Devices (HIDs), z. B. alternative Tastaturen oder exotische Gamepads, die zu neu, zu alt oder zu selten sind, um von den Gerätetreibern des Systems zugänglich zu sein. Die WebHID API bietet eine Lösung für dieses Problem, da sie eine Möglichkeit bietet, gerätespezifische Logik in JavaScript zu implementieren.
Empfohlene Anwendungsfälle
Ein HID-Gerät nimmt Eingaben von Menschen entgegen oder gibt eine Ausgabe an sie 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 Desktop-Computern über Betriebssystemtreiber. Die Webplattform unterstützt HID-Geräte, indem sie auf diese Treiber zurückgreift.
Die fehlende Möglichkeit, auf ungewöhnliche HID-Geräte zuzugreifen, ist besonders ärgerlich, wenn es um alternative Hilfstastaturen (z.B. Elgato Stream Deck, Jabra-Headsets, X-Keys) und exotische Gamepad-Unterstützung geht. Für Computer konzipierte Gamepads verwenden häufig HID für Gamepad-Eingaben (Tasten, Joysticks, Auslöser) und ‑Ausgaben (LEDs, Rumble). Leider sind die Eingaben und Ausgaben von Gamepads nicht gut standardisiert und Webbrowser erfordern oft benutzerdefinierte Logik für bestimmte Geräte. Das ist nicht nachhaltig und führt zu einer schlechten Unterstützung für die Long Tail-Geräte, also ältere und weniger gängige Geräte. Außerdem ist der Browser von Besonderheiten im Verhalten bestimmter Geräte abhängig.
Terminologie
HID besteht aus zwei grundlegenden Konzepten: Berichten und Berichtsbeschreibungen. 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 vom Gerät unterstützt werden.
Ein HID (Human Interface Device) ist ein Gerät, das Eingaben von Menschen entgegennimmt oder ihnen eine Ausgabe liefert. Es bezieht sich auch auf das HID-Protokoll, einen Standard für die bidirektionale Kommunikation zwischen einem Host und einem Gerät, der die Installation vereinfachen soll. Das HID-Protokoll wurde ursprünglich für USB-Geräte entwickelt, wurde aber inzwischen über viele andere Protokolle implementiert, einschließlich Bluetooth.
Anwendungen und HID-Geräte tauschen Binärdaten über drei Berichtstypen aus:
Berichtstyp | Beschreibung |
---|---|
Eingabebericht | Daten, die vom Gerät an die Anwendung gesendet werden (z. B. wenn eine Schaltfläche gedrückt wird) |
Ausgabebericht | Daten, die von der Anwendung an das Gerät gesendet werden (z. B. eine Anfrage zum Einschalten der Tastaturbeleuchtung) |
Bericht zu Funktionen | Daten, die in beide Richtungen gesendet werden können. Das Format ist gerätespezifisch. |
Ein Berichtsdeskriptor beschreibt das Binärformat von Berichten, das vom Gerät unterstützt wird. Die Struktur ist hierarchisch und Berichte können als separate Sammlungen innerhalb der übergeordneten Sammlung gruppiert werden. Das Format des Descriptors wird durch die HID-Spezifikation definiert.
Eine HID-Nutzung ist ein numerischer Wert, der sich auf eine standardisierte Eingabe oder Ausgabe bezieht. Mithilfe von Nutzungswerten kann ein Gerät die beabsichtigte Verwendung des Geräts und den Zweck jedes Felds in seinen Berichten beschreiben. Eine solche Aktion ist beispielsweise für die linke Maustaste definiert. Die Nutzungen sind auch auf Seiten zur Nutzung organisiert, die eine Angabe zur übergeordneten Kategorie des Geräts oder Berichts enthalten.
WebHID API verwenden
Funktionserkennung
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 standardmäßig asynchron, um zu verhindern, dass die Benutzeroberfläche der Website blockiert wird, wenn eine Eingabe erwartet wird. Das ist wichtig, da HID-Daten jederzeit empfangen werden können und daher eine Möglichkeit zum Abhören erforderlich ist.
Wenn Sie eine HID-Verbindung öffnen möchten, greifen Sie zuerst auf ein HIDDevice
-Objekt zu. Dazu kannst du den Nutzer entweder auffordern, ein Gerät auszuwählen, indem du navigator.hid.requestDevice()
aufrufst, oder eines über navigator.hid.getDevices()
auswählen. Letzteres gibt eine Liste der Geräte zurück, auf die der Website zuvor Zugriff gewährt wurde.
Für die Funktion navigator.hid.requestDevice()
ist ein obligatorisches Objekt erforderlich, das Filter definiert. Sie werden verwendet, um jedes Gerät abzugleichen, das mit einer USB-Anbieter-ID (vendorId
), einer USB-Produkt-ID (productId
), einem Wert auf der Nutzungsseite (usagePage
) und einem Nutzungswert (usage
) verbunden ist. Sie finden sie im USB-ID-Repository und im Dokument „HID-Nutzungstabellen“.
Die von dieser Funktion zurückgegebenen HIDDevice
-Objekte repräsentieren mehrere HID-Schnittstellen auf demselben physischen Gerät.
// 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 die optionale Taste exclusionFilters
in navigator.hid.requestDevice()
verwenden, um bestimmte Geräte aus der Browserauswahl auszuschließen, die beispielsweise bekanntlich nicht ordnungsgemäß funktionieren.
// 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 Produkt-IDs zur Geräteidentifikation. Das collections
-Attribut 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 wurde, kannst du eingehende Eingabeberichte verarbeiten, indem du die "inputreport"
-Ereignisse vom Gerät abwartest. Diese Ereignisse enthalten die HID-Daten als DataView
-Objekt (data
), das zugehörige HID-Gerät (device
) und die 8‑Bit-Berichts-ID, die mit dem Eingabebericht verknüpft ist (reportId
).
Im Anschluss an das vorherige Beispiel zeigt der folgende Code, wie Sie erkennen können, welche Schaltfläche der Nutzer auf einer Joy-Con Right gedrückt hat, damit Sie es zu Hause ausprobieren können.
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 Ausgabebericht an ein HID-Gerät senden möchten, übergeben Sie die 8‑Bit-Berichts-ID, die mit dem Ausgabebericht verknüpft 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.
Im folgenden Beispiel wird gezeigt, wie Sie mithilfe von Ausgabeberichten ein Joy-Con-Gerät zum Vibrieren bringen.
// 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 below.
const rumbleData = [ /* ... */ ];
await device.sendReport(0x10, new Uint8Array(rumbleData));
Funktionsberichte senden und empfangen
Funktionsberichte sind die einzige Art von HID-Datenberichten, 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 Ausgabeberichten 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 mit dem Funktionsbericht verknüpft ist (reportId
), und die 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.
Im folgenden Beispiel wird die Verwendung von Funktionsberichten veranschaulicht. Sie erfahren, wie Sie eine Apple-Tastatur mit Hintergrundbeleuchtung anfordern, öffnen und zum Blinken bringen.
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 mit dem Funktionsbericht verknüpfte 8‑Bit-Berichts-ID (reportId
) an device.receiveFeatureReport()
. Das zurückgegebene Versprechen wird mit einem DataView
-Objekt aufgelöst, das den Inhalt des Feature-Berichts 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...
Auf Verbindung und Trennung hören
Wenn der Website die Berechtigung zum Zugriff auf ein HID-Gerät gewährt wurde, kann sie Verbindungs- und Trennungsereignisse aktiv empfangen, indem sie auf "connect"
- und "disconnect"
-Ereignisse achtet.
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 entfernen, das nicht mehr benötigt wird, indem forget()
auf die HIDDevice
-Instanz aufgerufen wird. Bei einer Bildungs-Webanwendung, die auf einem gemeinsam genutzten Computer mit vielen Geräten verwendet wird, führt eine große Anzahl von nutzergenerierten Berechtigungen zu einer schlechten Nutzererfahrung.
Wenn forget()
auf einer einzelnen HIDDevice
-Instanz aufgerufen wird, 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
Das Entfernen von Fehlern bei HID in Chrome ist mit der internen Seite about://device-log
ganz einfach. Dort finden Sie alle HID- und USB-Gerätereignisse an einem Ort.
Mit dem HID Explorer können Sie HID-Geräteinformationen in ein visuell lesbares Format umwandeln. Es werden Nutzungswerte für jede HID-Nutzung zu Namen zugeordnet.
Auf den meisten Linux-Systemen werden HID-Geräte standardmäßig mit Lesezugriffsberechtigungen zugeordnet. Damit Chrome ein HID-Gerät öffnen kann, müssen Sie eine neue udev-Regel hinzufügen. Erstellen Sie unter /etc/udev/rules.d/50-yourdevicename.rules
eine Datei mit folgendem Inhalt:
KERNEL=="hidraw*", ATTRS{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
In der Zeile oben ist [yourdevicevendor]
057e
, wenn es sich bei Ihrem Gerät beispielsweise um eine Nintendo Switch Joy-Con handelt. Für eine spezifischere Regel kann auch ATTRS{idProduct}
hinzugefügt werden. Achten Sie darauf, dass Ihre user
ein Mitglied der Gruppe plugdev
ist. Verbinden Sie Ihr Gerät dann einfach wieder.
Unterstützte Browser
Die WebHID API ist in Chrome 89 auf allen Desktop-Plattformen (ChromeOS, Linux, macOS und Windows) verfügbar.
Demos
Einige WebHID-Demos finden Sie unter web.dev/hid-examples. Sieh es dir an!
Sicherheit und Datenschutz
Die Autoren der Spezifikation haben die WebHID API anhand der in Controlling Access to Powerful Web Platform Features (Zugriff auf leistungsstarke Funktionen der Webplattform steuern) definierten Grundprinzipien entwickelt und implementiert, einschließlich Nutzersteuerung, Transparenz und Ergonomie. Die Verwendung dieser API wird hauptsächlich durch ein Berechtigungsmodell eingeschränkt, das nur Zugriff auf ein einzelnes HID-Gerät gleichzeitig gewährt. Als Reaktion auf eine Nutzeraufforderung muss der Nutzer aktiv Maßnahmen ergreifen, um ein bestimmtes HID-Gerät auszuwählen.
Informationen zu den Sicherheitsabwägungen finden Sie in der WebHID-Spezifikation im Abschnitt Sicherheits- und Datenschutzaspekte.
Außerdem prüft Chrome die Verwendung jeder Sammlung der obersten Ebene. Wenn eine Sammlung der obersten Ebene eine geschützte Verwendung hat (z. B. eine generische Tastatur oder Maus), kann eine Website keine in dieser Sammlung definierten Berichte senden und empfangen. Eine vollständige Liste der geschützten Verwendungen ist öffentlich verfügbar.
Sicherheitssensible HID-Geräte (z. B. FIDO-HID-Geräte, die für eine stärkere Authentifizierung verwendet werden) sind in Chrome ebenfalls blockiert. Weitere Informationen finden Sie in den Dateien USB-Blocklist und HID-Blocklist.
Feedback
Das Chrome-Team würde sich über Ihre Meinung und Erfahrungen mit der WebHID API freuen.
Informationen zum API-Design
Funktioniert die API nicht wie erwartet? Oder fehlen Methoden oder Eigenschaften, die Sie für die Implementierung Ihrer Idee benötigen?
Melden Sie ein Problem mit der Spezifikation im GitHub-Repository der WebHID API oder fügen Sie Ihre Anmerkungen zu einem vorhandenen Problem hinzu.
Problem mit der Implementierung melden
Haben Sie einen Fehler in der Chrome-Implementierung gefunden? Oder unterscheidet sich die Implementierung von der Spezifikation?
Weitere Informationen finden Sie unter WebHID-Fehler melden. Machen Sie dabei möglichst präzise Angaben, geben Sie eine einfache Anleitung zum Reproduzieren des Fehlers an und legen Sie Blink>HID
als Komponenten fest. Glitch eignet sich hervorragend, um schnell und einfach Reproduktionen zu teilen.
Unterstützung zeigen
Beabsichtigen Sie, die WebHID API zu verwenden? Ihre öffentliche Unterstützung hilft dem Chrome-Team, Funktionen zu priorisieren, und zeigt anderen Browseranbietern, wie wichtig es ist, diese zu unterstützen.
Senden Sie einen Tweet an @ChromiumDev mit dem Hashtag #WebHID
und teilen Sie uns mit, wo und wie Sie ihn verwenden.
Nützliche Links
- Spezifikation
- Tracking-Fehler
- Eintrag in ChromeStatus.com
- Blink-Komponente:
Blink>HID
Danksagungen
Vielen Dank an Matt Reynolds und Joe Medley für die Überprüfung dieses Artikels. Foto der roten und blauen Nintendo Switch von Sara Kurfeß und Foto eines schwarzen und silbernen Laptops von Athul Cyriac Ajay auf Unsplash.