התחברות למכשירי HID לא נפוצים

WebHID API מאפשר לאתרים לגשת למקלדות עזר חלופיות ולגיימפאד אקזוטיים.

Fran��ois Beaufort
François Beaufort

קיים "זנב ארוך" של מכשירי ממשק אנושי (HID), כמו מקלדות או לוחות משחק אקזוטיים, חדשים מדי, ישנים מדי או לא נפוצים מכדי נגישים דרך המערכות מנהלי התקנים של מכשירים. ה-WebHID API פותר את הבעיה הזו באמצעות להטמעת לוגיקה ספציפית למכשיר ב-JavaScript.

הצעות לתרחישים לדוגמה

מכשיר ממשק אנושי (HID) מקבל קלט מבני אדם או מספק פלט אליהם. דוגמאות למכשירים כוללות מקלדות, מכשירי הצבעה (עכברים, מסכי מגע וכו') ומכשירי גיימפאד. אפשר לגשת למכשירים האלה מהמחשב באמצעות פרוטוקול HID למחשבים שמשתמשים במנהלי התקנים של מערכת הפעלה. פלטפורמת האינטרנט תומכת במכשירי ממשק אנושי (HID) על ידי הסתמכות על הנהגים האלה.

חוסר היכולת לגשת למכשירי ממשק אנושי (HID) לא נפוצים היא מכאיבה במיוחד מגיע למקלדות עזר חלופיות (למשל Elgato Stream Deck, Jabra אוזניות, מקשי X) ותמיכה בגיימפאד אקזוטי. גיימפאדים שמיועדים למחשבים לרוב משתמשים במכשיר ��משק אנושי (HID) לקלט של בקר משחקים (לחצנים, ג'ויסטיקים, טריגרים) ופלט (נורות LED, רעשנים). לצערנו, אפשרויות הקלט והפלט של הגיימפאד לא טובות בדפדפני אינטרנט רגילים ובדפדפני אינטרנט נדרשת בדרך כלל לוגיקה מותאמת אישית למכשירים ספציפיים. הדבר אינו בר קיימא וגורם לתמיכה נמוכה בזנב הארוך של אנשים מבוגרים ולא נפוצים. הוא גם גורם לדפדפן להיות תלוי בחריגים בהתנהגות. של מכשירים מסוימים.

הסברים על המונחים

ממשק אנושי (HID) מורכב משני מושגים בסיסיים: דוחות ומתארי דוחות. דוחות הם הנתונים שמועברים בין מכשיר לבין לקוח תוכנה. במתאר הדוח מתואר הפורמט והמשמעות של הנתונים שבמכשיר נתמך.

מכשיר ממשק אנושי (HID) הוא סוג של מכשיר שמקבל קלט מספקת פלט לבני אדם. הוא מתייחס גם לפרוטוקול HID, תקן תקשורת דו-כיוונית בין מארח למכשיר, שנועדה מפשטים את תהליך ההתקנה. פרוטוקול ממשק אנושי (HID) פותח במקור להתקני USB, אבל מאז הוא יושם בפרוטוקולים רבים אחרים, כולל Bluetooth.

אפליקציות ומכשירי ממשק אנושי (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). אפשר לקבל את האימיילים האלה USB ID Repository והמסמך של טבלאות השימוש ב-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) באתר.
הנחיה למשתמש לבחירת Nintendo Switch Joy-Con.

אפשר גם להשתמש במפתח האופציונלי 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 בצבע אדום וכחול.
מכשירי Nintendo Switch Joy-Con.

בהמשך לדוגמה הקודמת, הקוד הבא מראה לכם איך הלחצן שהמשתמש לחץ עליו במכשיר Joy-ConRight כדי שתוכל אני מקווה שתנסו אותו בבית.

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() זמין ב-Chrome מגרסה 100 ואילך, לכן כדאי לבדוק אם התכונה הזו נתמכים עם:

if ("hid" in navigator && "forget" in HIDDevice.prototype) {
  // forget() is supported.
}

טיפים למפתחים

קל לנפות באגים ב-HID ב-Chrome בעזרת הדף הפנימי, about://device-log שבו אפשר לראות את כל האירועים שקשורים למכשיר ממשק אנושי (HID) ולהתקני USB במקום אחד.

צילום מסך של הדף הפנימי לניפוי באגים במכשיר HID.
דף פנימי ב-Chrome לניפוי באגים במכשיר ממשק אנושי (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. תקלה פועלת מצוין עבור ולשתף תגובות מהירות וקלות.

פנייה לתמיכה

האם בכ��ונתך להשתמש ב-WebHID API? התמיכה הציבורית שלך עוזרת ל-Chrome הצוות מתעדף תכונות ומראה לספקי דפדפנים אחרים עד כמה זה קריטי לתמוך בהם.

שליחת ציוץ אל @ChromiumDev בעזרת hashtag #WebHID ושליחת משוב איפה ואיך משתמשים בו.

קישורים שימושיים

אישורים

תודה למאט ריינולדס ולג'ו מדלי על הביקורות שפרסמו על המאמר הזה. תמונת Nintendo Switch בצבעי אדום וכחול מאת שרה קורפס, ומחשב נייד בצבעי שחור וכסף תמונת מחשב מאת Athul Cyriac Ajay ב-Un למידע