تسمح واجهة برمجة التطبيقات WebHID API للمواقع الإلكترونية بالوصول إلى لوحات المفاتيح الإضافية البديلة وأجهزة التحكّم في الألعاب الغريبة.
هناك عدد كبير من أجهزة الواجهة البشرية (HID)، مثل لوحات المفاتيح البديلة أو لوحات التحكّم في الألعاب الغريبة، التي تكون جديدة جدًا أو قديمة جدًا أو غير شائعة جدًا بحيث لا يمكن لبرامج تشغيل الأجهزة في الأنظمة الاستفادة منها. تحلّ WebHID API هذه المشكلة من خلال توفير طريقة لتنفيذ منطق خاص بالجهاز في JavaScript.
حالات الاستخدام المقترَحة
يتلقّى جهاز HID إدخالات من المستخدمين أو يقدّم لهم مخرجات. تشمل أمثلة الأجهزة لوحات المفاتيح وأجهزة التأشير (مثل أجهزة الماوس والشاشات التي تعمل باللمس وما إلى ذلك) وأجهزة التحكّم في الألعاب. يتيح بروتوكول HID الوصول إلى هذه الأجهزة على أجهزة الكمبيوتر المكتبي باستخدام برامج تشغيل نظام التشغيل. تتوافق منصة الويب مع أجهزة HID من خلال الاعتماد على برامج تشغيل هذه الأجهزة.
يُعدّ عدم التمكّن من الوصول إلى أجهزة HID غير الشائعة أمرًا مزعجًا بشكل خاص عند استخدام لوحات المفاتيح البديلة (مثل Elgato Stream Deck وسماعات رأس Jabra وX-keys) وأجهزة التحكّم في الألعاب الغريبة. إنّ أجهزة التحكّم في الألعاب المصمّمة لأجهزة الكمبيوتر المكتبي تستخدم غالبًا بروتوكول HID لإدخالات أجهزة التحكّم في الألعاب (الأزرار وعصا التحكم وأدوات التنشيط) ومخرجاتها (مؤشرات LED والاهتزاز). لا تكون مدخلات ومخرجات أجهزة التحكّم في الألعاب متّسقة بشكلٍ جيد، وغالبًا ما تتطلّب متصفّحات الويب منطقًا مخصّصًا لأجهزة معيّنة. وهذا النهج غير مستدام ويؤدي إلى توفّر دعم ضعيف للأجهزة القديمة والغير الشائعة. ويؤدي ذلك أيضًا إلى اعتماد المتصفّح على سلوكيات غريبة في الأجهزة المحدّدة.
المصطلحات
يتألف HID من مفهومَين أساسيَين: التقارير ووصاف التقارير. التقارير هي البيانات التي يتم تبادلها بين جهاز وعميل برنامج. يصف وصف التقرير تنسيق البيانات التي يقبلها الجهاز ومعناها.
جهاز HID (جهاز واجهة المستخدم) هو نوع من الأجهزة التي تتلقّى إدخالات من المستخدمين أو تُقدّم لهم مخرجات. ويشير أيضًا إلى بروتوكول HID، وهو معيار ل الاتصال الثنائي الاتجاه بين مضيف وجهاز مصمّم لمحاولة تبسيط عملية التثبيت. تم تطوير بروتوكول HID في الأصل لأجهزة USB، ولكن تم تنفيذه منذ ذلك الحين على العديد من البروتوكولات الأخرى، بما في ذلك البلوتوث.
تتبادل التطبيقات وأجهزة HID البيانات الثنائية من خلال ثلاثة أنواع من التقارير:
نوع التقرير | الوصف |
---|---|
تقرير الإدخال | البيانات التي يتم إرسالها من الجهاز إلى التطبيق (مثل الضغط على زر) |
تقرير المخرجات | البيانات التي يتم إرسالها من التطبيق إلى الجهاز (مثل طلب تشغيل الإضاءة الخلفية للوحة المفاتيح) |
تقرير الميزات | البيانات التي يمكن إرسالها في أي اتجاه يختلف التنسيق حسب الجهاز. |
يصف وصف التقرير التنسيق الثنائي للتقارير المتوافقة مع الجهاز. إنّ بنية هذه المجموعات هرمية ويمكنها تجميع التقارير معًا كمجموعات متمايزة ضمن المجموعة ذات المستوى الأعلى. يتم تحديد تنسيق الوصف من قِبل مواصفات HID.
استخدام HID هو قيمة رقمية تشير إلى إدخال أو إخراج موحّد. تسمح قيم الاستخدام للجهاز بوصف الاستخدام المقصود للجهاز و الغرض من كل حقل في تقاريره. على سبيل المثال، يتم تعريف زر واحد لزر الماوس الأيسر. يتم أيضًا تنظيم عمليات الاستخدام في صفحات الاستخدام التي تقدّم مؤشرًا للفئة العالية المستوى للجهاز أو التقرير.
استخدام واجهة برمجة التطبيقات WebHID API
رصد الميزات
للتحقّق من توفّر واجهة برمجة التطبيقات WebHID API، استخدِم:
if ("hid" in navigator) {
// The WebHID API is supported.
}
فتح اتصال HID
إنّ واجهة برمجة التطبيقات WebHID API غير متزامنة من حيث التصميم لمنع واجهة مستخدِم الموقع الإلكتروني من الحظر أثناء انتظار الإدخال. هذا مهم لأنّه يمكن تلقّي بيانات HID في أي وقت، ما يتطلّب طريقة للاستماع إليها.
لفتح اتصال HID، عليك أولاً الوصول إلى عنصر HIDDevice
. ولإجراء ذلك، يمكنك
إما مطالبة المستخدم باختيار جهاز من خلال الاتصال بالرقم
navigator.hid.requestDevice()
، أو اختيار جهاز من navigator.hid.getDevices()
الذي يعرض قائمة بالأجهزة التي تم منح الموقع الإلكتروني إذن الوصول إليها
في السابق.
تأخذ الدالة navigator.hid.requestDevice()
عنصرًا إلزاميًا يحدد الفلاتر. وتُستخدَم هذه العناصر لمطابقة أي جهاز متصل بمعرّف مورّد USB (vendorId
) ومعرّف منتج USB (productId
) وقيمة صفحة الاستخدام (usagePage
) وقيمة الاستخدام (usage
). ويمكنك الحصول على هذه العناصر من ملف IDEMUT الذي يحتوي على معرّفات 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 الأيمن حتى تتمكّن من تجربته في المنزل.
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 غير المُعَدَّلة. على عكس تقارير الإدخال والإخراج، لا يتلقّى التطبيق تقارير الميزات أو يرسلها بشكل منتظم.
لإرسال تقرير ميزة إلى جهاز 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()
متاح في الإصدار 100 من Chrome أو الإصدارات الأحدث، تحقَّق مما إذا كانت هذه الميزة
متوافقة مع ما يلي:
if ("hid" in navigator && "forget" in HIDDevice.prototype) {
// forget() is supported.
}
نصائح للمطوّرين
يمكنك بسهولة تصحيح أخطاء HID في Chrome باستخدام الصفحة الداخلية about://device-log
التي يمكنك من خلالها الاطّلاع على جميع الأحداث ذات الصلة بأجهزة HID وUSB في مكان واحد.
يمكنك الاطّلاع على HID explorer لتفريغ معلومات 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) في الإصدار 89 من Chrome.
إصدارات تجريبية
يمكنك الاطّلاع على بعض العروض التوضيحية لواجهة WebHID على الرابط web.dev/hid-examples. ألقِ نظرة.
الأمان والخصوصية
لقد صمم مؤلفو المواصفات واجهة برمجة التطبيقات WebHID API ونفّذوها باستخدام مبادئ أساسية تم تحديدها في مقالة التحكّم في الوصول إلى ميزات منصة الويب الفعّالة، بما في ذلك التحكّم الذي يمارسه المستخدم والشفافية وسهولة الاستخدام. إنّ إمكانية استخدام واجهة برمجة التطبيقات هذه محدودة بشكل أساسي من خلال نموذج أذونات يمنح إذن الوصول إلى جهاز HID واحد فقط في كل مرة. استجابةً لطلب من المستخدم، يجب أن يتّخذ المستخدم خطوات نشطة لاختيار جهاز HID معيّن.
لفهم المفاضلات الأمنية، اطّلِع على قسم الاعتبارات المتعلّقة بالخصوصية والأمان في مواصفات WebHID.
بالإضافة إلى ذلك، يتحقّق Chrome من استخدام كل مجموعة من المستوى الأعلى، وإذا كانت مجموعة من المستوى الأعلى لها استخدام محمي (مثل لوحة مفاتيح عامة أو فأرة)، لن يتمكّن الموقع الإلكتروني من إرسال أي تقارير محدّدة في تلك المجموعة أو تلقّيها. إنّ القائمة الكاملة للاستخدامات المحمية متاحة للجميع.
يُرجى العلم أنّه يتم أيضًا حظر أجهزة HID الحساسة للأمان (مثل أجهزة HID التي تستخدم بروتوكول FIDO للمصادقة بقوة أكبر) في Chrome. اطّلِع على ملفَي القائمة المحظورة لأجهزة USB والقائمة المحظورة لأجهزة HID.
ملاحظات
يسرّ فريق Chrome معرفة رأيك وتجاربك بشأن واجهة برمجة التطبيقات WebHID API.
أخبِرنا عن تصميم واجهة برمجة التطبيقات.
هل هناك مشكلة في واجهة برمجة التطبيقات لا تعمل على النحو المتوقّع؟ هل هناك methods أو properties مفقودة تحتاجها لتنفيذ فكرتك؟
يمكنك الإبلاغ عن مشكلة في المواصفات على مستودع GitHub الخاص بواجهة برمجة التطبيقات WebHID API أو إضافة ملاحظاتك إلى مشكلة حالية.
الإبلاغ عن مشكلة في التنفيذ
هل رصدت خطأ في عملية تنفيذ Chrome؟ أم هل التنفيذ مختلف عن المواصفات؟
اطّلِع على كيفية الإبلاغ عن أخطاء WebHID. احرص على تضمين أكبر قدر ممكن من
التفاصيل، وتقديم تعليمات بسيطة لإعادة إنتاج الخلل، وضبط قيمة
المكوّنات على Blink>HID
. تُعدّ أداة Glitch رائعة لمشاركة عمليات إعادة الإنتاج السريعة والسهلة.
إظهار الدعم
هل تخطّط لاستخدام واجهة برمجة التطبيقات WebHID API؟ يساعد دعمك العلني فريق Chrome في منح الأولوية للميزات ويُظهر لموفّري المتصفّحات الآخرين مدى أهمية إتاحة الميزات للجميع.
أرسِل تغريدة إلى @ChromiumDev باستخدام الهاشتاغ
#WebHID
وأخبِرنا
بمكان وطريقة استخدامك له.
روابط مفيدة
- المواصفات
- خطأ في التتبّع
- إدخال ChromeStatus.com
- عنصر Blink:
Blink>HID
الشكر والتقدير
نشكر مات رينولدز وجو ميديل على مراجعتهما لهذه المقالة. صورة لجهاز Nintendo Switch باللونَين الأحمر والأزرق تصوّرها سارة كورفيس، وصورة لجهاز كمبيوتر محمول باللونَين الأسود والفضي تصوّرها أتول كيرياك أجاي على Unsplash