WebHID API memungkinkan situs mengakses keyboard tambahan alternatif dan gamepad eksotis.
Dipublikasikan: 15 September 2020
Ada banyak perangkat antarmuka manusia (HID), seperti keyboard alternatif atau gamepad eksotis, yang terlalu baru, terlalu lama, atau terlalu tidak umum untuk dapat diakses oleh driver perangkat sistem. WebHID API memecahkan masalah ini dengan menyediakan cara untuk menerapkan logika khusus perangkat di JavaScript.
Kasus penggunaan yang disarankan
Perangkat HID menerima input dari atau memberikan output kepada manusia. Contoh perangkat mencakup keyboard, perangkat penunjuk (mouse, layar sentuh, dll.), dan gamepad. Protokol HID memungkinkan akses ke perangkat ini di komputer desktop menggunakan driver sistem operasi. Platform web mendukung perangkat HID dengan mengandalkan driver ini.
Ketidakmampuan untuk mengakses perangkat HID yang tidak umum sangat menyulitkan jika menyangkut keyboard tambahan alternatif (seperti Elgato Stream Deck, headset Jabra, X-keys) dan dukungan gamepad eksotis. Gamepad yang didesain untuk desktop sering kali menggunakan HID untuk input gamepad (tombol, joystick, pemicu) dan output (LED, getaran).
Sayangnya, input dan output gamepad tidak distandardisasi dengan baik dan browser web sering kali memerlukan logika kustom untuk perangkat tertentu. Hal ini tidak berkelanjutan dan menghasilkan dukungan yang buruk untuk perangkat lama dan tidak umum. Hal ini juga menyebabkan browser bergantung pada keunikan dalam perilaku perangkat tertentu.
Terminologi
Perangkat antarmuka manusia (HID) dapat menerima input atau menawarkan output kepada manusia. Ada protokol HID, yaitu standar untuk komunikasi dua arah antara host dan perangkat yang dirancang untuk menyederhanakan prosedur penginstalan.
HID terdiri dari dua konsep mendasar: laporan dan deskriptor laporan. Laporan adalah data yang dipertukarkan antara perangkat dan klien software. Deskriptor laporan menjelaskan format dan arti data yang didukung perangkat.
Aplikasi dan perangkat HID bertukar data biner melalui tiga jenis laporan:
| Jenis laporan | Deskripsi |
|---|---|
| Laporan input | Data yang dikirim dari perangkat ke aplikasi (misalnya, tombol ditekan). |
| Laporan output | Data yang dikirim dari aplikasi ke perangkat (misalnya, permintaan untuk mengaktifkan lampu latar keyboard). |
| Laporan fitur | Data yang dapat dikirim ke kedua arah. Formatnya spesifik per perangkat. |
Deskripsi laporan menjelaskan format biner laporan yang didukung oleh perangkat. Strukturnya hierarkis dan dapat mengelompokkan laporan bersama sebagai kumpulan yang berbeda dalam kumpulan tingkat teratas. format deskriptor ditentukan oleh spesifikasi HID.
Penggunaan HID adalah nilai numerik yang merujuk pada input atau output standar. Nilai penggunaan memungkinkan perangkat mendeskripsikan penggunaan yang dimaksudkan dari perangkat dan tujuan setiap kolom dalam laporannya. Misalnya, satu tombol ditentukan untuk tombol kiri mouse. Penggunaan juga diatur ke dalam halaman penggunaan, yang memberikan indikasi kategori tingkat tinggi perangkat atau laporan.
Menggunakan WebHID API
Untuk memeriksa apakah WebHID API didukung, gunakan:
if ("hid" in navigator) {
// The WebHID API is supported.
}
Membuka koneksi HID
WebHID API dirancang secara asinkron untuk mencegah UI situs diblokir saat menunggu input. Hal ini penting karena data HID dapat diterima kapan saja, sehingga memerlukan cara untuk memantaunya.
Untuk membuka koneksi HID, akses objek HIDDevice terlebih dahulu. Untuk melakukannya, Anda dapat
mengarahkan pengguna untuk memilih perangkat dengan memanggil
navigator.hid.requestDevice(), atau memilih salah satu dari navigator.hid.getDevices()
yang menampilkan daftar perangkat yang telah diberi akses oleh situs sebelumnya.
Fungsi navigator.hid.requestDevice() mengambil objek wajib yang
menentukan filter. Nilai tersebut digunakan untuk mencocokkan perangkat yang terhubung dengan ID vendor USB (vendorId), ID produk USB (productId), nilai halaman penggunaan (usagePage), dan nilai penggunaan (usage). Anda bisa mendapatkan nilai tersebut dari Repositori ID USB dan dokumen tabel penggunaan HID.
Beberapa objek HIDDevice yang ditampilkan oleh fungsi ini merepresentasikan beberapa
antarmuka HID pada perangkat fisik yang sama.
// 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();
Anda juga dapat menggunakan tombol exclusionFilters opsional di
navigator.hid.requestDevice() untuk mengecualikan beberapa perangkat dari pemilih browser
yang diketahui tidak berfungsi.
// 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 }],
});
Objek HIDDevice berisi ID produk dan vendor USB untuk identifikasi perangkat. Atribut collections diinisialisasi dengan deskripsi hierarkis
format laporan perangkat.
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
}
Perangkat HIDDevice secara default ditampilkan dalam status "tertutup" dan harus
dibuka dengan memanggil open() sebelum data dapat dikirim atau diterima.
// Wait for the HID connection to open before sending/receiving data.
await device.open();
Menerima laporan input

Setelah koneksi HID dibuat, Anda dapat menangani laporan input masuk dengan memproses peristiwa "inputreport" dari perangkat. Peristiwa tersebut
berisi data HID sebagai objek DataView (data), perangkat HID yang menjadi
miliknya (device), dan ID laporan 8-bit yang terkait dengan laporan input
(reportId).
Melanjutkan contoh sebelumnya, kode ini membantu Anda mendeteksi tombol mana yang telah ditekan pengguna pada perangkat Joy-Con Kanan sehingga Anda dapat mencobanya di rumah.
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]}.`);
});
Lihat demo di CodePen.
Mengirim laporan output
Untuk mengirim laporan output ke perangkat HID, teruskan ID laporan 8-bit yang terkait dengan laporan output (reportId) dan byte sebagai BufferSource (data) ke
device.sendReport(). Promise yang ditampilkan akan di-resolve setelah laporan dikirim. Jika perangkat HID tidak menggunakan ID laporan, setel reportId ke 0.
Contoh berikutnya berlaku untuk perangkat Joy-Con dan menunjukkan cara membuat perangkat bergetar dengan laporan output.
// 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.
const rumbleData = [ /* ... */ ];
await device.sendReport(0x10, new Uint8Array(rumbleData));
Lihat demo di CodePen.
Mengirim dan menerima laporan fitur

Laporan fitur adalah satu-satunya jenis laporan data HID yang dapat bergerak ke dua arah. Fitur ini memungkinkan perangkat dan aplikasi HID bertukar data HID yang tidak standar. Tidak seperti laporan input dan output, laporan fitur tidak diterima atau dikirim oleh aplikasi secara rutin.
Untuk mengirim laporan fitur ke perangkat HID, teruskan ID laporan 8-bit yang terkait dengan laporan fitur (reportId) dan byte sebagai BufferSource (data) ke
device.sendFeatureReport(). Promise yang ditampilkan akan di-resolve setelah laporan dikirim. Jika perangkat HID tidak menggunakan ID laporan, setel reportId ke 0.
Contoh ini mengilustrasikan penggunaan laporan fitur dengan menunjukkan cara meminta perangkat lampu latar keyboard Apple, membukanya, dan membuatnya berkedip.
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);
}
Lihat demo di CodePen.
Untuk menerima laporan fitur dari perangkat HID, teruskan ID laporan 8-bit yang terkait dengan laporan fitur (reportId) ke device.receiveFeatureReport(). Promise yang ditampilkan di-resolve dengan objek DataView yang berisi konten laporan fitur. Jika perangkat HID tidak menggunakan ID laporan, setel reportId ke 0.
// Request feature report.
const dataView = await device.receiveFeatureReport(/* reportId= */ 1);
// Read feature report contents with dataView.getInt8(), getUint8(), etc...
Mendengarkan koneksi dan pemutusan koneksi
Jika situs telah diberi izin untuk mengakses perangkat HID, situs tersebut dapat secara aktif menerima peristiwa koneksi dan pemutusan koneksi dengan memantau peristiwa "connect" dan "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.
});
Mencabut akses ke perangkat HID
Situs dapat menghapus izin untuk mengakses perangkat HID yang tidak lagi ingin dipertahankannya dengan memanggil forget() pada instance HIDDevice. Misalnya, untuk aplikasi web pendidikan yang digunakan di komputer bersama dengan banyak perangkat, sejumlah besar izin yang dihasilkan pengguna yang terakumulasi akan menciptakan pengalaman pengguna yang buruk.
Memanggil forget() pada satu instance HIDDevice akan mencabut akses ke semua
antarmuka HID pada perangkat fisik yang sama.
// Voluntarily revoke access to this HID device.
await device.forget();
Karena forget() tersedia di Chrome 100 atau yang lebih baru, periksa apakah fitur ini didukung dengan langkah-langkah berikut:
if ("hid" in navigator && "forget" in HIDDevice.prototype) {
// forget() is supported.
}
Tips developer

Debug HID di Chrome dengan halaman internal, about://device-log
tempat Anda dapat melihat semua peristiwa terkait perangkat HID dan USB di satu tempat.
Lihat HID explorer untuk mengekspor info perangkat HID ke dalam format yang dapat dibaca manusia. Memetakan dari nilai penggunaan ke nama untuk setiap penggunaan HID.
Di sebagian besar sistem Linux, perangkat HID dipetakan dengan izin hanya baca secara
default. Untuk mengizinkan Chrome membuka perangkat HID, Anda harus menambahkan aturan
udev baru. Buat file di /etc/udev/rules.d/50-yourdevicename.rules dengan
konten berikut:
KERNEL=="hidraw*", ATTRS{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
Dalam kode ini, [yourdevicevendor] adalah 057e, misalnya jika perangkat Anda adalah
Nintendo Switch Joy-Con. ATTRS{idProduct} dapat ditambahkan untuk aturan yang lebih spesifik. Pastikan user Anda adalah anggota grup plugdev. Kemudian, cukup
hubungkan kembali perangkat Anda.
Demo
Beberapa demo WebHID tercantum di web.dev/hid-examples.
Keamanan dan privasi
Penulis spesifikasi telah mendesain dan menerapkan WebHID API menggunakan prinsip inti yang ditentukan dalam Mengontrol Akses ke Fitur Platform Web yang Canggih, termasuk kontrol pengguna, transparansi, dan ergonomi. Kemampuan untuk menggunakan API ini terutama dibatasi oleh model izin yang memberikan akses hanya ke satu perangkat HID dalam satu waktu. Sebagai respons terhadap perintah pengguna, pengguna harus mengambil langkah-langkah aktif untuk memilih perangkat HID tertentu.
Untuk memahami pertimbangan keamanan, lihat bagian Pertimbangan Keamanan dan Privasi dalam spesifikasi WebHID.
Selain itu, Chrome memeriksa penggunaan setiap koleksi tingkat teratas dan jika koleksi tingkat teratas memiliki penggunaan yang dilindungi (misalnya, keyboard generik, mouse), maka situs tidak akan dapat mengirim dan menerima laporan apa pun yang ditentukan dalam koleksi tersebut. Daftar lengkap penggunaan yang dilindungi tersedia secara publik.
Perhatikan bahwa perangkat HID yang sensitif terhadap keamanan (seperti perangkat HID FIDO yang digunakan untuk autentikasi yang lebih kuat) juga diblokir di Chrome. Lihat file daftar blokir USB dan daftar blokir HID.
Masukan
Tim Chrome ingin mendengar pendapat dan pengalaman Anda terkait WebHID API.
Beri tahu kami tentang desain API
Apakah ada sesuatu tentang API yang tidak berfungsi seperti yang diharapkan? Atau apakah ada metode atau properti yang belum ada dan Anda perlukan untuk menerapkan ide Anda?
Laporkan masalah spesifikasi di repo GitHub WebHID API atau tambahkan pendapat Anda ke masalah yang ada.
Melaporkan masalah terkait penerapan
Apakah Anda menemukan bug pada penerapan Chrome? Atau apakah implementasinya berbeda dari spesifikasi?
Lihat Cara melaporkan bug WebHID. Pastikan untuk menyertakan detail sebanyak mungkin, berikan petunjuk untuk mereproduksi bug, dan tetapkan Komponen ke Blink>HID.
Link bermanfaat
- Spesifikasi
- Melacak bug
- Entri ChromeStatus.com
- Komponen Blink:
Blink>HID
Ucapan terima kasih
Terima kasih kepada Matt Reynolds dan Joe Medley atas ulasan mereka.