Connessione a dispositivi HID insoliti

L'API WebHID consente ai siti web di accedere a tastiere ausiliarie alternative e gamepad esotici.

François Beaufort
François Beaufort

C'è una "long tail" di dispositivi con interfaccia umana (HID), come tastiere o gamepad esotici, troppo nuovi, troppo vecchi o troppo insoliti per essere accessibili dai sistemi i driver di dispositivo. L'API WebHID risolve questo problema fornendo un per implementare una logica specifica per il dispositivo in JavaScript.

Casi d'uso suggeriti

Un dispositivo HID riceve l'input dagli esseri umani o li fornisce. Esempi di dispositivi includono tastiere, dispositivi di puntamento (Mouse, touchscreen e così via) e gamepad. Il protocollo HID consente di accedere a questi dispositivi da computer. computer che utilizzano driver del sistema operativo. La piattaforma web supporta i dispositivi HID facendo affidamento su questi fattori.

L'impossibilità di accedere a dispositivi HID insoliti è particolarmente dolorosa quando offre tastiere ausiliarie alternative (ad es. Elgato Stream Deck, Jabra) cuffie, tasti X) ed esotico supporto per gamepad. Gamepad progettati per i computer spesso utilizzano l'HID per gli input (pulsanti, joystick, trigger) e gli output del gamepad (LED, rumore). Purtroppo, gli input e gli output del gamepad non sono ben standardizzati e browser web spesso richiedono una logica personalizzata per dispositivi specifici. È una soluzione insostenibile e si traduce in un supporto scarso per la long tail di bambini e ragazzi dispositivi insoliti. Inoltre, il browser potrebbe dipendere da anomalie nel comportamento. di dispositivi specifici.

Terminologia

L'HID si basa su due concetti fondamentali: report e descrittori dei report. I report sono i dati scambiati tra un dispositivo e un client software. Il descrittore del report descrive il formato e il significato dei dati che il dispositivo Google Cloud.

Un HID (Human Interface Device) è un tipo di dispositivo che riceve input da o fornisce output agli esseri umani. Si riferisce anche al protocollo HID, uno standard per comunicazione bidirezionale tra un host e un dispositivo progettato per semplificare la procedura di installazione. Il protocollo HID è stato originariamente sviluppato per i dispositivi USB, ma da allora è stato implementato su molti altri protocolli, incluso il Bluetooth.

Applicazioni e dispositivi HID scambiano dati binari tramite tre tipi di report:

Tipo di rapporto Descrizione
Report input Dati inviati dal dispositivo all'applicazione (ad esempio la pressione di un pulsante).
Output report Dati inviati dall'applicazione al dispositivo (ad es. la richiesta di attivare la retroilluminazione della tastiera).
Report Funzionalità Dati che possono essere inviati in entrambe le direzioni. Il formato è specifico per dispositivo.

Un descrittore di report descrive il formato binario dei report supportati dal dispositivo. La sua struttura è gerarchica e può raggruppare i report in modo all'interno della raccolta di primo livello. Il formato del descrittore è definito dalla specifica HID.

Un utilizzo HID è un valore numerico che fa riferimento a un input o output standardizzato. I valori di utilizzo consentono a un dispositivo di descrivere l'utilizzo previsto del dispositivo lo scopo di ogni campo nei suoi report. Ad esempio, ne viene definito uno per il il pulsante del mouse. Gli utilizzi sono inoltre organizzati in pagine di utilizzo, che forniscono una un'indicazione della categoria di alto livello del dispositivo o del report.

Utilizzo dell'API WebHID

Rilevamento delle caratteristiche

Per verificare se l'API WebHID è supportata, utilizza:

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

Apri una connessione HID

L'API WebHID è asincrona per impedire all'interfaccia utente del sito web di quando sono in attesa di input. Questo è importante perché è possibile ricevere dati HID in qualsiasi momento, richiedendo un modo per ascoltarli.

Per aprire una connessione HID, accedi prima a un oggetto HIDDevice. A questo scopo, puoi puoi chiedere all'utente di selezionare un dispositivo chiamando navigator.hid.requestDevice() o scegline una da navigator.hid.getDevices() che restituisce un elenco dei dispositivi a cui è stato concesso l'accesso al sito web in precedenza.

La funzione navigator.hid.requestDevice() accetta un oggetto obbligatorio che definisce i filtri. Questi vengono utilizzati per abbinare qualsiasi dispositivo collegato a un fornitore USB identificatore di prodotto (vendorId), un codice identificativo di prodotto USB (productId), una pagina Utilizzo (usagePage) e un valore di utilizzo (usage). Puoi recuperare questi dati dal USB ID Repository e il documento delle tabelle di utilizzo HID.

I vari oggetti HIDDevice restituiti da questa funzione rappresentano più Interfacce HID sullo stesso dispositivo fisico.

// 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();
Screenshot della richiesta di un dispositivo HID su un sito web.
Richiesta all'utente di selezionare una Joy-Con per Nintendo Switch.

Puoi anche utilizzare la chiave facoltativa exclusionFilters in navigator.hid.requestDevice() per escludere alcuni dispositivi dal selettore del browser noti per esempio per essere malfunzionanti.

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

Un oggetto HIDDevice contiene il fornitore USB e gli ID prodotto del dispositivo l'identificazione personale. Il suo attributo collections è inizializzato con un ordine gerarchico descrizione dei formati dei report del dispositivo.

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
}

Per impostazione predefinita, i dispositivi HIDDevice vengono restituiti in un contenitore "chiuso" e deve essere aperta chiamando open() prima che i dati possano essere inviati o ricevuti.

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

Ricevi report di input

Una volta stabilita la connessione HID, puoi gestire l'input in entrata i report ascoltando gli eventi "inputreport" dal dispositivo. Questi eventi Contenere i dati HID come oggetto DataView (data), il dispositivo HID a cui appartiene a (device) e l'ID report a 8 bit associato al report di input (reportId).

Foto di Nintendo Switch di colore rosso e blu.
Dispositivi Joy-Con per Nintendo Switch.

Continuando con l'esempio precedente, il codice seguente mostra come rilevare quale pulsante ha premuto l'utente su un dispositivo Joy-Con destro per spero di provarla a casa.

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

Invia report di output

Per inviare un report di output a un dispositivo HID, trasmetti l'ID report a 8 bit associato con il report di output (reportId) e byte come BufferSource (data) per device.sendReport(), La promessa restituita si risolve una volta che il report è stato inviate. Se il dispositivo HID non usa gli ID report, imposta reportId su 0.

L'esempio riportato di seguito riguarda un dispositivo Joy-Con e ti mostra come realizzare creare report di output.

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

Invia e ricevi report sulle funzionalità

I report sulle funzionalità sono l'unico tipo di report sui dati HID che può essere inviato indicazioni stradali. Consentono lo scambio di applicazioni e dispositivi HID non standardizzati Dati HID. A differenza dei report di input e output, i report sulle funzionalità non vengono ricevuti inviate regolarmente dall'applicazione.

Foto di un laptop nero e argento.
Tastiera del laptop

Per inviare un report sulle funzionalità a un dispositivo HID, trasmetti l'ID report a 8 bit associato con il report sulle funzionalità (reportId) e i byte come BufferSource (data) per device.sendFeatureReport(), La promessa restituita si risolve una volta che il report inviate. Se il dispositivo HID non usa gli ID report, imposta reportId su 0.

L'esempio riportato di seguito illustra l'utilizzo dei report sulle funzionalità mostrando come richiedere un dispositivo per la retroilluminazione della tastiera Apple, aprirlo e farlo lampeggiare.

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

Per ricevere un report sulle funzionalità da un dispositivo HID, trasmetti l'ID report a 8 bit associate al report sulle funzionalità (reportId) per device.receiveFeatureReport(). La promessa restituita si risolve con DataView che include i contenuti del report sulle funzionalità. Se l'HID Il dispositivo non utilizza gli ID report, imposta reportId su 0.

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

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

Ascolta connessione e disconnessione

Quando al sito web viene concessa l'autorizzazione ad accedere a un dispositivo HID, può ricevere attivamente eventi di connessione e disconnessione ascoltando "connect" e "disconnect" eventi.

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

Revocare l'accesso a un dispositivo HID

Il sito web può eliminare le autorizzazioni per accedere a un dispositivo HID che non è più che ti interessa mantenere chiamando forget() sull'istanza HIDDevice. Per per un'applicazione web didattica utilizzata su un computer condiviso con molte dispositivi, un numero elevato di autorizzazioni generate dagli utenti un'esperienza utente positiva.

La chiamata di forget() su una singola istanza HIDDevice revocherà l'accesso a tutti le interfacce HID sullo stesso dispositivo fisico.

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

Poiché forget() è disponibile in Chrome 100 o versioni successive, controlla se questa funzionalità è supportati con quanto segue:

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

Suggerimenti per gli sviluppatori

Eseguire il debug di HID in Chrome è facile con la pagina interna about://device-log dove puoi vedere in un unico posto tutti gli eventi relativi a dispositivi HID e USB.

Screenshot della pagina interna per eseguire il debug dell&#39;HID.
Pagina interna in Chrome per eseguire il debug dell'HID.

Controlla l'Explorer HID per eseguire il dump del dispositivo HID in un formato leggibile. Mappa dai valori di utilizzo ai nomi di ogni Utilizzo dell'HID.

Sulla maggior parte dei sistemi Linux, i dispositivi HID sono mappati con autorizzazioni di sola lettura predefinito. Per consentire a Chrome di aprire un dispositivo HID, dovrai aggiungere un nuovo udev personalizzata. Crea un file all'indirizzo /etc/udev/rules.d/50-yourdevicename.rules con i seguenti contenuti:

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

Nella riga precedente, [yourdevicevendor] è 057e se il tuo dispositivo è Nintendo Switch ad esempio Joy-Con. Puoi anche aggiungere ATTRS{idProduct} per una configurazione personalizzata. Assicurati che user sia un membro del gruppo plugdev. Poi, ricollega il dispositivo.

Supporto browser

L'API WebHID è disponibile su tutte le piattaforme desktop (ChromeOS, Linux, macOS, e Windows) in Chrome 89.

Demo

Alcune demo di WebHID sono elencate all'indirizzo web.dev/hid-examples. Dai un'occhiata!

Sicurezza e privacy

Gli autori delle specifiche hanno progettato e implementato l'API WebHID utilizzando le principi definiti in Controllo dell'accesso a potenti funzionalità della piattaforma web, tra cui controllo dell'utente, trasparenza ed ergonomia. Possibilità di utilizzare L'API è controllata principalmente da un modello di autorizzazione che concede l'accesso solo a un singolo Dispositivo HID alla volta. In risposta al prompt di un utente, quest'ultimo deve attivare passaggi per selezionare un determinato dispositivo HID.

Per comprendere i compromessi in termini di sicurezza, consulta Sicurezza e privacy Considerazioni della specifica WebHID.

Inoltre, Chrome controlla l'utilizzo di ogni raccolta di primo livello e se raccolta di primo livello ha un utilizzo protetto (ad es. tastiera generica, mouse), quindi un sito web non potrà inviare e ricevere i report definiti in questo . L'elenco completo degli utilizzi protetti è disponibile pubblicamente.

Tieni presente che i dispositivi HID sensibili alla sicurezza (come i dispositivi HID FIDO utilizzati per autenticazione più forte) sono bloccati anche in Chrome. Consulta la lista bloccata USB e File della lista bloccata HID.

Feedback

Il team di Chrome vorrebbe conoscere la tua opinione ed esperienza con gli API WebHID.

Parlaci della progettazione dell'API

C'è qualcosa che non funziona come previsto nell'API? Oppure ci sono mancano metodi o proprietà necessari per implementare la tua idea?

Segnala un problema relativo alle specifiche nel repository GitHub dell'API WebHID o aggiungi le tue opinioni a un problema esistente.

Segnalare un problema con l'implementazione

Hai trovato un bug nell'implementazione di Chrome? Oppure l'implementazione rispetto alle specifiche?

Leggi l'articolo su come segnalare bug WebHID. Assicurati di includere fornire maggiori dettagli possibili, fornire semplici istruzioni per riprodurre il bug e Componenti impostati su Blink>HID. Glitch è perfetto per e condividere riproduzioni facili e veloci.

Mostra il tuo sostegno

Intendi utilizzare l'API WebHID? Il tuo supporto pubblico aiuta Chrome del team assegna la priorità alle funzionalità e mostra ad altri fornitori di browser quanto sia fondamentale supportarle.

Invia un tweet a @ChromiumDev utilizzando l'hashtag #WebHID e faccelo sapere dove e come lo usi.

Link utili

Ringraziamenti

Grazie a Matt Reynolds e Joe Medley per le loro recensioni su questo articolo. Foto di Nintendo Switch rossa e blu di Sara Kurfeß e laptop nero e argento foto al computer di Athul Cyriac Ajay su Unsplash.