Blog. Just Blog

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

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Web-мастеру и не только | Автор: ManHunter
Использования 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 это делается одной простой проверкой:
  1. // Проверка поддержки WebHID
  2. if ('hid' in navigator) {
  3.     // Можно работать с API WebHID
  4. }
  5. else {
  6.     alert('WebHID в этом браузере не поддерживается');
  7. }
Если проверка прошла успешно, то теперь можно вызывать доступные методы, слушать события и даже отправлять команды на устройство.

Теперь немного теории. Безопасность при работе с 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, нужно оборачивать в такую функцию. Кроме того, вызывать ее следует только в ответ на действие пользователя, например, по клику кнопки. Это требование безопасности: браузер не разрешает запрашивать доступ к устройствам автоматически, без явного согласия. Как это выглядит в коде:
  1. <button id="connectBtn">Подключить HID-устройство</button>
  2.  
  3. <script>
  4. async function connectToDevice() {
  5.     try {
  6.         // Запрос доступа к HID-устройствам
  7.         const devices await navigator.hid.requestDevice({
  8.             // Пустой фильтр, показать все совместимые устройства
  9.             filters: []
  10.         });
  11.  
  12.         // Проверка, было ли выбрано устройство
  13.         if (!devices.length) {
  14.             console.log('Устройство не выбрано.');
  15.             return;
  16.         }
  17.  
  18.         // Берем первое из устройств, которые клиент
  19.         // явно выбрал в диалоговом окне
  20.         const device devices[0];
  21.  
  22.         // Теперь можно открыть соединение и работать с ним
  23.         await device.open();
  24.         console.log('Устройство подключено:'device.productName);
  25.     }
  26.     catch (error) {
  27.         console.error('Ошибка:'error);
  28.     }
  29. }
  30.  
  31. // Вызвать функцию по клику
  32. document.getElementById('connectBtn').addEventListener(
  33.     'click',
  34.     connectToDevice
  35. );
  36. </script>
После того как пользователь выбрал HID-устройство и соединение установлено, веб-приложение получает доступ к его метаданным. Эти данные позволяют идентифицировать устройство, отображать понятное имя и, при необходимости, адаптировать логику взаимодействия под конкретную модель. Каждый объект устройства содержит такие свойства, как: productName - человекочитаемое название (например, "SVEN WIRELESS MOUSE" или "JadeAuto JA11"), vendorId - идентификатор производителя (VID), productId - идентификатор модели (PID). Если название не задано в дескрипторе устройства, браузер может вернуть пустую строку, поэтому на практике стоит предусмотреть резервное значение. VID и PID всегда представлены в виде чисел, но для удобства их обычно выводят в шестнадцатеричном формате, именно так они указываются в документации и прошивках. Пример получения и отображения информации об устройстве:
  1. // Название устройства
  2. const name device.productName || 'Unknown';
  3. // Идентификатор производителя
  4. const vid device.vendorId.toString(16).padStart(4'0');
  5. // Идентификатор модели
  6. const pid device.productId.toString(16).padStart(4'0');
Эта информация полезна не только для отладки, но и для построения адаптивных интерфейсов, например, загрузки нужного профиля конфигурации или отображения предупреждения о несовместимости.

После подключения к HID-устройству веб-приложение может получать данные от него в реальном времени. Для этого используется событие inputreport, которое срабатывает каждый раз, когда устройство отправляет отчет хосту (в данном случае - браузеру). Каждый такой отчет содержит: reportId - идентификатор типа отчета (может быть 0, если не используется), data - двоичные данные в виде объекта DataView, device - ссылка на само устройство (полезно, если подключено несколько девайсов). Данные приходят в "сыром" виде, поэтому их нужно интерпретировать в соответствии с HID-дескриптором устройства: например, первый байт может означать состояние кнопок, следующие - положение джойстика и т.д.
  1. device.addEventListener('inputreport', (event) => {
  2.     const { reportIddata } = event;
  3.  
  4.     // Чтение первого байта отчёта
  5.     const firstByte data.getUint8(0);
  6.  
  7.     // Пропускаем пустые или нулевые отчеты
  8.     if (firstByte === 0) return;
  9.  
  10.     // Пример: простая декодировка битовой маски кнопок
  11.     const buttonMap = {
  12.         1'Кнопка 1',
  13.         2'Кнопка 2',
  14.         4'Кнопка 3',
  15.         8'Кнопка 4'
  16.     };
  17.  
  18.     // Проверяем, какая кнопка нажата
  19.     for (const [masklabelof Object.entries(buttonMap)) {
  20.         if ((firstByte mask) !== 0) {
  21.             console.log('Нажата: ' label ' (отчет ID: ' reportId ')');
  22.         }
  23.     }
  24. });
Таким образом, именно через inputreport веб-интерфейс "узнает", что пользователь сделал с устройством: нажал кнопку, повернул ручку или переключил режим, может мгновенно отреагировать, обновить UI, отправить команду в другое приложение или записать действие в лог.

Важно! Формат данных полностью зависит от прошивки и HID-дескриптора вашего устройства. Этот пример демонстрирует лишь общий подход, реальная логика декодирования.

Хотя WebHID автоматически разрывает соединение при закрытии вкладки или перезагрузке страницы, хорошей практикой считается явно закрывать соединение с устройством, когда оно больше не нужно, например, по нажатию кнопки "Отключить" или при переходе на другую страницу. Это освобождает системные ресурсы и гарантирует корректное завершение работы. Для этого используется метод device.close(). После его вызова устройство становится недоступным до следующего подключения, а все подписки на события (например, inputreport) перестают срабатывать. Пример отключения:
  1. async function disconnectDevice(device) {
  2.     if (device && device.opened) {
  3.         await device.close();
  4.         console.log('Устройство отключено.');
  5.     }
  6. }
Если вы сохраняете ссылку на устройство, не забудьте обнулить ее после отключения, чтобы избежать попыток работы с уже закрытым соединением. Такой подход делает взаимодействие с HID-устройствами предсказуемым, устойчивым к ошибкам и удобным для пользователя, особенно в интерфейсах, где возможны частые подключения и отключения.

Оказалось, что ничего сложного в WebHID API нет, главное здесь само приложение.

Поделиться ссылкой ВКонтакте
Просмотров: 277 | Комментариев: 2

Метки: JavaScript

Комментарии

Отзывы посетителей сайта о статье
Дима (28.02.2026 в 12:03):
Вот я тормоз :) Надо было выбрать на всплывающем окне на устройство, а я думал оно само определит *рукалицо*. Работает и на "опере" тоже.
Дима (28.02.2026 в 11:31):
Добрый день! А у меня че-то не работает этот "веб-хид", ни на "опере", ни на "эдже". Крутится "лоадинг" и всё. Недавно купил на али свисток Fransun KT02H20, вычитал в отзывах что он перешивается в JadeAudio, ну и прошил. Так вот, всё прошло нормально, свисток работает нормально, приложение для андроида работает, а на сайте нет.

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2026
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.08 сек. / MySQL: 2 (0.0027 сек.) / Память: 4.5 Mb
Наверх