Verbindung zu ungewöhnlichen HID-Geräten herstellen

Über die WebHID API können Websites auf alternative Zusatztastaturen und exotische Gamepads zugreifen.

François Beaufort
François Beaufort

Es gibt eine lange Reihe von Human Interface Devices (HIDs), z. B. alternative Geräte Tastaturen oder exotische Gamepads, die zu neu, zu alt oder zu ungewöhnlich sind. für die Systeme zugänglich sind, Gerätetreiber. Die WebHID API löst dieses Problem, indem sie eine gerätespezifische Logik in JavaScript zu implementieren.

Empfohlene Anwendungsfälle

Ein HID-Gerät nimmt Eingaben von Menschen an oder stellt Ausgaben für sie bereit. Gerätebeispiele z. B. Tastaturen, Zeigegeräte (Mäuse, Touchscreens) und Gamepads. Das HID-Protokoll ermöglicht den Zugriff auf diese Geräte über einen Desktop-Computer mit Betriebssystemtreibern. Die Webplattform unterstützt HID-Geräte auf diese Treiber setzen.

Besonders schmerzhaft ist es, auf ungewöhnliche HID-Geräte zuzugreifen, alternative Tastaturen (z.B. Elgato Stream Deck, Jabra) Headsets, X-Tasten) und Unterstützung für exotische Gamepads. Gamepads für Computer verwenden häufig HID für Gamepad-Eingaben (Tasten, Joysticks, Trigger) und Ausgaben. (LEDs, Ruckeln). Leider sind die Ein- und Ausgaben des Gamepads nicht gut Standardisierte Browser und Webbrowser erfordern oft eine benutzerdefinierte Logik für bestimmte Geräte. Dies ist nicht nachhaltig und führt zu mangelhafter Unterstützung für die Long Tails von älteren und ungewöhnlichen Geräten. Außerdem ist der Browser von Eigenheiten im Verhalten abhängig. für bestimmte Geräte.

Terminologie

HID umfasst zwei grundlegende Konzepte: Berichte 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.

Ein HID (Human Interface Device) ist ein Gerätetyp, der Eingaben von oder Ausgabe für Menschen. Es bezieht sich auch auf das HID-Protokoll, ein Standard für eine bidirektionale Kommunikation zwischen einem Host und einem Gerät, den Installationsprozess zu vereinfachen. Das HID-Protokoll wurde ursprünglich entwickelt, für USB-Geräte, 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 App 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.

Eine Berichtsbeschreibung beschreibt das vom . Ihre Struktur ist hierarchisch und ermöglicht das Gruppieren von Berichten als eigenständige innerhalb der übergeordneten Sammlung. Das Format des Deskriptors ist definiert durch die HID-Spezifikation.

Die HID-Nutzung ist ein numerischer Wert, der sich auf eine standardisierte Eingabe oder Ausgabe bezieht. Nutzungswerte ermöglichen es einem Gerät, die beabsichtigte Nutzung des Geräts und jedes Felds in seinen Berichten. Ein Beispiel ist für die linke mit der Maus. Die Nutzung ist in Nutzungsseiten organisiert, die eine die die übergeordnete Kategorie des Geräts oder Berichts angibt.

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 Website-UI wenn auf eine Eingabe gewartet wird. Das ist wichtig, da HID-Daten empfangen werden können und eine Möglichkeit zum Anhören erfordert.

Um eine HID-Verbindung zu öffnen, greifen Sie zuerst auf ein HIDDevice-Objekt zu. Dazu können Sie Nutzer auffordern, ein Gerät auszuwählen, indem sie navigator.hid.requestDevice() oder eine Option aus navigator.hid.getDevices() auswählen gibt eine Liste der Geräte zurück, auf die die Website Zugriff hat. .

Die Funktion navigator.hid.requestDevice() verwendet ein obligatorisches Objekt, das Filter definiert. Sie werden für alle Geräte verwendet, die mit einem USB-Anbieter verbunden sind. Kennzeichnung (vendorId), eine USB-Produktkennzeichnung (productId), eine Nutzungsseite (usagePage) und einen Nutzungswert (usage). Diese erhalten Sie in der USB ID Repository und das Dokument mit HID-Nutzungstabellen.

Die verschiedenen HIDDevice-Objekte, die von dieser Funktion zurückgegeben werden, stellen 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();
<ph type="x-smartling-placeholder">
</ph> Screenshot einer Aufforderung für ein HID-Gerät auf einer Website
Nutzeraufforderung zur Auswahl einer Nintendo Switch Joy-Con.

Sie können auch den optionalen Schlüssel exclusionFilters in navigator.hid.requestDevice(), um Geräte aus der Browserauswahl auszuschließen beispielsweise bekanntermaßen 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 die USB-Anbieter- und Produkt-ID des Geräts. zur Identifikation. Das Attribut collections ist mit einer hierarchischen eine Beschreibung der Berichtsformate des Geräts.

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 geschlossenen Zustand zurückgegeben. und muss die 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 Eingaben verarbeiten indem sie die "inputreport"-Ereignisse auf dem Gerät erfassen. Diese Ereignisse Die HID-Daten als DataView-Objekt (data) enthalten, das zugehörige HID-Gerät an (device) und die mit dem Eingabebericht verknüpfte 8-Bit-Berichts-ID (reportId)

<ph type="x-smartling-placeholder">
</ph> Rot-blaues Nintendo-Foto.
Nintendo Switch Joy-Con-Geräte.

In Anlehnung an das vorherige Beispiel zeigt der folgende Code, wie Sie welche Taste der Nutzer auf einem Joy-Con-Rechts-Gerät gedrückt hat, 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 Ausgabebericht an ein HID-Gerät senden möchten, müssen Sie die zugehörige 8-Bit-Berichts-ID übergeben. mit dem Ausgabebericht (reportId) und Byte als BufferSource (data) device.sendReport() Das zurückgegebene Versprechen wird aufgelöst, sobald der Bericht erstellt wurde. gesendet. Wenn das HID-Gerät keine Berichts-IDs verwendet, setzen Sie reportId auf 0.

Das folgende Beispiel bezieht sich auf ein Joy-Con-Gerät und zeigt, wie du mit Ausgabeberichten.

// 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 beiden Wegbeschreibungen. Sie ermöglichen HID-Geräten und -Anwendungen den Austausch nicht standardisierter Geräte HID-Daten Im Gegensatz zu Eingabe- und Ausgabeberichten werden Funktionsberichte nicht empfangen oder regelmäßig von der Anwendung gesendet werden.

<ph type="x-smartling-placeholder">
</ph> Schwarz-silbernes Laptopfoto.
Laptoptastatur

Wenn du einen Funktionsbericht an ein HID-Gerät senden möchtest, musst du die zugehörige 8-Bit-Berichts-ID übergeben. mit dem Funktionsbericht (reportId) und Byte als BufferSource (data) für device.sendFeatureReport() Das zurückgegebene Versprechen wird aufgelöst, sobald der Bericht gesendet wurden. Wenn das HID-Gerät keine Berichts-IDs verwendet, setzen Sie reportId auf 0.

Das folgende Beispiel veranschaulicht die Verwendung von Funktionsberichten. Es zeigt, wie Sie um eine Hintergrundbeleuchtung für die Apple-Tastatur anzufordern, öffnen Sie es und lassen Sie es blinken.

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);
}

Um einen Funktionsbericht von einem HID-Gerät zu erhalten, musst du die 8-Bit-Berichts-ID übergeben. die mit dem Funktionsbericht (reportId) verknüpft sind, device.receiveFeatureReport(). Das zurückgegebene Versprechen wird mit einem DataView-Objekt, das den Inhalt des Featureberichts enthält. Wenn die HID Gerät verwendet keine Berichts-IDs, legen Sie für reportId den Wert 0 fest.

// Request feature report.
const dataView = await device.receiveFeatureReport(/* reportId= */ 1);

// Read feature report contents with dataView.getInt8(), getUint8(), etc...

Informationen zu Verbindungs- und Verbindungsabbrüchen anhören

Wenn der Website die Berechtigung für den Zugriff auf ein HID-Gerät gewährt wurde, kann sie aktiv empfangene Verbindungs- und Verbindungsabbrüche durch Überwachung von "connect" und "disconnect" Ereignisse.

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 die Berechtigungen für den Zugriff auf ein nicht mehr vorhandenes HID-Gerät bereinigen die Sie behalten möchten, indem Sie forget() für die HIDDevice-Instanz aufrufen. Für Bei einer Webanwendung für den Bildungsbereich, die auf einem gemeinsam genutzten Computer mit vielen kann eine große Zahl angesammelter benutzergenerierter Berechtigungen einen schlechten User Experience aus.

Durch das Aufrufen von forget() für eine einzelne HIDDevice-Instanz wird der Zugriff für alle die HID-Schnittstellen auf demselben physischen Gerät.

// Voluntarily revoke access to this HID device.
await device.forget();

forget() ist in Chrome 100 oder höher verfügbar. Prüfen Sie daher, ob diese Funktion unterstützt durch Folgendes:

if ("hid" in navigator && "forget" in HIDDevice.prototype) {
  // forget() is supported.
}

Entwicklertipps

Über die interne Seite about://device-log ist das Debuggen von HID in Chrome ganz einfach. Hier können Sie alle Ereignisse in Zusammenhang mit HID und USB-Geräten an einem einzigen Ort sehen.

<ph type="x-smartling-placeholder">
</ph> Screenshot der internen Seite zum Debuggen von HID.
Interne Seite in Chrome zum Debuggen von HID.

HID-Explorer zum Speichern von HID-Geräten nutzen in ein visuell lesbares Format. Es ordnet Nutzungswerte den Namen der einzelnen HID-Nutzung.

Auf den meisten Linux-Systemen erhalten HID-Geräte Standardeinstellung. Damit Chrome ein HID-Gerät öffnen kann, müssen Sie ein neues udev-Gerät hinzufügen Regel. Erstellen Sie eine Datei unter /etc/udev/rules.d/50-yourdevicename.rules mit dem folgenden Inhalt:

KERNEL=="hidraw*", ATTRS{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"

In der Zeile oben hat [yourdevicevendor] bei einer Nintendo Switch den Wert 057e. zum Beispiel die Joy-Con. ATTRS{idProduct} kann auch für eine spezifischere Regel. Ihr user muss Mitglied der Gruppe plugdev sein. Dann müssen Sie nur noch Verbinden Sie Ihr Gerät erneut.

Unterstützte Browser

Die WebHID API ist auf allen Desktop-Plattformen verfügbar (ChromeOS, Linux, macOS, und Windows) in Chrome 89.

Demos

Einige WebHID-Demos finden Sie unter web.dev/hid-examples. Schau mal hier!

Sicherheit und Datenschutz

Die Spezifikationsautoren haben die WebHID API mithilfe des Kerns die unter Zugriff auf leistungsstarke Webplattform-Funktionen steuern erläutert wird, einschließlich Nutzersteuerung, Transparenz und Ergonomie. Die Möglichkeit, diese Die API wird hauptsächlich durch ein Berechtigungsmodell gesteuert, das nur einem einzelnen Nutzer jeweils einem HID-Gerät. Als Reaktion auf eine Nutzeraufforderung muss der Nutzer zur Auswahl eines bestimmten HID-Geräts.

Weitere Informationen zu den Vor- und Nachteilen der Sicherheit finden Sie im Artikel Sicherheit und Datenschutz Überlegungen der WebHID-Spezifikation.

Darüber hinaus prüft Chrome die Nutzung der einzelnen Sammlungen auf oberster Ebene und ob ein der obersten Ebene geschützt werden (z.B. allgemeine Tastatur, Maus), auf einer Website keine Berichte gesendet und empfangen werden, . Die vollständige Liste der geschützten Nutzungen ist öffentlich zugänglich.

Beachten Sie, dass sicherheitsrelevante HID-Geräte (z. B. FIDO-HID-Geräte für stärkere Authentifizierung) werden auch in Chrome blockiert. Weitere Informationen finden Sie in der USB-Sperrliste und Dateien mit der HID-Sperrliste

Feedback

Das Chrome-Team würde gern Ihre Meinung und Ihre Erfahrungen mit der WebHID API

Informationen zum API-Design

Gibt es etwas an der API, das nicht wie erwartet funktioniert? Oder gibt es fehlende Methoden oder Eigenschaften, die Sie benötigen, um Ihre Idee umzusetzen?

Reichen Sie ein Spezifikationsproblem im GitHub-Repository für die WebHID API ein oder schreiben Sie uns Ihre Meinung. auf ein bestehendes Problem.

Problem mit der Implementierung melden

Haben Sie bei der Implementierung von Chrome einen Fehler gefunden? Oder ist die Implementierung von der Spezifikation abweichen?

Weitere Informationen finden Sie unter WebHID-Fehler melden. Achten Sie darauf, so viele wie möglich, eine einfache Anleitung zum Reproduzieren des Fehlers geben und Components wurde auf Blink>HID festgelegt. Glitch eignet sich hervorragend für schnelle und einfache Reproduktionen.

Support anzeigen

Möchten Sie die WebHID API verwenden? Ihre öffentliche Unterstützung hilft der Chrome- priorisiert und zeigt anderen Browseranbietern, wie wichtig es ist, sie zu unterstützen.

Sende einen Tweet mit dem Hashtag an @ChromiumDev #WebHID und gib uns Bescheid, wo und wie Sie es verwenden.

Nützliche Links

Danksagungen

Vielen Dank an Matt Reynolds und Joe Medley für die Rezensionen zu diesem Artikel. Rot-blaues Nintendo Switch-Foto von Sara Kurfeß und schwarz-silberner Laptop Computerfoto von Athul Cyriac Ajay auf Unsplash.