API WebHID позволяет веб-сайтам получать доступ к альтернативным вспомогательным клавиатурам и экзотическим геймпадам.
Существует множество устройств интерфейса пользователя (HID), таких как альтернативные клавиатуры или экзотические геймпады, которые слишком новы, слишком стары или слишком редки для доступа к ним со стороны системных драйверов устройств. API WebHID решает эту проблему, предоставляя способ реализации специфичной для устройств логики на JavaScript.
Предлагаемые варианты использования
HID-устройство принимает входные данные от человека или предоставляет выходные данные ему. Примерами таких устройств являются клавиатуры, указывающие устройства (мыши, сенсорные экраны и т. д.) и геймпады. Протокол HID позволяет получать доступ к этим устройствам на настольных компьютерах с помощью драйверов операционной системы. Веб-платформа поддерживает HID-устройства, используя эти драйверы.
Отсутствие доступа к редким HID-устройствам особенно остро ощущается, когда речь идёт об альтернативных вспомогательных клавиатурах (например, Elgato Stream Deck , гарнитурах Jabra , X-keys ) и поддержке экзотических геймпадов. Геймпады, разработанные для настольных компьютеров, часто используют HID для входов (кнопок, джойстиков, триггеров) и выходов (светодиодов, виброотдачи). К сожалению, входы и выходы геймпадов недостаточно стандартизированы, и веб-браузеры часто требуют специальной логики для конкретных устройств. Это неустойчиво и приводит к плохой поддержке множества старых и редких устройств. Это также заставляет браузер зависеть от особенностей поведения конкретных устройств.
Терминология
HID состоит из двух основных концепций: отчётов и дескрипторов отчётов. Отчёты — это данные, которыми обмениваются устройство и программный клиент. Дескриптор отчёта описывает формат и значение данных, поддерживаемых устройством.
HID (Human Interface Device) — это тип устройства, принимающего входные данные от человека или предоставляющего выходные данные ему. Также относится к протоколу HID, стандарту двунаправленной связи между хостом и устройством, разработанному для упрощения процедуры установки. Протокол HID изначально был разработан для USB-устройств, но с тех пор был реализован во многих других протоколах, включая Bluetooth.
Приложения и HID-устройства обмениваются двоичными данными посредством трех типов отчетов:
Тип отчета | Описание |
---|---|
Входной отчет | Данные, отправляемые с устройства в приложение (например, нажатие кнопки). |
Выходной отчет | Данные, отправляемые из приложения на устройство (например, запрос на включение подсветки клавиатуры). |
Отчет о функциях | Данные могут быть переданы в любом направлении. Формат зависит от устройства. |
Дескриптор отчёта описывает двоичный формат отчётов, поддерживаемый устройством. Его структура иерархична и позволяет группировать отчёты в отдельные коллекции внутри коллекции верхнего уровня. Формат дескриптора определяется спецификацией HID.
Использование HID — это числовое значение, относящееся к стандартизированному входу или выходу. Значения использования позволяют описать предполагаемое использование устройства и назначение каждого поля в его отчётах. Например, одно из полей определено для левой кнопки мыши. Использования также организованы в страницы использования, которые указывают на общую категорию устройства или отчёта.
Использование API WebHID
Обнаружение особенностей
Чтобы проверить, поддерживается ли API WebHID, используйте:
if ("hid" in navigator) {
// The WebHID API is supported.
}
Открыть HID-соединение
API WebHID изначально асинхронный, чтобы предотвратить блокировку пользовательского интерфейса веб-сайта в ожидании ввода. Это важно, поскольку данные HID могут быть получены в любой момент, что требует способа их прослушивания.
Чтобы открыть HID-соединение, сначала обратитесь к объекту HIDDevice
. Для этого можно либо предложить пользователю выбрать устройство, вызвав метод navigator.hid.requestDevice()
, либо выбрать устройство с помощью метода navigator.hid.getDevices()
, который возвращает список устройств, к которым веб-сайту ранее был предоставлен доступ.
Функция navigator.hid.requestDevice()
принимает обязательный объект, определяющий фильтры. Они используются для сопоставления любого устройства, подключенного по идентификатору поставщика USB ( vendorId
), идентификатору продукта USB ( productId
), значению страницы использования ( usagePage
) и значению использования ( usage
). Их можно получить из репозитория идентификаторов USB и таблиц использования HID (документ) .
Несколько объектов HIDDevice
, возвращаемых этой функцией, представляют несколько интерфейсов HID на одном физическом устройстве.
// 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();

Вы также можете использовать необязательный ключ exclusionFilters
в navigator.hid.requestDevice()
чтобы исключить из выбора браузера некоторые устройства, о которых известно, что они работают неисправно.
// 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 }],
});
Объект HIDDevice
содержит идентификаторы производителя и продукта USB-устройства для идентификации устройства. Его атрибут collections
инициализируется иерархическим описанием форматов отчётов устройства.
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
}
Устройства HIDDevice
по умолчанию возвращаются в «закрытом» состоянии и должны быть открыты путем вызова open()
прежде чем данные можно будет отправить или получить.
// Wait for the HID connection to open before sending/receiving data.
await device.open();
Получать отчеты о входных данных
После установления HID-соединения вы можете обрабатывать входящие отчёты о входных данных, прослушивая события "inputreport"
от устройства. Эти события содержат данные HID в виде объекта DataView
( data
), HID-устройство, к которому они относятся ( device
), и 8-битный идентификатор отчёта, связанный с отчётом о входных данных ( reportId
).

Продолжая предыдущий пример, код ниже показывает, как определить, какую кнопку нажал пользователь на устройстве Joy-Con Right, чтобы вы могли попробовать это дома.
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]}.`);
});
Посмотрите демо-ролик Pen webhid-joycon-button .
Отправлять выходные отчеты
Чтобы отправить отчёт о выходе на HID-устройство, передайте 8-битный идентификатор отчёта, связанный с отчётом о выходе ( reportId
), и байты в качестве BufferSource
( data
) в device.sendReport()
. Возвращённое обещание разрешается после отправки отчёта. Если HID-устройство не использует идентификаторы отчётов, установите reportId
равным 0.
Приведенный ниже пример относится к устройству Joy-Con и показывает, как заставить его вибрировать с помощью выходных отчетов.
// 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));
Посмотрите демо-версию Pen webhid-joycon-rumble .
Отправка и получение отчетов о функциях
Отчёты о функциях — единственный тип отчётов HID-данных, который может передаваться в обоих направлениях. Они позволяют HID-устройствам и приложениям обмениваться нестандартизированными HID-данными. В отличие от отчётов о входных и выходных данных, отчёты о функциях не принимаются и не отправляются приложением регулярно.

Чтобы отправить отчёт о функции на HID-устройство, передайте 8-битный идентификатор отчёта, связанный с отчётом о функции ( reportId
), и байты в качестве BufferSource
( data
) в device.sendFeatureReport()
. Возвращённое обещание разрешается после отправки отчёта. Если HID-устройство не использует идентификаторы отчётов, установите reportId
равным 0.
В примере ниже показано использование отчетов о функциях: как запросить устройство подсветки клавиатуры Apple, открыть его и заставить его мигать.
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);
}
Посмотрите демонстрацию Pen webhid-apple-keyboard-backlight .
Чтобы получить отчёт о функции от HID-устройства, передайте 8-битный идентификатор отчёта, связанный с этим отчётом ( reportId
), в device.receiveFeatureReport()
. Возвращённое обещание разрешается с объектом DataView
, содержащим содержимое отчёта о функции. Если HID-устройство не использует идентификаторы отчётов, установите reportId
равным 0.
// Request feature report.
const dataView = await device.receiveFeatureReport(/* reportId= */ 1);
// Read feature report contents with dataView.getInt8(), getUint8(), etc...
Прослушивание подключения и отключения
Когда веб-сайту предоставлено разрешение на доступ к HID-устройству, он может активно получать события подключения и отключения, прослушивая события "connect"
и "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.
});
Отозвать доступ к HID-устройству
Веб-сайт может очистить разрешения на доступ к HID-устройству, которое ему больше не нужно, вызвав метод forget()
для экземпляра HIDDevice
. Например, в образовательном веб-приложении, используемом на общем компьютере с множеством устройств, большое количество накопленных разрешений, сгенерированных пользователями, создаёт неудобства для пользователя.
Вызов forget()
для одного экземпляра HIDDevice
отменит доступ ко всем интерфейсам HID на одном физическом устройстве.
// Voluntarily revoke access to this HID device.
await device.forget();
Поскольку forget()
доступна в Chrome 100 и более поздних версиях, проверьте, поддерживается ли эта функция, с помощью следующего:
if ("hid" in navigator && "forget" in HIDDevice.prototype) {
// forget() is supported.
}
Советы разработчикам
Отладка HID в Chrome проста благодаря внутренней странице about://device-log
, где вы можете увидеть все события, связанные с устройствами HID и USB, в одном месте.

Воспользуйтесь HID Explorer для вывода информации об устройствах HID в удобном для восприятия формате. Он сопоставляет значения использования с названиями для каждого использования HID.
В большинстве систем Linux HID-устройства по умолчанию отображаются с правами только для чтения. Чтобы разрешить Chrome открывать HID-устройства, необходимо добавить новое правило udev . Создайте файл /etc/udev/rules.d/50-yourdevicename.rules
со следующим содержимым:
KERNEL=="hidraw*", ATTRS{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
В строке выше [yourdevicevendor]
— это 057e
если ваше устройство, например, Nintendo Switch Joy-Con. ATTRS{idProduct}
также можно добавить для более точного правила. Убедитесь, что ваш user
входит в группу plugdev
. Затем просто переподключите устройство.
Поддержка браузеров
API WebHID доступен на всех настольных платформах (ChromeOS, Linux, macOS и Windows) в Chrome 89.
Демо-версии
Некоторые демо-версии WebHID доступны на сайте web.dev/hid-examples . Заходите и посмотрите!
Безопасность и конфиденциальность
Авторы спецификации разработали и реализовали API WebHID, используя основные принципы, изложенные в документе «Управление доступом к мощным функциям веб-платформы» , включая пользовательский контроль, прозрачность и эргономичность. Возможность использования этого API в первую очередь ограничена моделью разрешений, которая предоставляет доступ только к одному HID-устройству одновременно. В ответ на запрос пользователя пользователь должен выполнить активные действия для выбора конкретного HID-устройства.
Чтобы понять компромиссы в области безопасности, ознакомьтесь с разделом « Вопросы безопасности и конфиденциальности» спецификации WebHID.
Кроме того, Chrome проверяет использование каждой коллекции верхнего уровня, и если в коллекции верхнего уровня есть защищённое использование (например, стандартная клавиатура, мышь), то веб-сайт не сможет отправлять и получать какие-либо отчёты, определённые в этой коллекции. Полный список защищённых использований доступен в открытом доступе .
Обратите внимание, что в Chrome также блокируются устройства HID, требующие повышенного уровня безопасности (например, устройства FIDO HID, используемые для более надёжной аутентификации). См. файлы чёрного списка USB и чёрного списка HID .
Обратная связь
Команда Chrome будет рада услышать ваши мысли и опыт использования API WebHID.
Расскажите нам о дизайне API
Есть ли что-то в API, что работает не так, как ожидалось? Или отсутствуют методы или свойства, необходимые для реализации вашей идеи?
Отправьте сообщение о проблеме со спецификацией в репозиторий WebHID API GitHub или добавьте свои мысли к существующей проблеме.
Сообщить о проблеме с реализацией
Вы обнаружили ошибку в реализации Chrome? Или реализация отличается от спецификации?
Ознакомьтесь со статьёй «Как сообщать об ошибках WebHID» . Опишите ошибку как можно подробнее, предоставьте простые инструкции по её воспроизведению и установите для компонентов значение Blink>HID
.
Показать поддержку
Планируете ли вы использовать API WebHID? Ваша публичная поддержка помогает команде Chrome расставлять приоритеты в отношении функций и показывает другим разработчикам браузеров, насколько важна их поддержка.
Отправьте твит @ChromiumDev , используя хэштег #WebHID
и расскажите, где и как вы его используете.
Полезные ссылки
- Спецификация
- Ошибка отслеживания
- Запись ChromeStatus.com
- Компонент Blink:
Blink>HID
Благодарности
Благодарим Мэтта Рейнольдса и Джо Медли за рецензии на эту статью. Фотография красно-синего Nintendo Switch сделана Сарой Курфесс , а фотография чёрно-серебристого ноутбука — Атулом Сириаком Аджаем на Unsplash.