
Использования WebHID API на JavaScript

Использования WebHID API на JavaScript
Когда я готовил статью про FiiO JA11, мне стало интересно, как веб-сайты могут управлять локальными устройствами через браузер, в частности, речь идет об аудиоусилителе Fransun и эквалайзере FiiO. Оказалось, что для этого существуют вполне документированные возможности. WebHID (Human Interface Device) - это часть Web API, позволяющая веб-приложениям напрямую взаимодействовать с HID-устройствами через браузер. Это дает возможность создавать браузерные интерфейсы управления без установки драйверов или дополнительного программного обеспечения.
Технология WebHID особенно полезна для устройств, которые работают по принципу plug-and-play, хранят настройки непосредственно на борту и управляются через удобный веб-интерфейс, например, в Chrome или Edge. Однако не все браузеры поддерживают WebHID. На момент 2026 года этот API доступен только в браузерах на движке Chromium: Google Chrome начиная с версии 89 и Microsoft Edge 89+. Браузеры Firefox, Safari и другие, основанные не на Chromium, WebHID не поддерживают.
Прежде чем использовать WebHID в своем коде, надо убедиться, что браузер пользователя его поддерживает. В JavaScript это делается одной простой проверкой:
Code (JavaScript) : Убрать нумерацию
- // Проверка поддержки WebHID
- if ('hid' in navigator) {
- // Можно работать с API WebHID
- }
- else {
- alert('WebHID в этом браузере не поддерживается');
- }
Теперь немного теории. Безопасность при работе с WebHID обеспечивается на нескольких уровнях. Пользователь всегда видит диалог выбора устройства - браузер никогда не подключается к HID-устройству без его явного согласия. Даже если устройство было однажды разрешено, оно не остается доступным постоянно: при перезагрузке страницы или повторном заходе на сайт потребуется новое подтверждение. Кроме того, API работает только в защищенном контексте, то есть по HTTPS или на http://localhost. Это исключает возможность перехвата данных на уровне сети. HTML-файл с интерфейсом можно хранить локально и запускать напрямую по адресу file:// - никакой веб-сервер или облачное размещение не требуются. Это особенно удобно в условиях строгой изоляции систем, где важны предсказуемость, безопасность и минимум зависимостей. Запрос на доступ к устройствам возможен только в ответ на прямое действие пользователя, например клик или касание; автоматический вызов в фоне технически невозможен. Разрешение выдается строго на конкретное устройство: даже если подключено несколько одинаковых девайсов, браузер предложит выбрать нужное из списка. И наконец, когда вкладка становится неактивной, обработка входящих HID-отчетов может приостанавливаться или замедляться, что дополнительно снижает риски скрытого сбора данных в фоне.

Запрос устройств
Чтобы взаимодействовать с HID-устройством через браузер, веб-приложение должно сначала запросить у пользователя разрешение на доступ. Это делается с помощью метода navigator.hid.requestDevice(). При вызове этого метода браузер немедленно приостанавливает выполнение скрипта и показывает системное окно, в котором отображаются все подключенные HID-устройства, соответствующие заданным критериям. Эти критерии, так называемые фильтры, позволяют сузить список до нужных типов устройств. Например, можно указать vendor ID и product ID конкретного девайса или использовать более общие параметры, такие как usage page и usage, определенные в спецификации HID. Если фильтры не указаны, браузер покажет все доступные HID-устройства, которые не считаются системными (например, стандартные клавиатуры и мыши обычно скрыты). После того как пользователь подтвердил свой выбор в системном диалоге, браузер возвращает массив устройств, каждое из которых было явно одобрено клиентом. Даже если в списке было несколько вариантов, в код попадают только те, что пользователь отметил галочкой или выделил. В простейшем случае берется первое из них, ведь именно его выбрал человек, и именно с ним он ожидает взаимодействия.
В обычном JavaScript конструкцию await нельзя использовать на верхнем уровне, только внутри функций, помеченных как async. Поэтому код, работающий с WebHID, нужно оборачивать в такую функцию. Кроме того, вызывать ее следует только в ответ на действие пользователя, например, по клику кнопки. Это требование безопасности: браузер не разрешает запрашивать доступ к устройствам автоматически, без явного согласия. Как это выглядит в коде:
Code (JavaScript) : Убрать нумерацию
- <button id="connectBtn">Подключить HID-устройство</button>
- <script>
- async function connectToDevice() {
- try {
- // Запрос доступа к HID-устройствам
- const devices = await navigator.hid.requestDevice({
- // Пустой фильтр, показать все совместимые устройства
- filters: []
- });
- // Проверка, было ли выбрано устройство
- if (!devices.length) {
- console.log('Устройство не выбрано.');
- return;
- }
- // Берем первое из устройств, которые клиент
- // явно выбрал в диалоговом окне
- const device = devices[0];
- // Теперь можно открыть соединение и работать с ним
- await device.open();
- console.log('Устройство подключено:', device.productName);
- }
- catch (error) {
- console.error('Ошибка:', error);
- }
- }
- // Вызвать функцию по клику
- document.getElementById('connectBtn').addEventListener(
- 'click',
- connectToDevice
- );
- </script>
Code (JavaScript) : Убрать нумерацию
- // Название устройства
- const name = device.productName || 'Unknown';
- // Идентификатор производителя
- const vid = device.vendorId.toString(16).padStart(4, '0');
- // Идентификатор модели
- const pid = device.productId.toString(16).padStart(4, '0');
После подключения к HID-устройству веб-приложение может получать данные от него в реальном времени. Для этого используется событие inputreport, которое срабатывает каждый раз, когда устройство отправляет отчет хосту (в данном случае - браузеру). Каждый такой отчет содержит: reportId - идентификатор типа отчета (может быть 0, если не используется), data - двоичные данные в виде объекта DataView, device - ссылка на само устройство (полезно, если подключено несколько девайсов). Данные приходят в "сыром" виде, поэтому их нужно интерпретировать в соответствии с HID-дескриптором устройства: например, первый байт может означать состояние кнопок, следующие - положение джойстика и т.д.
Code (JavaScript) : Убрать нумерацию
- device.addEventListener('inputreport', (event) => {
- const { reportId, data } = event;
- // Чтение первого байта отчёта
- const firstByte = data.getUint8(0);
- // Пропускаем пустые или нулевые отчеты
- if (firstByte === 0) return;
- // Пример: простая декодировка битовой маски кнопок
- const buttonMap = {
- 1: 'Кнопка 1',
- 2: 'Кнопка 2',
- 4: 'Кнопка 3',
- 8: 'Кнопка 4'
- };
- // Проверяем, какая кнопка нажата
- for (const [mask, label] of Object.entries(buttonMap)) {
- if ((firstByte & mask) !== 0) {
- console.log('Нажата: ' + label + ' (отчет ID: ' + reportId + ')');
- }
- }
- });
Важно! Формат данных полностью зависит от прошивки и HID-дескриптора вашего устройства. Этот пример демонстрирует лишь общий подход, реальная логика декодирования.
Хотя WebHID автоматически разрывает соединение при закрытии вкладки или перезагрузке страницы, хорошей практикой считается явно закрывать соединение с устройством, когда оно больше не нужно, например, по нажатию кнопки "Отключить" или при переходе на другую страницу. Это освобождает системные ресурсы и гарантирует корректное завершение работы. Для этого используется метод device.close(). После его вызова устройство становится недоступным до следующего подключения, а все подписки на события (например, inputreport) перестают срабатывать. Пример отключения:
Code (JavaScript) : Убрать нумерацию
- async function disconnectDevice(device) {
- if (device && device.opened) {
- await device.close();
- console.log('Устройство отключено.');
- }
- }
Оказалось, что ничего сложного в WebHID API нет, главное здесь само приложение.
Просмотров: 277 | Комментариев: 2
Метки: JavaScript
Комментарии
Отзывы посетителей сайта о статье
Дима
(28.02.2026 в 12:03):
Вот я тормоз :) Надо было выбрать на всплывающем окне на устройство, а я думал оно само определит *рукалицо*. Работает и на "опере" тоже.
Дима
(28.02.2026 в 11:31):
Добрый день! А у меня че-то не работает этот "веб-хид", ни на "опере", ни на "эдже". Крутится "лоадинг" и всё. Недавно купил на али свисток Fransun KT02H20, вычитал в отзывах что он перешивается в JadeAudio, ну и прошил. Так вот, всё прошло нормально, свисток работает нормально, приложение для андроида работает, а на сайте нет.
Добавить комментарий
Заполните форму для добавления комментария


