WebHID API ช่วยให้เว็บไซต์เข้าถึงแป้นพิมพ์เสริมสำรองและเกมแพดที่แปลกใหม่ได้
อุปกรณ์สำหรับมนุษย์ (HID) ที่มีอยู่หากันมาอย่างยาวนาน เช่น แป้นพิมพ์หรือเกมแพดที่แปลกใหม่ ซึ่งใหม่เกินไป เก่าเกินไป หรือแปลกผิดปกติ เข้าถึงได้จากระบบ ไดรเวอร์อุปกรณ์ WebHID API แก้ปัญหานี้โดยการระบุ วิธีนำตรรกะที่เจาะจงอุปกรณ์ไปใช้ใน JavaScript
Use Case ที่แนะนำ
อุปกรณ์ HID รับอินพุตหรือเอาต์พุตให้มนุษย์ ตัวอย่างอุปกรณ์ รวมถึงแป้นพิมพ์ อุปกรณ์ชี้ตำแหน่ง (เมาส์ หน้าจอสัมผัส ฯลฯ) และเกมแพด โปรโตคอล HID ช่วยให้เข้าถึงอุปกรณ์เหล่านี้บนเดสก์ท็อปได้ คอมพิวเตอร์ที่ใช้ไดรเวอร์ระบบปฏิบัติการ แพลตฟอร์มเว็บรองรับอุปกรณ์ HID โดยอาศัยตัวขับเคลื่อนเหล่านี้
การไม่สามารถเข้าถึงอุปกรณ์ HID ที่ผิดปกตินั้นเป็นเรื่องที่เจ็บปวดมาก สำหรับแป้นพิมพ์เสริมทางเลือก (เช่น Elgato Stream Deck, Jabra ชุดหูฟัง ปุ่ม X) และการสนับสนุนเกมแพดที่แปลกใหม่ เกมแพดที่ออกแบบมาเพื่อเดสก์ท็อป มักใช้ HID สำหรับอินพุตเกมแพด (ปุ่ม จอยสติ๊ก ทริกเกอร์) และเอาต์พุต (ไฟ LED สีรุ้ง) ขออภัย อินพุตและเอาต์พุตของเกมแพดไม่ดี และเว็บเบราว์เซอร์มาตรฐานมักต้องใช้ตรรกะที่กำหนดเองสำหรับอุปกรณ์บางประเภท สิ่งนี้ไม่ยั่งยืน ส่งผลให้เกิดการสนับสนุนที่ไม่ดีสำหรับผู้สูงอายุและ อุปกรณ์ที่ผิดปกติ และยังทำให้เบราว์เซอร์ต้องพึ่งพฤติกรรมที่ไม่ปกติ ของอุปกรณ์ที่เฉพาะเจาะจง
คำศัพท์
HID ประกอบด้วยแนวคิดพื้นฐาน 2 ประการ ได้แก่ รายงานและข้อบ่งชี้รายงาน รายงานคือข้อมูลที่รับส่งกันระหว่างอุปกรณ์กับซอฟต์แวร์ไคลเอ็นต์ ข้อบ่งชี้รายงานจะอธิบายรูปแบบและความหมายของข้อมูลที่อุปกรณ์ รองรับ
HID (Human Interface Device) เป็นประเภทของอุปกรณ์ที่รับอินพุตหรือ ให้ผลผลิตแก่มนุษย์ นอกจากนี้ยังหมายถึงโปรโตคอล 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 ID และเอกสารตารางการใช้งาน 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();
![ภาพหน้าจอของข้อความแจ้งอุปกรณ์ HID ในเว็บไซต์](https://developer.chrome.com/static/docs/capabilities/hid/image/screenshot-an-hid-device-e26b194feb58a.jpg?authuser=19&hl=th)
คุณยังใช้คีย์ 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
)
![รูปภาพสวิตช์ Nintendo สีแดงและน้ำเงิน](https://developer.chrome.com/static/docs/capabilities/hid/image/red-blue-nintendo-switch-9754d1c61bf3.jpg?authuser=19&hl=th)
จากตัวอย่างก่อนหน้านี้ โค้ดด้านล่างจะแสดงให้คุณเห็นวิธีตรวจหา ปุ่มที่ผู้ใช้กดบนอุปกรณ์ 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 ประเภทเดียวที่สำรวจได้ทั้ง เส้นทาง ช่วยให้อุปกรณ์และแอปพลิเคชัน HID แลกเปลี่ยนข้อมูลแบบไม่เป็นมาตรฐานได้ ข้อมูล HID ระบบไม่ได้รับรายงานฟีเจอร์ ซึ่งแตกต่างจากรายงานอินพุตและเอาต์พุต หรือ ที่ส่งจากแอปพลิเคชันเป็นประจำ
![รูปภาพแล็ปท็อปสีดำและสีเงิน](https://developer.chrome.com/static/docs/capabilities/hid/image/black-silver-laptop-comp-91a25010b2b48.jpg?authuser=19&hl=th)
หากต้องการส่งรายงานฟีเจอร์ไปยังอุปกรณ์ 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](https://developer.chrome.com/static/docs/capabilities/hid/image/screenshot-the-internal-958992d62d73e.jpg?authuser=19&hl=th)
ดูโปรแกรมสำรวจ 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 ในการตอบสนองต่อข้อความแจ้งผู้ใช้ ผู้ใช้ต้องมีสถานะใช้งาน ขั้นตอนในการเลือกอุปกรณ์ HID ที่เฉพาะเจาะจง
หากต้องการทำความเข้าใจเกี่ยวกับข้อดีและข้อเสียของความปลอดภัย โปรดดูที่ความปลอดภัยและความเป็นส่วนตัว ส่วนข้อควรพิจารณาของข้อกำหนด WebHID
นอกจากนี้ Chrome ยังตรวจสอบการใช้งานคอลเล็กชันระดับบนสุดแต่ละรายการ คอลเล็กชันระดับบนสุดมีการใช้งานที่มีการป้องกัน (เช่น แป้นพิมพ์ทั่วไป เมาส์) แล้ว เว็บไซต์จะไม่สามารถส่งและรับรายงานใดๆ ที่ระบุใน คอลเล็กชัน รายการการใช้งานที่มีการคุ้มครองทั้งหมดนี้จะพร้อมใช้งานแบบสาธารณะ
โปรดทราบว่าอุปกรณ์ HID ที่มีความละเอียดอ่อนต่อความปลอดภัย (เช่น อุปกรณ์ FIDO HID ที่ใช้สำหรับ การตรวจสอบสิทธิ์ที่รัดกุมยิ่งขึ้น) จะถูกบล็อกใน Chrome ด้วย โปรดดูรายการที่บล็อก USB และ ไฟล์รายการ HID ที่บล็อก
ความคิดเห็น
ทีม Chrome อยากทราบความคิดเห็นและประสบการณ์ของคุณเกี่ยวกับ WebHID API
บอกเราเกี่ยวกับการออกแบบ API
มีบางอย่างเกี่ยวกับ API ที่ไม่ทำงานตามที่คาดไว้หรือไม่ หรือมี วิธีการหรือคุณสมบัติที่จำเป็นไม่ครบที่คุณต้องการนำไอเดียไปปฏิบัติ
แจ้งปัญหาเกี่ยวกับที่เก็บ WebHID API GitHub หรือเพิ่มความเห็น กับปัญหาที่มีอยู่
รายงานปัญหาเกี่ยวกับการติดตั้งใช้งาน
คุณพบข้อบกพร่องในการติดตั้งใช้งาน 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