WebHID API ช่วยให้เว็บไซต์เข้าถึงแป้นพิมพ์เสริมและเกมแพดพิเศษอื่นๆ ได้
อุปกรณ์ที่เชื่อมต่อกับมนุษย์ (HID) มีอยู่เป็นจำนวนมาก เช่น คีย์บอร์ดสำรองหรือเกมแพดแปลกใหม่ ที่ใหม่เกินไป เก่าเกินไป หรือผิดปกติจนเข้าถึงได้โดยไดรเวอร์อุปกรณ์ของระบบ WebHID API แก้ปัญหานี้โดยการนำเสนอวิธีใช้งานตรรกะเฉพาะอุปกรณ์ใน JavaScript
กรณีการใช้งานที่แนะนำ
อุปกรณ์ HID รับอินพุตจากหรือให้เอาต์พุตแก่มนุษย์ ตัวอย่างอุปกรณ์ ได้แก่ แป้นพิมพ์ อุปกรณ์ชี้ตำแหน่ง (เมาส์ หน้าจอสัมผัส ฯลฯ) และเกมแพด โปรโตคอล HID ช่วยให้เข้าถึงอุปกรณ์เหล่านี้ในคอมพิวเตอร์เดสก์ท็อปได้โดยใช้ไดรเวอร์ระบบปฏิบัติการ แพลตฟอร์มเว็บรองรับอุปกรณ์ HID โดยอาศัยไดรเวอร์เหล่านี้
การที่ไม่สามารถเข้าถึงอุปกรณ์ HID ทั่วไปจะสร้างความเจ็บปวดเป็นพิเศษเมื่อแป้นพิมพ์เสริมทางเลือก (เช่น Elgato Stream Deck, ชุดหูฟัง Jabra, X-key) และการสนับสนุนเกมแพดแปลกใหม่ เกมแพดที่ออกแบบมาเพื่อเดสก์ท็อป มักจะใช้ HID สำหรับอินพุตของเกมแพด (ปุ่ม จอยสติ๊ก ทริกเกอร์) และเอาต์พุต (LED, เสียงแตก) แต่อินพุตและเอาต์พุตของเกมแพดไม่ได้มาตรฐานที่ดี และเว็บเบราว์เซอร์มักต้องใช้ตรรกะที่กำหนดเองสำหรับอุปกรณ์เฉพาะ ซึ่งเป็นวิธีที่ยั่งยืนและส่งผลให้การสนับสนุนอุปกรณ์ระยะยาวในอุปกรณ์รุ่นเก่าและอุปกรณ์ทั่วไปไม่มีประสิทธิภาพ และยังทำให้เบราว์เซอร์ต้องใช้พฤติกรรมที่ผิดปกติ ของอุปกรณ์บางอย่างด้วย
คำศัพท์
HID ประกอบด้วยแนวคิดพื้นฐาน 2 ประการ ได้แก่ รายงานและข้อบ่งชี้รายงาน รายงานคือข้อมูลที่แลกเปลี่ยนระหว่างอุปกรณ์กับไคลเอ็นต์ซอฟต์แวร์ ข้อบ่งชี้รายงานจะอธิบายรูปแบบและความหมายของข้อมูลที่อุปกรณ์รองรับ
HID (อุปกรณ์อินเทอร์เฟซมนุษย์) เป็นอุปกรณ์ประเภทหนึ่งที่รับอินพุตจากหรือให้เอาต์พุตแก่มนุษย์ และยังหมายถึงโปรโตคอล HID ซึ่งเป็นมาตรฐานสำหรับการสื่อสารแบบ 2 ทิศทางระหว่างโฮสต์และอุปกรณ์ที่ออกแบบมาเพื่อทำให้ขั้นตอนการติดตั้งง่ายขึ้น เดิมทีโปรโตคอล HID พัฒนาขึ้นสำหรับอุปกรณ์ USB แต่ได้ใช้บนโปรโตคอลอื่นๆ มามากมาย ซึ่งรวมถึงบลูทูธ
แอปพลิเคชันและอุปกรณ์ HID จะแลกเปลี่ยนข้อมูลไบนารีผ่านรายงาน 3 ประเภทดังนี้
ประเภทรายงาน | คำอธิบาย |
---|---|
รายงานอินพุต | ข้อมูลที่ส่งจากอุปกรณ์ไปยังแอปพลิเคชัน (เช่น มีการกดปุ่ม) |
รายงานเอาต์พุต | ข้อมูลที่ส่งจากแอปพลิเคชันไปยังอุปกรณ์ (เช่น คำขอเปิดไฟแบ็กไลต์ของแป้นพิมพ์) |
รายงานฟีเจอร์ | ข้อมูลที่ส่งไปในทิศทางใดก็ได้ โดยจะมีรูปแบบเฉพาะอุปกรณ์ |
ข้อบ่งชี้รายงานจะอธิบายถึงรูปแบบไบนารีของรายงานที่อุปกรณ์รองรับ มีโครงสร้างเป็นลำดับชั้นและสามารถจัดกลุ่มรายงานต่างๆ เป็นคอลเล็กชันที่ต่างกันภายในคอลเล็กชันระดับบนสุด รูปแบบของข้อบ่งชี้จะกำหนดโดยข้อกำหนดเฉพาะ HID
การใช้งาน HID คือค่าตัวเลขที่อ้างถึงอินพุตหรือเอาต์พุตมาตรฐาน ค่าการใช้งานช่วยให้อุปกรณ์อธิบายจุดประสงค์ในการใช้อุปกรณ์และวัตถุประสงค์ของแต่ละฟิลด์ในรายงาน เช่น ปุ่มหนึ่งกำหนดไว้สำหรับ ปุ่มด้านซ้ายของเมาส์ นอกจากนี้ยังมีการจัดระเบียบการใช้งานไว้ในหน้าการใช้งาน ซึ่งระบุหมวดหมู่ระดับสูงของอุปกรณ์หรือรายงานด้วย
การใช้ WebHID API
การตรวจหาฟีเจอร์
หากต้องการตรวจสอบว่าระบบรองรับ WebHID API หรือไม่ ให้ใช้
if ("hid" in navigator) {
// The WebHID API is supported.
}
เปิดการเชื่อมต่อ HID
WebHID API ทำงานไม่พร้อมกันโดยออกแบบมาให้ป้องกันไม่ให้ UI ของเว็บไซต์บล็อกเมื่อรออินพุต ซึ่งเป็นสิ่งสำคัญเนื่องจากสามารถรับข้อมูล 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]}.`);
});
ส่งรายงานเอาต์พุต
หากต้องการส่งรายงานเอาต์พุตไปยังอุปกรณ์ 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));
ส่งและรับรายงานฟีเจอร์
รายงานฟีเจอร์เป็นรายงานข้อมูล HID ประเภทเดียวที่สามารถเดินทางได้ในทั้ง 2 ทิศทาง อุปกรณ์และแอปพลิเคชัน 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);
}
หากต้องการรับรายงานฟีเจอร์จากอุปกรณ์ 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 เพื่อดูข้อมูลอุปกรณ์ 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
จากนั้นเพียงเชื่อมต่ออุปกรณ์อีกครั้ง
การสนับสนุนเบราว์เซอร์
WebHID API พร้อมใช้งานในแพลตฟอร์มเดสก์ท็อปทั้งหมด (ChromeOS, Linux, macOS และ Windows) ใน Chrome 89
เดโม
การสาธิต WebHID บางส่วนแสดงไว้ที่ web.dev/hid-examples ลองดูเลย!
ความปลอดภัยและความเป็นส่วนตัว
ผู้เขียนข้อกำหนดได้ออกแบบและใช้งาน WebHID API โดยใช้หลักการสำคัญที่ระบุไว้ในการควบคุมสิทธิ์เข้าถึงฟีเจอร์แพลตฟอร์มเว็บที่มีประสิทธิภาพ ซึ่งรวมถึงการควบคุมผู้ใช้ ความโปร่งใส และการยศาสตร์ ความสามารถในการใช้ API นี้จะถูกจำกัดโดยโมเดลสิทธิ์ที่ให้สิทธิ์เข้าถึงอุปกรณ์ HID เพียงครั้งละ 1 เครื่องเป็นหลัก ในการตอบสนองต่อข้อความแจ้งของผู้ใช้ ผู้ใช้ต้องทำตามขั้นตอนที่มีอยู่เพื่อเลือกอุปกรณ์ HID ที่ต้องการ
หากต้องการทำความเข้าใจเกี่ยวกับข้อดีข้อเสียด้านความปลอดภัย โปรดดูส่วนข้อควรพิจารณาด้านความปลอดภัยและความเป็นส่วนตัวของข้อกำหนด WebHID
นอกจากนี้ Chrome จะตรวจสอบการใช้งานคอลเล็กชันระดับบนสุดแต่ละรายการ และหากคอลเล็กชันระดับบนสุดมีการใช้งานที่มีการป้องกัน (เช่น แป้นพิมพ์ทั่วไป เมาส์) เว็บไซต์ก็จะไม่สามารถส่งและรับรายงานใดๆ ที่กําหนดไว้ในคอลเล็กชันนั้นได้ รายการการใช้งานที่ได้รับการคุ้มครองทั้งหมดเผยแพร่แบบสาธารณะ
โปรดทราบว่าอุปกรณ์ HID ที่ไวต่อความปลอดภัย (เช่น อุปกรณ์ FIDO HID ที่ใช้สำหรับการตรวจสอบสิทธิ์ที่รัดกุมขึ้น) จะถูกบล็อกใน Chrome ด้วย ดูไฟล์รายการที่บล็อก USB และไฟล์รายการที่บล็อก HID
ความคิดเห็น
ทีม Chrome ต้องการทราบความคิดเห็นและประสบการณ์ของคุณเกี่ยวกับ WebHID API
บอกให้เราทราบเกี่ยวกับการออกแบบ API
มีบางอย่างเกี่ยวกับ API ที่ทำงานไม่ได้ตามที่คาดไว้ไหม หรือมีวิธีหรือคุณสมบัติที่ขาดหายไปที่คุณจำเป็นต้องใช้ในการนำแนวคิดของคุณไปปรับใช้
แจ้งปัญหาด้านข้อมูลจำเพาะในที่เก็บ GitHub API ของ WebHID หรือแสดงความคิดเห็นเกี่ยวกับปัญหาที่มีอยู่
รายงานปัญหาเกี่ยวกับการใช้งาน
คุณพบข้อบกพร่องในการใช้งาน Chrome หรือไม่ หรือการใช้งานแตกต่างจาก ข้อกำหนดหรือไม่
โปรดดูวิธีรายงานข้อบกพร่อง WebHID อย่าลืมใส่รายละเอียดให้มากที่สุดเท่าที่จะทำได้ ระบุวิธีการง่ายๆ ในการสร้างข้อบกพร่องอีกครั้ง และตั้งค่าคอมโพเนนต์เป็น Blink>HID
Glitch เหมาะสำหรับการแชร์
การเรียกซ้ำที่ง่ายและรวดเร็ว
แสดงการสนับสนุน
คุณวางแผนที่จะใช้ WebHID API หรือไม่ การสนับสนุนแบบสาธารณะของคุณช่วยให้ทีม Chrome จัดลำดับความสำคัญของฟีเจอร์ และแสดงให้ผู้ให้บริการเบราว์เซอร์รายอื่นๆ เห็นว่าการสนับสนุนฟีเจอร์ดังกล่าวสำคัญเพียงใด
ส่งทวีตไปที่ @ChromiumDev โดยใช้แฮชแท็ก #WebHID
และแจ้งให้เราทราบว่าคุณใช้แฮชแท็กนี้ที่ไหนและอย่างไร
ลิงก์ที่มีประโยชน์
- ข้อกำหนด
- ข้อบกพร่องในการติดตาม
- รายการ ChromeStatus.com
- คอมโพเนนต์การกะพริบ:
Blink>HID
ข้อความแสดงการยอมรับ
ขอขอบคุณ Matt Reynolds และ Joe Medley สำหรับรีวิวบทความนี้ รูปภาพ Nintendo Switch สีแดงและน้ำเงินโดย Sara Kurfeß และรูปภาพแล็ปท็อปสีดำและสีเงินโดย Athul Cyriac Ajay ใน Unsplash