Verbinding maken met ongebruikelijke HID-apparaten

Met de WebHID API hebben websites toegang tot alternatieve extra toetsenborden en exotische gamepads.

François Beaufort
François Beaufort

Er is een lange reeks van Human Interface Devices (HID's), zoals alternatieve toetsenborden of exotische gamepads, die te nieuw, te oud of te ongebruikelijk zijn om toegankelijk te zijn voor de apparaatstuurprogramma's van systemen. De WebHID API lost dit op door een manier te bieden om apparaatspecifieke logica in JavaScript te implementeren.

Voorgestelde gebruiksscenario's

Een HID-apparaat neemt input van of levert output aan mensen. Voorbeelden van apparaten zijn toetsenborden, aanwijsapparaten (muizen, touchscreens, enz.) en gamepads. Het HID-protocol maakt het mogelijk om toegang te krijgen tot deze apparaten op desktopcomputers met behulp van stuurprogramma's voor het besturingssysteem. Het webplatform ondersteunt HID-apparaten door op deze stuurprogramma's te vertrouwen.

Het onvermogen om toegang te krijgen tot ongebruikelijke HID-apparaten is vooral pijnlijk als het gaat om alternatieve extra toetsenborden (bijv. Elgato Stream Deck , Jabra-headsets , X-keys ) en ondersteuning voor exotische gamepads. Gamepads die voor desktop zijn ontworpen, gebruiken vaak HID voor gamepad-ingangen (knoppen, joysticks, triggers) en uitgangen (LED's, gerommel). Helaas zijn de inputs en outputs van gamepads niet goed gestandaardiseerd en vereisen webbrowsers vaak aangepaste logica voor specifieke apparaten. Dit is onhoudbaar en resulteert in slechte ondersteuning voor de lange staart van oudere en ongebruikelijke apparaten. Het zorgt er ook voor dat de browser afhankelijk is van eigenaardigheden in het gedrag van specifieke apparaten.

Terminologie

HID bestaat uit twee fundamentele concepten: rapporten en rapportdescriptoren. Rapporten zijn de gegevens die worden uitgewisseld tussen een apparaat en een softwareclient. De rapportdescriptor beschrijft het formaat en de betekenis van gegevens die het apparaat ondersteunt.

Een HID (Human Interface Device) is een type apparaat dat input van mensen ontvangt of output levert aan mensen. Het verwijst ook naar het HID-protocol, een standaard voor bidirectionele communicatie tussen een host en een apparaat die is ontworpen om de installatieprocedure te vereenvoudigen. Het HID-protocol is oorspronkelijk ontwikkeld voor USB-apparaten, maar is sindsdien geïmplementeerd via vele andere protocollen, waaronder Bluetooth.

Applicaties en HID-apparaten wisselen binaire gegevens uit via drie rapporttypen:

Rapporttype Beschrijving
Invoerrapport Gegevens die van het apparaat naar de applicatie worden verzonden (er wordt bijvoorbeeld op een knop gedrukt).
Uitvoerrapport Gegevens die vanuit de applicatie naar het apparaat worden verzonden (bijvoorbeeld een verzoek om de toetsenbordverlichting in te schakelen).
Functierapport Gegevens die in beide richtingen kunnen worden verzonden. Het formaat is apparaatspecifiek.

Een rapportdescriptor beschrijft het binaire formaat van rapporten die door het apparaat worden ondersteund. De structuur is hiërarchisch en kan rapporten groeperen als afzonderlijke collecties binnen de collectie op het hoogste niveau. Het formaat van de descriptor wordt gedefinieerd door de HID-specificatie.

Een HID-gebruik is een numerieke waarde die verwijst naar een gestandaardiseerde invoer of uitvoer. Met gebruikswaarden kan een apparaat het beoogde gebruik van het apparaat en het doel van elk veld in zijn rapporten beschrijven. Er is bijvoorbeeld één gedefinieerd voor de linkerknop van een muis. Gebruik wordt ook georganiseerd in gebruikspagina's, die een indicatie geven van de categorie op hoog niveau van het apparaat of rapport.

Met behulp van de WebHID-API

Functiedetectie

Om te controleren of de WebHID API wordt ondersteund, gebruikt u:

if ("hid" in navigator) {
  // The WebHID API is supported.
}

Open een HID-verbinding

De WebHID API is asynchroon ontworpen om te voorkomen dat de gebruikersinterface van de website blokkeert tijdens het wachten op invoer. Dit is belangrijk omdat HID-gegevens op elk moment kunnen worden ontvangen, waardoor er een manier nodig is om ernaar te luisteren.

Om een ​​HID-verbinding te openen, moet u eerst een HIDDevice object openen. Hiervoor kunt u de gebruiker vragen een apparaat te selecteren door navigator.hid.requestDevice() aan te roepen, of er een kiezen uit navigator.hid.getDevices() die een lijst retourneert met apparaten waartoe de website eerder toegang heeft gekregen.

De functie navigator.hid.requestDevice() gebruikt een verplicht object dat filters definieert. Deze worden gebruikt om elk apparaat te matchen dat is verbonden met een USB-leveranciers-ID ( vendorId ), een USB-product-ID ( productId ), een gebruikspaginawaarde ( usagePage ) en een gebruikswaarde ( usage ). U kunt deze ophalen uit de USB ID Repository en het document HID-gebruikstabellen .

De meerdere HIDDevice objecten die door deze functie worden geretourneerd, vertegenwoordigen meerdere HID-interfaces op hetzelfde fysieke apparaat.

// 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();
Schermafbeelding van een HID-apparaatprompt op een website.
Gebruikersprompt voor het selecteren van een Nintendo Switch Joy-Con.

U kunt ook de optionele exclusionFilters sleutel in navigator.hid.requestDevice() gebruiken om bijvoorbeeld bepaalde apparaten uit te sluiten van de browserkiezer waarvan bekend is dat ze niet goed werken.

// 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 }],
});

Een HIDDevice object bevat USB-leveranciers- en product-ID's voor apparaatidentificatie. Het collections wordt geïnitialiseerd met een hiërarchische beschrijving van de rapportformaten van het apparaat.

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
}

De HIDDevice apparaten worden standaard geretourneerd in een "gesloten" status en moeten worden geopend door open() aan te roepen voordat gegevens kunnen worden verzonden of ontvangen.

// Wait for the HID connection to open before sending/receiving data.
await device.open();

Ontvang inputrapporten

Zodra de HID-verbinding tot stand is gebracht, kunt u inkomende invoerrapporten afhandelen door naar de "inputreport" -gebeurtenissen van het apparaat te luisteren. Deze gebeurtenissen bevatten de HID-gegevens als een DataView object ( data ), het HID-apparaat waartoe het behoort ( device ) en de 8-bits rapport-ID die is gekoppeld aan het invoerrapport ( reportId ).

Rode en blauwe Nintendo Switch-foto.
Nintendo Switch Joy-Con-apparaten.

Als we verdergaan met het vorige voorbeeld, laat de onderstaande code zien hoe je kunt detecteren welke knop de gebruiker op een Joy-Con Right-apparaat heeft ingedrukt, zodat je het hopelijk thuis kunt proberen.

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]}.`);
});

Outputrapporten verzenden

Als u een uitvoerrapport naar een HID-apparaat wilt verzenden, geeft u de 8-bits rapport-ID die is gekoppeld aan het uitvoerrapport ( reportId ) en bytes als een BufferSource ( data ) door aan device.sendReport() . De geretourneerde belofte verdwijnt zodra het rapport is verzonden. Als het HID-apparaat geen rapport-ID's gebruikt, stelt u reportId in op 0.

Het onderstaande voorbeeld is van toepassing op een Joy-Con-apparaat en laat zien hoe je het kunt laten rommelen met uitvoerrapporten.

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

Functierapporten verzenden en ontvangen

Functierapporten zijn het enige type HID-gegevensrapporten dat in beide richtingen kan reizen. Ze zorgen ervoor dat HID-apparaten en -applicaties niet-gestandaardiseerde HID-gegevens kunnen uitwisselen. In tegenstelling tot invoer- en uitvoerrapporten worden functierapporten niet op regelmatige basis door de applicatie ontvangen of verzonden.

Zwart en zilver laptop computer foto.
Laptoptoetsenbord

Als u een functierapport naar een HID-apparaat wilt verzenden, geeft u de 8-bits rapport-ID die is gekoppeld aan het functierapport ( reportId ) en bytes als een BufferSource ( data ) door aan device.sendFeatureReport() . De geretourneerde belofte verdwijnt zodra het rapport is verzonden. Als het HID-apparaat geen rapport-ID's gebruikt, stelt u reportId in op 0.

Het onderstaande voorbeeld illustreert het gebruik van functierapporten door u te laten zien hoe u een Apple-apparaat met toetsenbordverlichting kunt aanvragen, openen en laten knipperen.

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

Als u een functierapport wilt ontvangen van een HID-apparaat, geeft u de 8-bits rapport-ID die is gekoppeld aan het functierapport ( reportId ) door aan device.receiveFeatureReport() . De geretourneerde belofte wordt opgelost met een DataView object dat de inhoud van het functierapport bevat. Als het HID-apparaat geen rapport-ID's gebruikt, stelt u reportId in op 0.

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

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

Luister naar verbinding en ontkoppeling

Wanneer aan de website toestemming is verleend om toegang te krijgen tot een HID-apparaat, kan deze actief verbindings- en ontkoppelingsgebeurtenissen ontvangen door te luisteren naar "connect" en "disconnect" -gebeurtenissen.

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

Toegang tot een HID-apparaat intrekken

De website kan de machtigingen voor toegang tot een HID-apparaat opschonen waarin het niet langer geïnteresseerd is om het te behouden, door forget() aan te roepen op de HIDDevice instantie. Voor een educatieve webapplicatie die op een gedeelde computer met veel apparaten wordt gebruikt, zorgt een groot aantal verzamelde, door gebruikers gegenereerde machtigingen bijvoorbeeld voor een slechte gebruikerservaring.

Als u forget() aanroept op een enkele HIDDevice instantie, wordt de toegang tot alle HID-interfaces op hetzelfde fysieke apparaat ingetrokken.

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

Omdat forget() beschikbaar is in Chrome 100 of hoger, controleer je of deze functie wordt ondersteund met het volgende:

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

Ontwikkelaarstips

Fouten opsporen in HID in Chrome is eenvoudig met de interne pagina, about://device-log , waar u alle HID- en USB-apparaatgerelateerde gebeurtenissen op één plek kunt zien.

Schermafbeelding van de interne pagina voor het debuggen van HID.
Interne pagina in Chrome om HID te debuggen.

Bekijk de HID-verkenner om HID-apparaatinformatie in een voor mensen leesbaar formaat te dumpen. Het wijst gebruikswaarden toe aan namen voor elk HID-gebruik.

Op de meeste Linux-systemen worden HID-apparaten standaard toegewezen met alleen-lezen-rechten. Om Chrome toe te staan ​​een HID-apparaat te openen, moet u een nieuwe udev-regel toevoegen. Maak een bestand op /etc/udev/rules.d/50-yourdevicename.rules met de volgende inhoud:

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

In de regel hierboven is [yourdevicevendor] 057e als uw apparaat bijvoorbeeld een Nintendo Switch Joy-Con is. ATTRS{idProduct} kan ook worden toegevoegd voor een specifiekere regel. Zorg ervoor dat uw user lid is van de plugdev groep. Sluit vervolgens uw apparaat opnieuw aan.

Browser-ondersteuning

De WebHID API is beschikbaar op alle desktopplatforms (ChromeOS, Linux, macOS en Windows) in Chrome 89.

Demo's

Sommige WebHID-demo's staan ​​vermeld op web.dev/hid-examples . Ga eens kijken!

Veiligheid en privacy

De auteurs van de specificaties hebben de WebHID API ontworpen en geïmplementeerd met behulp van de kernprincipes die zijn gedefinieerd in Controlling Access to Powerful Web Platform Features , inclusief gebruikerscontrole, transparantie en ergonomie. De mogelijkheid om deze API te gebruiken wordt voornamelijk bepaald door een toestemmingsmodel dat toegang verleent aan slechts één HID-apparaat tegelijk. Als reactie op een gebruikersprompt moet de gebruiker actieve stappen ondernemen om een ​​bepaald HID-apparaat te selecteren.

Om de beveiligingsafwegingen te begrijpen, bekijk het gedeelte Beveiligings- en privacyoverwegingen van de WebHID-specificatie.

Bovendien inspecteert Chrome het gebruik van elke collectie op het hoogste niveau. Als een collectie op het hoogste niveau een beschermd gebruik heeft (bijvoorbeeld een algemeen toetsenbord, muis), kan een website geen rapporten verzenden en ontvangen die zijn gedefinieerd in die collectie. De volledige lijst met beschermde toepassingen is openbaar beschikbaar .

Houd er rekening mee dat beveiligingsgevoelige HID-apparaten (zoals FIDO HID-apparaten die worden gebruikt voor sterkere authenticatie) ook worden geblokkeerd in Chrome. Bekijk de USB-blokkeerlijst- en HID-blokkeerlijstbestanden .

Feedback

Het Chrome-team hoort graag uw mening en ervaringen met de WebHID API.

Vertel ons over het API-ontwerp

Is er iets aan de API dat niet werkt zoals verwacht? Of ontbreken er methoden of eigenschappen die je nodig hebt om je idee te implementeren?

Dien een spec-probleem in op de WebHID API GitHub-opslagplaats of voeg uw mening toe aan een bestaand probleem.

Meld een probleem met de implementatie

Heeft u een bug gevonden in de implementatie van Chrome? Of wijkt de uitvoering af van de specificaties?

Bekijk WebHID-bugs indienen . Zorg ervoor dat u zoveel mogelijk details vermeldt, geef eenvoudige instructies voor het reproduceren van de bug en zorg ervoor dat Componenten zijn ingesteld op Blink>HID . Glitch werkt uitstekend voor het delen van snelle en gemakkelijke reproducties.

Toon steun

Bent u van plan de WebHID API te gebruiken? Uw publieke steun helpt het Chrome-team prioriteiten te stellen voor functies en laat andere browserleveranciers zien hoe belangrijk het is om deze te ondersteunen.

Stuur een tweet naar @ChromiumDev met de hashtag #WebHID en laat ons weten waar en hoe u deze gebruikt.

Handige Links

Dankbetuigingen

Met dank aan Matt Reynolds en Joe Medley voor hun recensies van dit artikel. Rode en blauwe Nintendo Switch-foto door Sara Kurfeß , en zwart-zilveren laptopfoto door Athul Cyriac Ajay op Unsplash.

,

Met de WebHID API hebben websites toegang tot alternatieve extra toetsenborden en exotische gamepads.

François Beaufort
François Beaufort

Er is een lange reeks van Human Interface Devices (HID's), zoals alternatieve toetsenborden of exotische gamepads, die te nieuw, te oud of te ongebruikelijk zijn om toegankelijk te zijn voor de apparaatstuurprogramma's van systemen. De WebHID API lost dit op door een manier te bieden om apparaatspecifieke logica in JavaScript te implementeren.

Voorgestelde gebruiksscenario's

Een HID-apparaat neemt input van of levert output aan mensen. Voorbeelden van apparaten zijn toetsenborden, aanwijsapparaten (muizen, touchscreens, enz.) en gamepads. Het HID-protocol maakt het mogelijk om toegang te krijgen tot deze apparaten op desktopcomputers met behulp van stuurprogramma's voor het besturingssysteem. Het webplatform ondersteunt HID-apparaten door op deze stuurprogramma's te vertrouwen.

Het onvermogen om toegang te krijgen tot ongebruikelijke HID-apparaten is vooral pijnlijk als het gaat om alternatieve extra toetsenborden (bijv. Elgato Stream Deck , Jabra-headsets , X-keys ) en ondersteuning voor exotische gamepads. Gamepads die voor desktop zijn ontworpen, gebruiken vaak HID voor gamepad-ingangen (knoppen, joysticks, triggers) en uitgangen (LED's, gerommel). Helaas zijn de inputs en outputs van gamepads niet goed gestandaardiseerd en vereisen webbrowsers vaak aangepaste logica voor specifieke apparaten. Dit is onhoudbaar en resulteert in slechte ondersteuning voor de lange staart van oudere en ongebruikelijke apparaten. Het zorgt er ook voor dat de browser afhankelijk is van eigenaardigheden in het gedrag van specifieke apparaten.

Terminologie

HID bestaat uit twee fundamentele concepten: rapporten en rapportdescriptoren. Rapporten zijn de gegevens die worden uitgewisseld tussen een apparaat en een softwareclient. De rapportdescriptor beschrijft het formaat en de betekenis van gegevens die het apparaat ondersteunt.

Een HID (Human Interface Device) is een type apparaat dat input van mensen ontvangt of output levert aan mensen. Het verwijst ook naar het HID-protocol, een standaard voor bidirectionele communicatie tussen een host en een apparaat die is ontworpen om de installatieprocedure te vereenvoudigen. Het HID-protocol is oorspronkelijk ontwikkeld voor USB-apparaten, maar is sindsdien geïmplementeerd via vele andere protocollen, waaronder Bluetooth.

Applicaties en HID-apparaten wisselen binaire gegevens uit via drie rapporttypen:

Rapporttype Beschrijving
Invoerrapport Gegevens die van het apparaat naar de applicatie worden verzonden (er wordt bijvoorbeeld op een knop gedrukt).
Uitvoerrapport Gegevens die vanuit de applicatie naar het apparaat worden verzonden (bijvoorbeeld een verzoek om de toetsenbordverlichting in te schakelen).
Functierapport Gegevens die in beide richtingen kunnen worden verzonden. Het formaat is apparaatspecifiek.

Een rapportdescriptor beschrijft het binaire formaat van rapporten die door het apparaat worden ondersteund. De structuur is hiërarchisch en kan rapporten groeperen als afzonderlijke collecties binnen de collectie op het hoogste niveau. Het formaat van de descriptor wordt gedefinieerd door de HID-specificatie.

Een HID-gebruik is een numerieke waarde die verwijst naar een gestandaardiseerde invoer of uitvoer. Met gebruikswaarden kan een apparaat het beoogde gebruik van het apparaat en het doel van elk veld in zijn rapporten beschrijven. Er is bijvoorbeeld één gedefinieerd voor de linkerknop van een muis. Gebruik wordt ook georganiseerd in gebruikspagina's, die een indicatie geven van de categorie op hoog niveau van het apparaat of rapport.

Met behulp van de WebHID-API

Functiedetectie

Om te controleren of de WebHID API wordt ondersteund, gebruikt u:

if ("hid" in navigator) {
  // The WebHID API is supported.
}

Open een HID-verbinding

De WebHID API is asynchroon ontworpen om te voorkomen dat de gebruikersinterface van de website blokkeert tijdens het wachten op invoer. Dit is belangrijk omdat HID-gegevens op elk moment kunnen worden ontvangen, waardoor er een manier nodig is om ernaar te luisteren.

Om een ​​HID-verbinding te openen, moet u eerst een HIDDevice object openen. Hiervoor kunt u de gebruiker vragen een apparaat te selecteren door navigator.hid.requestDevice() aan te roepen, of er een kiezen uit navigator.hid.getDevices() die een lijst retourneert met apparaten waartoe de website eerder toegang heeft gekregen.

De functie navigator.hid.requestDevice() gebruikt een verplicht object dat filters definieert. Deze worden gebruikt om elk apparaat te matchen dat is verbonden met een USB-leveranciers-ID ( vendorId ), een USB-product-ID ( productId ), een gebruikspaginawaarde ( usagePage ) en een gebruikswaarde ( usage ). U kunt deze ophalen uit de USB ID Repository en het document HID-gebruikstabellen .

De meerdere HIDDevice objecten die door deze functie worden geretourneerd, vertegenwoordigen meerdere HID-interfaces op hetzelfde fysieke apparaat.

// 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();
Schermafbeelding van een HID-apparaatprompt op een website.
Gebruikersprompt voor het selecteren van een Nintendo Switch Joy-Con.

U kunt ook de optionele exclusionFilters sleutel in navigator.hid.requestDevice() gebruiken om bijvoorbeeld bepaalde apparaten uit te sluiten van de browserkiezer waarvan bekend is dat ze niet goed werken.

// 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 }],
});

Een HIDDevice object bevat USB-leveranciers- en product-ID's voor apparaatidentificatie. Het collections wordt geïnitialiseerd met een hiërarchische beschrijving van de rapportformaten van het apparaat.

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
}

De HIDDevice apparaten worden standaard geretourneerd in een "gesloten" status en moeten worden geopend door open() aan te roepen voordat gegevens kunnen worden verzonden of ontvangen.

// Wait for the HID connection to open before sending/receiving data.
await device.open();

Ontvang inputrapporten

Zodra de HID-verbinding tot stand is gebracht, kunt u inkomende invoerrapporten afhandelen door naar de "inputreport" -gebeurtenissen van het apparaat te luisteren. Deze gebeurtenissen bevatten de HID-gegevens als een DataView object ( data ), het HID-apparaat waartoe het behoort ( device ) en de 8-bits rapport-ID die is gekoppeld aan het invoerrapport ( reportId ).

Rode en blauwe Nintendo Switch-foto.
Nintendo Switch Joy-Con-apparaten.

Als we verdergaan met het vorige voorbeeld, laat de onderstaande code zien hoe je kunt detecteren welke knop de gebruiker op een Joy-Con Right-apparaat heeft ingedrukt, zodat je het hopelijk thuis kunt proberen.

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]}.`);
});

Outputrapporten verzenden

Als u een uitvoerrapport naar een HID-apparaat wilt verzenden, geeft u de 8-bits rapport-ID die is gekoppeld aan het uitvoerrapport ( reportId ) en bytes als een BufferSource ( data ) door aan device.sendReport() . De geretourneerde belofte verdwijnt zodra het rapport is verzonden. Als het HID-apparaat geen rapport-ID's gebruikt, stelt u reportId in op 0.

Het onderstaande voorbeeld is van toepassing op een Joy-Con-apparaat en laat zien hoe je het kunt laten rommelen met uitvoerrapporten.

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

Functierapporten verzenden en ontvangen

Functierapporten zijn het enige type HID-gegevensrapporten dat in beide richtingen kan reizen. Ze zorgen ervoor dat HID-apparaten en -applicaties niet-gestandaardiseerde HID-gegevens kunnen uitwisselen. In tegenstelling tot invoer- en uitvoerrapporten worden functierapporten niet op regelmatige basis door de applicatie ontvangen of verzonden.

Zwart en zilver laptop computer foto.
Laptoptoetsenbord

Als u een functierapport naar een HID-apparaat wilt verzenden, geeft u de 8-bits rapport-ID die is gekoppeld aan het functierapport ( reportId ) en bytes als een BufferSource ( data ) door aan device.sendFeatureReport() . De geretourneerde belofte verdwijnt zodra het rapport is verzonden. Als het HID-apparaat geen rapport-ID's gebruikt, stelt u reportId in op 0.

Het onderstaande voorbeeld illustreert het gebruik van functierapporten door u te laten zien hoe u een Apple-apparaat met toetsenbordverlichting kunt aanvragen, openen en laten knipperen.

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

Als u een functierapport van een HID-apparaat wilt ontvangen, geeft u de 8-bits rapport-ID die aan het functierapport is gekoppeld ( reportId ) door aan device.receiveFeatureReport() . De geretourneerde belofte wordt opgelost met een DataView object dat de inhoud van het functierapport bevat. Als het HID-apparaat geen rapport-ID's gebruikt, stelt u reportId in op 0.

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

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

Luister naar verbinding en ontkoppeling

Wanneer aan de website toestemming is verleend om toegang te krijgen tot een HID-apparaat, kan deze actief verbindings- en ontkoppelingsgebeurtenissen ontvangen door te luisteren naar "connect" en "disconnect" -gebeurtenissen.

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

Toegang tot een HID-apparaat intrekken

De website kan de machtigingen voor toegang tot een HID-apparaat opschonen waarin het niet langer geïnteresseerd is om het te behouden, door forget() aan te roepen op de HIDDevice instantie. Voor een educatieve webapplicatie die op een gedeelde computer met veel apparaten wordt gebruikt, zorgt een groot aantal verzamelde, door gebruikers gegenereerde machtigingen bijvoorbeeld voor een slechte gebruikerservaring.

Als u forget() aanroept op een enkele HIDDevice instantie, wordt de toegang tot alle HID-interfaces op hetzelfde fysieke apparaat ingetrokken.

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

Omdat forget() beschikbaar is in Chrome 100 of hoger, controleer je of deze functie wordt ondersteund met het volgende:

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

Ontwikkelaarstips

Fouten opsporen in HID in Chrome is eenvoudig met de interne pagina, about://device-log , waar u alle HID- en USB-apparaatgerelateerde gebeurtenissen op één plek kunt zien.

Schermafbeelding van de interne pagina voor het debuggen van HID.
Interne pagina in Chrome om HID te debuggen.

Bekijk de HID-verkenner om HID-apparaatinformatie in een voor mensen leesbaar formaat te dumpen. Het wijst gebruikswaarden toe aan namen voor elk HID-gebruik.

Op de meeste Linux-systemen worden HID-apparaten standaard toegewezen met alleen-lezen-rechten. Om Chrome toe te staan ​​een HID-apparaat te openen, moet u een nieuwe udev-regel toevoegen. Maak een bestand op /etc/udev/rules.d/50-yourdevicename.rules met de volgende inhoud:

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

In de regel hierboven is [yourdevicevendor] 057e als uw apparaat bijvoorbeeld een Nintendo Switch Joy-Con is. ATTRS{idProduct} kan ook worden toegevoegd voor een specifiekere regel. Zorg ervoor dat uw user lid is van de plugdev groep. Sluit vervolgens uw apparaat opnieuw aan.

Browser-ondersteuning

De WebHID API is beschikbaar op alle desktopplatforms (ChromeOS, Linux, macOS en Windows) in Chrome 89.

Demo's

Sommige WebHID-demo's staan ​​vermeld op web.dev/hid-examples . Ga eens kijken!

Veiligheid en privacy

De auteurs van de specificaties hebben de WebHID API ontworpen en geïmplementeerd met behulp van de kernprincipes die zijn gedefinieerd in Controlling Access to Powerful Web Platform Features , inclusief gebruikerscontrole, transparantie en ergonomie. De mogelijkheid om deze API te gebruiken wordt voornamelijk bepaald door een toestemmingsmodel dat toegang verleent aan slechts één HID-apparaat tegelijk. Als reactie op een gebruikersprompt moet de gebruiker actieve stappen ondernemen om een ​​bepaald HID-apparaat te selecteren.

Om de beveiligingsafwegingen te begrijpen, bekijk het gedeelte Beveiligings- en privacyoverwegingen van de WebHID-specificatie.

Bovendien inspecteert Chrome het gebruik van elke collectie op het hoogste niveau. Als een collectie op het hoogste niveau een beschermd gebruik heeft (bijvoorbeeld een algemeen toetsenbord, muis), kan een website geen rapporten verzenden en ontvangen die zijn gedefinieerd in die collectie. De volledige lijst met beschermde toepassingen is openbaar beschikbaar .

Houd er rekening mee dat beveiligingsgevoelige HID-apparaten (zoals FIDO HID-apparaten die worden gebruikt voor sterkere authenticatie) ook worden geblokkeerd in Chrome. Bekijk de USB-blokkeerlijst- en HID-blokkeerlijstbestanden .

Feedback

Het Chrome-team hoort graag uw mening en ervaringen met de WebHID API.

Vertel ons over het API-ontwerp

Is er iets aan de API dat niet werkt zoals verwacht? Of ontbreken er methoden of eigenschappen die je nodig hebt om je idee te implementeren?

Dien een spec-probleem in op de WebHID API GitHub-opslagplaats of voeg uw mening toe aan een bestaand probleem.

Meld een probleem met de implementatie

Heeft u een bug gevonden in de implementatie van Chrome? Of wijkt de uitvoering af van de specificaties?

Bekijk WebHID-bugs indienen . Zorg ervoor dat u zoveel mogelijk details vermeldt, geef eenvoudige instructies voor het reproduceren van de bug en zorg ervoor dat Componenten zijn ingesteld op Blink>HID . Glitch werkt uitstekend voor het delen van snelle en gemakkelijke reproducties.

Toon steun

Bent u van plan de WebHID API te gebruiken? Uw publieke steun helpt het Chrome-team prioriteiten te stellen voor functies en laat andere browserleveranciers zien hoe belangrijk het is om deze te ondersteunen.

Stuur een tweet naar @ChromiumDev met de hashtag #WebHID en laat ons weten waar en hoe u deze gebruikt.

Handige Links

Dankbetuigingen

Met dank aan Matt Reynolds en Joe Medley voor hun recensies van dit artikel. Rode en blauwe Nintendo Switch-foto door Sara Kurfeß , en zwart-zilveren laptopfoto door Athul Cyriac Ajay op Unsplash.