連線至不常見的 HID 裝置

WebHID API 可讓網站存取替代的輔助鍵盤和奇特的遊戲墊。

François Beaufort
François Beaufort

人類介面裝置 (HID) 為長尾,例如替代品 鍵盤或奇特的益智遊戲,太新、太舊或不常見 可供系統存取裝置驅動程式WebHID API 解決這個問題的方法 在 JavaScript 中實作裝置專屬邏輯的方式。

建議用途

HID 裝置會接收輸入內容或提供輸出內容,裝置範例 包括鍵盤、指標裝置 (滑鼠、觸控螢幕等) 和遊戲手把。 有了 HID 通訊協定,你就能在電腦上存取這些裝置 電腦。網路平台支援 HID 裝置 仰賴這些驅動程式

無法存取不常見的 HID 裝置會更加困難 會出現替代輔助鍵盤 (例如 Elgato Stream DeckJabra) 耳機X 鍵) 和獨特遊戲手把的支援。專為電腦設計的遊戲搖桿 通常會使用 HID 做為遊戲手把的輸入裝置 (按鈕、搖桿、觸發條件) 和輸出內容。 (LED 燈、翻滾)。可惜的是,遊戲手把的輸入和輸出內容不正常 標準化和網路瀏覽器通常需要針對特定裝置自訂邏輯。 這種做法無法滿足,且對長尾及 更常見的裝置這也會使瀏覽器依賴行為中的特殊元素 特定裝置的叢集

術語

HID 由兩個基本概念構成:報表和報表描述元。 報表是裝置和軟體用戶端之間交換的資料。 報表描述元用於描述裝置提供的資料格式和意義 支援。

HID (人機介面裝置) 是一種裝置,用於接收 並提供給人類使用也是 HID 通訊協定 主機與針對 可簡化安裝程序HID 通訊協定最初是開發的 但之後已透過許多其他通訊協定實作 包括藍牙

應用程式和 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()」中選擇一項 這會傳回網站有權存取的裝置清單 像是剛才說過,即便 VM 正在運作 您還是能變更 VM 可用性政策

navigator.hid.requestDevice() 函式採用必要物件 定義篩選器。這些憑證會用來比對任何與 USB 供應商連線的裝置 ID (vendorId),USB 產品 ID (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 裝置提示螢幕截圖。
使用者選取 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 供應商和產品 ID 以及識別身分其 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" 事件。這些活動 包含做為 DataView 物件 (data) 的 HID 資料,亦即其所屬 HID 裝置 (device),以及與輸入報表相關聯的 8 位元報表 ID (reportId)。

紅色和藍色任天堂切換相片。
Nintendo Switch Joy-Con 裝置。

延續上例,下方程式碼示範如何偵測 使用者先前在 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 位元報告 ID 輸出報表 (reportId) 和位元組,做為 BufferSource (data), device.sendReport()。報表擷取完畢之後,傳回的承諾就會解決 已傳送。如果 HID 裝置並未使用報告 ID,請將 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 資料。有別於輸入和輸出報表,Google 不會收到 定期發送通知

黑色和銀色的筆記型電腦相片。
筆電鍵盤

如要將功能報告傳送到 HID 裝置,請傳遞相關聯的 8 位元報告 ID 使用特徵報表 (reportId) 和位元組 BufferSource (data), device.sendFeatureReport()。一旦報表執行以下作業,傳回的承諾就會解決 八位元數量。如果 HID 裝置並未使用報告 ID,請將 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 位元報告 ID 與特徵報表 (reportId) 相關聯的 device.receiveFeatureReport()。傳回的承諾會以 包含功能報告內容的 DataView 物件。如果 HID 裝置未使用報表 ID,請將 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 裝置 想在 HIDDevice 執行個體上呼叫 forget() 來保留資料。適用對象 例如教育性網頁應用程式,應用程式在與多人共用電腦中 大量使用者產生的權限會造成 使用者體驗

在單一 HIDDevice 執行個體上呼叫 forget() 會撤銷所有用戶端的存取權 同一部實體裝置上的 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.
}

開發人員秘訣

使用內部網頁 (about://device-log),即可輕鬆在 Chrome 中對 HID 進行偵錯 集中查看所有 HID 和 USB 裝置相關事件。

用於對 HID 偵錯的內部頁面螢幕截圖。
使用 Chrome 的內部頁面對 HID 進行偵錯。

瞭解如何透過 HID 瀏覽器傾印 HID 裝置 轉換為使用者可理解的格式會將使用情況值對應至各個項目的名稱 HID 使用率。

在大部分的 Linux 系統中, 預設值。如要允許 Chrome 開啟 HID 裝置,您必須新增 udev 規則。在 /etc/udev/rules.d/50-yourdevicename.rules 中建立檔案,並使用 以下內容:

KERNEL=="hidraw*", ATTRS{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"

在上述的行中,如果您的裝置是 Nintendo Switch,[yourdevicevendor]057e 例如 Joy-Con。也可以新增 ATTRS{idProduct} 的 規則。請確認您的 userplugdev 群組的成員。接著, 重新連結裝置。

瀏覽器支援

WebHID API 支援所有電腦平台 (ChromeOS、Linux、macOS、 和 Windows)。

示範

部分 WebHID 示範列於 web.dev/hid-examples。去看看吧!

安全性和隱私權

規格作者根據核心架構設計並實作 WebHID API 控管強大的 Web Platform 功能存取權中定義的原則, 包括使用者控制權、資訊公開以及人因工程學透過這項功能 API 主要由權限模型控管,該模型僅會將存取權授予單一 一次 HID 裝置。如要回應使用者提示,使用者必須主動操作 來選取特定 HID 裝置

如要瞭解安全性的取捨,請參閱安全性和隱私權 WebHID 規格的注意事項一節。

此外,Chrome 會檢查每個頂層集合的使用情形,以及是否 頂層集合具有受保護的用途 (例如一般鍵盤和滑鼠), 網站將無法傳送及接收您在該報表 集合。受保護使用的完整清單已對外開放

注意:具安全性疑慮的 HID 裝置 (例如用於 FIDO HID 裝置) Chrome 也會封鎖強度更高的驗證方式。請參閱 USB 封鎖清單HID 封鎖清單檔案。

意見回饋

Chrome 小組很想聽聽您的想法和使用經驗 WebHID API。

請與我們分享 API 設計

是否有 API 未正常運作?或者在那裡

前往 WebHID API GitHub 存放區提出規格問題,或寫下自己的想法 現有問題。

回報導入問題

您發現 Chrome 實作錯誤嗎?另一種是實作 該怎麼辦?

請參閱這篇文章,瞭解如何回報 WebHID 錯誤。請務必盡量附上 請盡可能詳細說明,提供重現錯誤的簡單操作說明,並請 元件設為 Blink>HIDGlitch 適用於以下情境: 輕鬆快速地做出反應

顯示支援

您是否打算使用 WebHID API?你的公開支援能協助 Chrome 讓功能優先處理,並向其他瀏覽器供應商說明其重要性 對他們提供支援

使用主題標記將推文傳送至 @ChromiumDev #WebHID 告訴我們 瞭解您使用了哪些應用程式

實用連結

特別銘謝

感謝 Matt ReynoldsJoe Medley。 由 Sara Kurfe 更快 搭配黑色和銀色筆記型電腦製成的紅色與藍色 Nintendo Switch 相片 由 Athul Cyriac Ajay 分享的 Unsplash 網站上。