L'API WebHID permet aux sites Web d'accéder à d'autres claviers auxiliaires et à des manettes de jeu exotiques.
Il existe une longue traîne de périphériques d'interface humaine (HID), tels que des claviers alternatifs ou des manettes de jeu exotiques, qui sont trop récents, trop anciens ou trop inhabituels pour être accessibles par les pilotes d'appareils des systèmes. L'API WebHID résout ce problème en fournissant un moyen d'implémenter une logique propre à l'appareil en JavaScript.
Suggestions de cas d'utilisation
Un appareil HID reçoit des entrées ou fournit des sorties à des humains. Les claviers, les dispositifs de pointage (souris, écrans tactiles, etc.) et les manettes de jeu en sont des exemples. Le protocole HID permet d'accéder à ces appareils sur les ordinateurs de bureau à l'aide de pilotes de système d'exploitation. La plate-forme Web est compatible avec les appareils HID en s'appuyant sur ces pilotes.
L'impossibilité d'accéder aux périphériques HID inhabituels est particulièrement pénible lorsqu'il s'agit d'autres claviers auxiliaires (par exemple, Elgato Stream Deck, casques Jabra, X-keys) et de la prise en charge de manettes de jeu exotiques. Les manettes de jeu conçues pour les ordinateurs de bureau utilisent souvent HID pour les entrées (boutons, joysticks, déclencheurs) et les sorties (voyants, retour haptique) de la manette. Malheureusement, les entrées et sorties des manettes de jeu ne sont pas bien standardisées, et les navigateurs Web nécessitent souvent une logique personnalisée pour des appareils spécifiques. Cette situation n'est pas viable et entraîne une mauvaise prise en charge de la longue traîne d'appareils plus anciens et inhabituels. Le navigateur dépend également des particularités du comportement d'appareils spécifiques.
Terminologie
HID se compose de deux concepts fondamentaux: les rapports et les descripteurs de rapports. Les rapports sont les données échangées entre un appareil et un client logiciel. Le descripteur de rapport décrit le format et la signification des données compatibles avec l'appareil.
Un périphérique d'interface humaine (HID) est un type d'appareil qui reçoit des entrées ou fournit des sorties à des humains. Il fait également référence au protocole HID, une norme de communication bidirectionnelle entre un hôte et un appareil conçue pour simplifier la procédure d'installation. Le protocole HID a été développé à l'origine pour les appareils USB, mais il a depuis été implémenté sur de nombreux autres protocoles, y compris Bluetooth.
Les applications et les appareils HID échangent des données binaires via trois types de rapports:
Type de rapport | Description |
---|---|
Rapport sur les entrées | Données envoyées de l'appareil à l'application (par exemple, un bouton est enfoncé). |
Rapport de sortie | Données envoyées de l'application à l'appareil (par exemple, une requête pour allumer le rétroéclairage du clavier). |
Rapport sur les fonctionnalités | Données pouvant être envoyées dans les deux sens. Le format est spécifique à l'appareil. |
Un descripteur de rapport décrit le format binaire des rapports compatibles avec l'appareil. Sa structure est hiérarchique et peut regrouper des rapports en collections distinctes au sein de la collection de niveau supérieur. Le format du descripteur est défini par la spécification HID.
Une utilisation HID est une valeur numérique faisant référence à une entrée ou une sortie standardisée. Les valeurs d'utilisation permettent à un appareil de décrire l'utilisation prévue de l'appareil et l'objectif de chaque champ dans ses rapports. Par exemple, un est défini pour le bouton gauche d'une souris. Les utilisations sont également organisées en pages d'utilisation, qui indiquent la catégorie de haut niveau de l'appareil ou du rapport.
Utiliser l'API WebHID
Détection de fonctionnalités
Pour vérifier si l'API WebHID est prise en charge, utilisez:
if ("hid" in navigator) {
// The WebHID API is supported.
}
Établir une connexion HID
L'API WebHID est asynchrone par conception pour éviter que l'interface utilisateur du site Web ne se bloque en attente d'entrée. Ceci est important, car les données HID peuvent être reçues à tout moment, ce qui nécessite un moyen de les écouter.
Pour ouvrir une connexion HID, accédez d'abord à un objet HIDDevice
. Pour ce faire, vous pouvez demander à l'utilisateur de sélectionner un appareil en appelant navigator.hid.requestDevice()
ou en en sélectionnant un dans navigator.hid.getDevices()
, qui renvoie une liste des appareils auxquels le site Web a déjà été autorisé à accéder.
La fonction navigator.hid.requestDevice()
utilise un objet obligatoire qui définit des filtres. Ils permettent de faire correspondre n'importe quel appareil connecté à un identifiant de fournisseur USB (vendorId
), un identifiant de produit USB (productId
), une valeur de page d'utilisation (usagePage
) et une valeur d'utilisation (usage
). Vous pouvez les obtenir à partir du répertoire d'ID USB et du document sur les tables d'utilisation des appareils HID.
Les multiples objets HIDDevice
renvoyés par cette fonction représentent plusieurs interfaces HID sur le même appareil physique.
// 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();
Vous pouvez également utiliser la clé exclusionFilters
facultative dans navigator.hid.requestDevice()
pour exclure certains appareils du sélecteur de navigateur qui sont connus pour ne pas fonctionner correctement, par exemple.
// 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 objet HIDDevice
contient des identifiants de fournisseur et de produit USB pour l'identification de l'appareil. Son attribut collections
est initialisé avec une description hiérarchique des formats de rapport de l'appareil.
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
}
Les appareils HIDDevice
sont renvoyés par défaut dans un état "fermé" et doivent être ouverts en appelant open()
avant que des données puissent être envoyées ou reçues.
// Wait for the HID connection to open before sending/receiving data.
await device.open();
Recevoir des rapports sur les entrées
Une fois la connexion HID établie, vous pouvez gérer les rapports d'entrée entrants en écoutant les événements "inputreport"
de l'appareil. Ces événements contiennent les données HID sous la forme d'un objet DataView
(data
), de l'appareil HID auquel il appartient (device
) et de l'ID de rapport 8 bits associé au rapport d'entrée (reportId
).
Poursuivant l'exemple précédent, le code ci-dessous vous montre comment détecter le bouton sur lequel l'utilisateur a appuyé sur un appareil Joy-Con droit afin que vous puissiez l'essayer chez vous.
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]}.`);
});
Envoyer des rapports de sortie
Pour envoyer un rapport de sortie à un appareil HID, transmettez l'ID de rapport 8 bits associé au rapport de sortie (reportId
) et les octets en tant que BufferSource
(data
) à device.sendReport()
. La promesse renvoyée est résolue une fois le rapport envoyé. Si l'appareil HID n'utilise pas d'ID de rapport, définissez reportId
sur 0.
L'exemple ci-dessous s'applique à un appareil Joy-Con et vous montre comment le faire vibrer à l'aide de rapports de sortie.
// 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));
Envoyer et recevoir des rapports sur les fonctionnalités
Les rapports sur les éléments géographiques sont le seul type de rapports sur les données HID pouvant circuler dans les deux sens. Ils permettent aux appareils et applications HID d'échanger des données HID non standardisées. Contrairement aux rapports d'entrée et de sortie, les rapports sur les fonctionnalités ne sont pas reçus ni envoyés régulièrement par l'application.
Pour envoyer un rapport de fonctionnalité à un appareil HID, transmettez l'ID de rapport 8 bits associé au rapport de fonctionnalité (reportId
) et les octets en tant que BufferSource
(data
) à device.sendFeatureReport()
. La promesse renvoyée est résolue une fois le rapport envoyé. Si l'appareil HID n'utilise pas d'ID de rapport, définissez reportId
sur 0.
L'exemple ci-dessous illustre l'utilisation des rapports sur les fonctionnalités en vous montrant comment demander un appareil de rétroéclairage de clavier Apple, l'ouvrir et le faire clignoter.
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);
}
Pour recevoir un rapport de fonctionnalités à partir d'un appareil HID, transmettez l'ID de rapport 8 bits associé au rapport de fonctionnalités (reportId
) à device.receiveFeatureReport()
. La promesse renvoyée se résout avec un objet DataView
contenant le contenu du rapport sur les éléments géographiques. Si l'appareil HID n'utilise pas d'ID de rapport, définissez reportId
sur 0.
// Request feature report.
const dataView = await device.receiveFeatureReport(/* reportId= */ 1);
// Read feature report contents with dataView.getInt8(), getUint8(), etc...
Écouter la connexion et la déconnexion
Lorsqu'un site Web a été autorisé à accéder à un appareil HID, il peut recevoir activement des événements de connexion et de déconnexion en écoutant les événements "connect"
et "disconnect"
.
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.
});
Révoquer l'accès à un appareil HID
Le site Web peut nettoyer les autorisations d'accès à un appareil HID qu'il ne souhaite plus conserver en appelant forget()
sur l'instance HIDDevice
. Par exemple, pour une application Web éducative utilisée sur un ordinateur partagé avec de nombreux appareils, un grand nombre d'autorisations générées par l'utilisateur accumulées crée une mauvaise expérience utilisateur.
Appeler forget()
sur une seule instance HIDDevice
révoque l'accès à toutes les interfaces HID du même appareil physique.
// Voluntarily revoke access to this HID device.
await device.forget();
Comme forget()
est disponible dans Chrome 100 ou version ultérieure, vérifiez si cette fonctionnalité est compatible avec les éléments suivants:
if ("hid" in navigator && "forget" in HIDDevice.prototype) {
// forget() is supported.
}
Conseils pour les développeurs
Le débogage des appareils HID dans Chrome est facile grâce à la page interne about://device-log
, où vous pouvez consulter tous les événements liés aux appareils HID et USB au même endroit.
Consultez l'explorateur HID pour extraire des informations sur les appareils HID dans un format lisible par l'humain. Il fait correspondre les valeurs d'utilisation aux noms pour chaque utilisation d'HID.
Sur la plupart des systèmes Linux, les appareils HID sont mappés avec des autorisations en lecture seule par défaut. Pour autoriser Chrome à ouvrir un appareil HID, vous devez ajouter une règle udev. Créez un fichier à l'emplacement /etc/udev/rules.d/50-yourdevicename.rules
avec le contenu suivant:
KERNEL=="hidraw*", ATTRS{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
Dans la ligne ci-dessus, [yourdevicevendor]
est 057e
si votre appareil est un Joy-Con Nintendo Switch, par exemple. Vous pouvez également ajouter ATTRS{idProduct}
pour une règle plus spécifique. Assurez-vous que votre user
est membre du groupe plugdev
. Ensuite, reconnectez votre appareil.
Prise en charge des navigateurs
L'API WebHID est disponible sur toutes les plates-formes pour ordinateur (ChromeOS, Linux, macOS et Windows) dans Chrome 89.
Démonstrations
Vous trouverez certaines démonstrations WebHID sur web.dev/hid-examples. Allez y jeter un œil !
Sécurité et confidentialité
Les auteurs de la spécification ont conçu et implémenté l'API WebHID en utilisant les principes fondamentaux définis dans Contrôler l'accès aux fonctionnalités puissantes de la plate-forme Web, y compris le contrôle utilisateur, la transparence et l'ergonomie. La possibilité d'utiliser cette API est principalement limitée par un modèle d'autorisation qui n'accorde l'accès qu'à un seul appareil HID à la fois. En réponse à une invite utilisateur, l'utilisateur doit prendre des mesures actives pour sélectionner un appareil HID particulier.
Pour comprendre les compromis de sécurité, consultez la section Considérations sur la sécurité et la confidentialité de la spécification WebHID.
De plus, Chrome inspecte l'utilisation de chaque collection de niveau supérieur. Si une collection de niveau supérieur a une utilisation protégée (par exemple, un clavier ou une souris génériques), un site Web ne pourra pas envoyer ni recevoir de rapports définis dans cette collection. La liste complète des utilisations protégées est publique.
Notez que les appareils HID sensibles à la sécurité (tels que les appareils HID FIDO utilisés pour une authentification plus forte) sont également bloqués dans Chrome. Consultez les fichiers Liste de blocage USB et Liste de blocage HID.
Commentaires
L'équipe Chrome aimerait connaître votre avis et votre expérience avec l'API WebHID.
Parlez-nous de la conception de l'API
L'API ne fonctionne-t-elle pas comme prévu ? Ou manque-t-il des méthodes ou des propriétés dont vous avez besoin pour implémenter votre idée ?
Signalez un problème de spécification dans le dépôt GitHub de l'API WebHID ou ajoutez vos commentaires à un problème existant.
Signaler un problème d'implémentation
Avez-vous trouvé un bug dans l'implémentation de Chrome ? Ou l'implémentation est-elle différente de la spécification ?
Consultez Signaler des bugs WebHID. Veillez à inclure autant de détails que possible, à fournir des instructions simples pour reproduire le bug et à définir Composants sur Blink>HID
. Glitch est idéal pour partager des reproductions rapides et faciles.
Montrer votre soutien
Comptez-vous utiliser l'API WebHID ? Votre soutien public aide l'équipe Chrome à hiérarchiser les fonctionnalités et montre aux autres fournisseurs de navigateurs à quel point il est essentiel de les prendre en charge.
Envoyez un tweet à @ChromiumDev en utilisant le hashtag #WebHID
et indiquez-nous où et comment vous l'utilisez.
Liens utiles
- Spécification
- Bug de suivi
- Enregistrement sur ChromeStatus.com
- Composant clignotement:
Blink>HID
Remerciements
Merci à Matt Reynolds et Joe Medley pour leurs commentaires sur cet article. Photo d'une Nintendo Switch rouge et bleue par Sara Kurfeß, et photo d'un ordinateur portable noir et argenté par Athul Cyriac Ajay sur Unsplash.