Foto de Elgato Stream Deck.

Conexión a dispositivos HID poco comunes

La API WebHID permite que los sitios web accedan a teclados auxiliares alternativos y controles de juego exóticos.

Published on Updated on

Translated to: English, Português, 한국어

Éxito

La API WebHID, parte del proyecto de capacidades, se lanzó en Chrome 89.

Existe una larga lista de dispositivos de interfaz humana (HID), como teclados alternativos o controles de juego exóticos, que son demasiado nuevos, demasiado antiguos o poco comunes para que los controladores de dispositivos de los sistemas puedan acceder a ellos. La API WebHID resuelve esto dando una forma de implementar la lógica específica del dispositivo en JavaScript.

Casos de uso sugeridos

Un dispositivo HID toma la entrada o les da una salida a los seres humanos. Ejemplos de dispositivos pueden ser teclados, dispositivos señaladores (mouse, pantallas táctiles, etc.) y controles de juego. El protocolo HID hace posible acceder a estos dispositivos en computadoras de escritorio utilizando controladores del sistema operativo. La plataforma web admite dispositivos HID basándose en estos controladores.

La imposibilidad de acceder a dispositivos HID poco comunes es particularmente dolorosa cuando se trata de teclados auxiliares alternativos (por ejemplo, Elgato Stream Deck, auriculares Jabra, teclas X) y compatibilidad con controles de juego exóticos. Los controles de juego diseñados para computadoras de escritorio a menudo usan HID para las entradas del control (botones, palancas, disparadores) y salidas (LED, vibración). Desafortunadamente, las entradas y salidas del control no están bien estandarizadas y los navegadores web a menudo requieren una lógica personalizada para dispositivos específicos. Esto es insostenible y da como resultado un soporte deficiente para la larga fila de dispositivos más antiguos y poco comunes. También hace que el navegador dependa de peculiaridades en el comportamiento de dispositivos específicos.

Terminología

HID consta de dos conceptos fundamentales: informes y descriptores de informes. Los informes son los datos que se intercambian entre un dispositivo y un cliente de software. El descriptor de informe describe el formato y el significado de los datos que admite el dispositivo.

Un HID (Dispositivo de interfaz humana) es un tipo de dispositivo que recibe entradas de personas o les proporciona salidas. También se refiere al protocolo HID, un estándar para la comunicación bidireccional entre un host y un dispositivo que está diseñado para simplificar el procedimiento de instalación. El protocolo HID se desarrolló originalmente para dispositivos USB, pero desde entonces se ha implementado en muchos otros protocolos, incluido Bluetooth.

Las aplicaciones y los dispositivos HID intercambian datos binarios a través de tres tipos de informes:

Tipo de informeDescripción
Informe de entradaDatos que se envían desde el dispositivo a la aplicación (por ejemplo, se presiona un botón).
Informe de salidaDatos que se envían desde la aplicación al dispositivo (por ejemplo, una solicitud para encender la luz de fondo del teclado).
Informe de funcionesDatos que pueden enviarse en cualquier dirección. El formato es específico del dispositivo.

Un descriptor de informe describe el formato binario de los informes admitidos por el dispositivo. Su estructura es jerárquica y puede agrupar informes como colecciones distintas dentro de la colección de nivel superior. El formato del descriptor está definido por la especificación HID.

Un uso de HID es un valor numérico que se refiere a una entrada o salida estandarizada. Los valores de uso permiten que un dispositivo describa el uso previsto del dispositivo y el propósito de cada campo en sus informes. Por ejemplo, se define uno para el botón izquierdo de un mouse. Los usos también se organizan en páginas de uso, que proporcionan una indicación de la categoría de alto nivel del dispositivo o informe.

Uso de la API de WebHID

Detección de características

Para comprobar si la API WebHID es compatible, utilice:

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

Abra una conexión HID

La API WebHID es asincrónica por diseño para evitar que la interfaz de usuario del sitio web se bloquee cuando se espera una entrada. Esto es importante porque los datos HID se pueden recibir en cualquier momento, lo que requiere una forma de escucharlos.

Para abrir una conexión HID, primero acceda a un objeto HIDDevice. Para ello, puede pedirle al usuario que seleccione un dispositivo llamando a navigator.hid.requestDevice(), o elegir uno de navigator.hid.getDevices() que devuelve una lista de dispositivos a los que el sitio web ha tenido acceso previamente.

La función navigator.hid.requestDevice() toma un objeto obligatorio que define filtros. Se utilizan para emparejar cualquier dispositivo conectado con un identificador de proveedor USB (vendorId), un identificador de producto USB (productId), un valor de página de uso (usagePage) y un valor de uso usage. Puede obtenerlos del repositorio de ID de USB y del documento de tablas de uso de HID.

Los múltiples objetos HIDDevice devueltos por esta función representan múltiples interfaces HID en el mismo dispositivo físico.

// 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();
Captura de pantalla de un mensaje de dispositivo HID en un sitio web.
Mensaje de usuario para seleccionar un Joy-Con de Nintendo Switch.

Un objeto HIDDevice contiene identificadores de producto y proveedor USB para la identificación del dispositivo. Su atributo collections se inicializa con una descripción jerárquica de los formatos de informe del dispositivo.

for (let collection of device.collections) {
// A 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
}

Los dispositivos HIDDevice se devuelven por default en un estado "cerrado" y deben abrirse llamando a open() antes de que se puedan enviar o recibir datos.

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

Reciba informes de entrada

Una vez que se ha establecido la conexión HID, puede manejar los informes de entrada entrantes escuchando los "inputreport" del dispositivo. Esos eventos contienen los datos HID como un objeto DataView (data), el dispositivo HID al que pertenece (device) y el ID de informe de 8 bits asociado con el informe de entrada (reportId).

Foto de Nintendo switch rojo y azul.
Dispositivos Nintendo Switch Joy-Con.

Continuando con el ejemplo anterior, el código a continuación le muestra cómo detectar qué botón ha presionado el usuario en un dispositivo Joy-Con Right para que, con suerte, pueda probarlo en 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]}.`);
});

Envíe informes de salida

Para enviar un informe de salida a un dispositivo HID, pase el ID de informe de 8 bits asociado con el informe de salida (reportId) y bytes como un BufferSource (data) a device.sendReport(). La promesa devuelta se resuelve una vez que se ha enviado el informe. Si el dispositivo HID no utiliza IDs de informe, ponga reportId a 0.

El siguiente ejemplo aplica a un dispositivo Joy-Con y le muestra cómo hacerlo vibrar con los informes de salida.

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

Envíe y reciba informes de características

Los informes de características son el único tipo de informes de datos HID que pueden viajar en ambas direcciones. Permiten que los dispositivos y aplicaciones HID intercambien datos HID no estandarizados. A diferencia de los informes de entrada y salida, la aplicación no recibe ni envía informes de características de forma regular.

Foto de computadora portátil negra y plateada.
Teclado de computadora portátil

Para enviar un informe de características a un dispositivo HID, pase el ID de informe de 8 bits asociado con el informe de características (reportId) y bytes como un BufferSource (data) a device.sendFeatureReport(). La promesa devuelta se resuelve una vez que se ha enviado el informe. Si el dispositivo HID no utiliza IDs de informe, ponga reportId a 0.

El siguiente ejemplo ilustra el uso de informes de características mostrándole cómo enviar solicitud a un dispositivo de retroiluminación de teclado de Apple, abrirlo y hacer que parpadee.

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

Para recibir un informe de características de un dispositivo HID, pase el ID de informe de 8 bits asociado con el informe de características (reportId) a device.receiveFeatureReport(). La promesa devuelta se resuelve con un objeto DataView con el contenido del informe de características. Si el dispositivo HID no utiliza IDs de informe, ponga reportId a 0.

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

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

Escuche la conexión y la desconexión

Cuando el sitio web tiene permiso para acceder a un dispositivo HID, puede recibir activamente eventos de conexión y desconexión escuchando eventos "connect" y "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.
});

Consejos para desarrolladores

La depuración de HID en Chrome es fácil con la página interna, about://device-log, donde puede ver todos los eventos relacionados con dispositivos HID y USB en un solo lugar.

Captura de pantalla de la página interna para depurar HID.
Página interna en Chrome para depurar HID.

Compatibilidad con navegadores

La API WebHID está disponible en todas las plataformas de escritorio (ChromeOS, Linux, macOS y Windows) en Chrome 89.

Demostraciones

Algunas demostraciones de WebHID se enumeran en web.dev/hid-examples. ¡Deles un vistazo!

Seguridad y privacidad

Los autores de especificaciones han diseñado e implementado la API WebHID utilizando los principios básicos definidos en Control del acceso a las funciones de la plataforma web de gran alcance, incluido el control del usuario, la transparencia y la ergonomía. La capacidad de usar esta API está controlada principalmente por un modelo de permisos que otorga acceso a un solo dispositivo HID a la vez. En respuesta a un mensaje de usuario, el usuario debe tomar medidas activas para seleccionar un dispositivo HID en particular.

Para comprender las compensaciones de seguridad, consulte la sección Consideraciones de seguridad y privacidad de la especificación de WebHID.

Además de esto, Chrome inspecciona el uso de cada colección de nivel superior y si una colección de nivel superior tiene un uso protegido (por ejemplo, teclado genérico, mouse), entonces un sitio web no podrá enviar ni recibir ningún informe definido en esa colección. La lista completa de usos protegidos está disponible públicamente.

Tenga en cuenta que los dispositivos HID sensibles a la seguridad (como los dispositivos FIDO HID utilizados para una autenticación más sólida) también están bloqueados en Chrome. Consulte los archivos lista de bloqueo USB y lista de bloqueo HID.

Retroalimentación

Al equipo de Chrome le encantaría conocer sus pensamientos y experiencias con la API WebHID.

Cuéntenos sobre el diseño de la API

¿Hay algo en la API que no funcione como se esperaba? ¿O faltan métodos o propiedades que necesita para implementar su idea?

Reporte un problema de especificaciones en el repositorio GitHub de la API WebHID o agregue sus comentarios a un reporte existente.

Reporte problemas con la implementación

¿Encontró un error con la implementación en Chrome? ¿O la implementación es diferente de la especificación?

Reporte un error en https://new.crbug.com. Asegúrese de incluir todos los detalles que pueda, dé instrucciones sencillas para reproducir el error y configure los Componentes como Blink>HID. Glitch funciona muy bien para compartir reproducciones rápidas y fáciles.

Muestre apoyo

¿Está pensando en utilizar la API WebHID? Su soporte público ayuda al equipo de Chrome a priorizar las funciones y muestra a otros proveedores de navegadores lo importante que es brindarles soporte.

Envíe un tweet a @ChromiumDev usando el hashtag #WebHID y háganos saber dónde y cómo lo está usando.

Enlaces útiles

Agradecimientos

Gracias a Matt Reynolds y Joe Medley por sus reseñas de este artículo. Foto de Nintendo Switch roja y azul de Sara Kurfeß, y foto de computadora portátil negra y plateada de Athul Cyriac Ajay en Unsplash.

Updated on Improve article

We serve cookies on this site to analyze traffic, remember your preferences, and optimize your experience.