WebHID API

社区组报告草案

最新发布版本:
最新编辑草案:
https://wicg.github.io/webhid/
编辑:
Matt Reynolds (谷歌)
反馈:
GitHub WICG/webhid (拉取请求, 新建问题, 开放问题)

摘要

本文档描述了一种 API,用于访问支持人机接口设备 (HID) 协议的设备。

文档状态

本规范由 Web 平台孵化社区组发布。它不是 W3C 标准,也不在 W3C 标准轨道上。 请注意,根据 W3C 社区贡献者许可协议 (CLA),存在有限的选择退出权利,且适用其它条件。 了解更多关于 W3C 社区与业务组的信息。

关于此规范的讨论,请优先通过 GitHub Issues 进行。

1. 引言

本节为非规范性内容。

HID(人机接口设备)是一种用于人类输入或输出的设备类型。它也指 HID 协议,这是一种主机与设备之间双向通信的标准,旨在简化安装过程。HID 协议最初为 USB 设备开发,但如今已经在包括蓝牙等多种协议上实现。

Web 平台已支持许多 HID 设备输入。键盘、定位设备和游戏手柄通常都基于 HID 协议实现。不过,这种支持依赖于操作系统的 HID 驱动程序,该驱动程序将 HID 输入转换为高级输入 API。不被主机 HID 驱动很好支持的设备网页通常无法访问。同样,多数设备上的输出如果主机 HID 驱动不支持,网页也无法访问。

另请参阅相关的 解释文档

2. 应用动机

本节为非规范性内容。

2.1 小众设备

最常见类别的 HID 输入设备已经通过现有的高级输入 API 在 Web 平台上得到了很好的支持。例如,鼠标输入可通过 PointerEvent 访问, 键盘输入可通过 KeyboardEvent 访问。这些设备的输入由主机的本地 HID 驱动程序处理,通常不需要特定设备驱动或配置即可正常工作。WebHID 并不旨在覆盖这些已通过高级输入 API 得到很好支持的设备。

对于某些类别的 HID 设备,Web 平台仅支持其部分功能,而对其他功能则限制访问。例如, [GAMEPAD] 支持大多数游戏控制器的输入功能,但不支持 LED 指示灯或音频等较少见的功能。这些功能往往在主机 API 中得不到很好的支持,在用户代理中增加支持又会导致实现复杂度大幅上升。当高级 API 提供的功能不完整时,WebHID 为应用提供了替代方案。

许多 HID 设备无法通过任何 Web 平台 API 得到支持。HID 规范描述了可以用 HID 支持的广泛设备类型,包括虚拟现实控制器、飞行模拟器、医疗设备等。WebHID 允许这些设备在无需增加驱动或修改用户代理的情况下被使用。

2.2 原型制作、爱好者与教育设备

对于原型开发和爱好者应用,HID 很有吸引力,因为它允许设备使用主机的通用 HID 驱动,无需为每个主机编写特定驱动。简化的安装过程也使得教育工作者无需修改每台主机系统配置即可向一组学生部署设备。通过 Web 平台提供对 HID 设备的访问,将进一步降低安装需求,尤其针对目前仅支持主机专用应用的设备。

3. 安全与隐私注意事项

本节为非规范性内容。

3.1 滥用对设备的访问

HID 外设可能暴露许多强大的功能,不应在未经用户明确同意的情况下让页面访问它们。例如,某些 HID 外设可能带有传感器,可采集其周围环境信息。某些设备也可能存储不应泄露或被覆盖的私有信息。许多设备允许固件升级。操作系统通常不限制应用程序访问 HID 设备,这种访问有时可能被滥用于损坏设备或破坏设备上的数据。

某些情况下,设备可能暴露的功能完全不应被网页访问。可以通过识别 厂商 ID产品 ID 屏蔽特定设备,在枚举时隐藏它们。报告描述符 允许设备自行描述其能力,这些信息也可用于屏蔽某些类别的设备,即使事先无法得知厂商 ID 或产品 ID。 这可以通过检查 HID usage 值完成;例如, 通过拒绝包含键盘用途 顶级集合 的设备以禁止对类键盘设备的访问。

为减少滥用,设备在用户未明确授权前不会提供给页面访问。页面须先发起请求,用户在选择器中选择某个可用设备后方可授予访问权限。页面被授权后,应有可见指示器提示设备正被使用。

3.2 攻击设备

HID 协议极其多样,很多设备得益于这种多样性。因此,访问设备可能让恶意页面损坏该设备。HID 外设允许通过自定义 HID 报文进行固件升级尤为常见。设备制造商必须确保固件升级机制验证固件的真实性,也应防止能够降低安全性的回退升级。未受信任的升级可被用于为设备增加新功能,甚至让设备伪装成另一种设备。

某些设备如果收到超出预期范围的输入可能会损坏。例如,网页向游戏手柄发送无效震动命令时,其震动马达可能损坏。

总体而言,这类攻击具备设备依赖性,并不能在 API 层面缓解。

3.3 攻击主机

如果恶意页面获得设备访问权限,有时可用于攻击主机。最大担忧在于设备能否生成可信输入事件。这些事件可作为用户意图的代理,从而访问更多强大的 Web 平台功能。

鼠标和键盘通常以 HID 外设实现,也可生成可信输入。HID 键盘或鼠标可能带有可编程宏,支持存储输入序列并在之后回放。设备厂商应特别注意此类功能,以防止恶意应用重新编程为异常输入序列,也要防止未经用户明确同意触发宏回放。

3.4 缓解措施

为缓解安全和隐私风险,建议用户代理实现基于选择器的设备授权流程。当页面请求访问 HID 设备时,用户代理应弹出对话框通知用户页面希望访问设备。对话框应展示所有已连接的 HID 设备,并让用户选择要开放给页面的设备。为减少误操作风险,该对话应要求用户在列表选择设备后再次确认并关闭对话框。

4. Navigator 接口扩展

WebIDL[SecureContext] partial interface Navigator {
    [SameObject] readonly attribute HID hid;
};

4.1 hid 属性

读取时,hid 属性始终返回同一个 HID 对象实例。

5. WorkerNavigator 接口扩展

WebIDL[Exposed=(DedicatedWorker,ServiceWorker), SecureContext]
partial interface WorkerNavigator {
    [SameObject] readonly attribute HID hid;
};

5.1 hid 属性

读取时,hid 属性始终返回同一个 HID 对象实例。

6. HID 接口

WebIDL[Exposed=(DedicatedWorker,ServiceWorker,Window), SecureContext]
interface HID : EventTarget {
    attribute EventHandler onconnect;
    attribute EventHandler ondisconnect;
    Promise<sequence<HIDDevice>> getDevices();
    [Exposed=Window] Promise<sequence<HIDDevice>> requestDevice(
        HIDDeviceRequestOptions options);
};
Note

Navigator相关全局对象ServiceWorkerGlobalScope 时, 用户代理的实现可以选择有条件地暴露 hid 属性。例如,在 [browserext] 的 浏览器扩展上下文 中。

HID 的实例带有下表所述的内部槽创建:

内部槽 初始值 说明(非规范性)
[[devices]] 一个空的 有序集合 一个由 HIDDevice 实例组成的 有序集合,表示系统当前可用的 HID 接口
onconnect 属性
onconnect 是用于 connect 事件类型的 事件处理程序 IDL 属性
ondisconnect 属性
ondisconnect 是用于 disconnect 事件类型的 事件处理程序 IDL 属性

当系统上某个 HID 接口变为可用时,执行以下步骤:

Note

HID interface 是一种逻辑接口,可用于通过 HID 协议与设备通信。每个 HID interface 都恰好有一个描述该接口支持的报文集合的 report descriptor。单个物理设备 可能暴露多个 HID interface。拥有多个 HID interface 的设备应对每个接口各自运行这些步骤。

例如,USB 设备由一组接口构成,每个接口可指定一个接口类。当某设备具有多个使用 HID 类的 USB 接口时,每个接口都会作为独立的 HID interface 进行枚举。

  1. device 为一个 HIDDevice
  2. device.[[vendorId]] 设为暴露该接口的设备的 厂商 ID
  3. device.[[productId]] 设为暴露该接口的设备的 产品 ID
  4. device.[[productName]] 设为暴露该接口的设备的 产品名称
  5. device.[[collections]] 设为 解析报告描述符 的结果。
  6. device相关全局对象Window 对象,则令 hid 为调用该对象的 hid getter 的结果;否则令其为调用 WorkerNavigator 对象的 hid getter 的结果。
  7. device 追加hid.[[devices]]
  8. 如果由于之前调用 requestDevice(),用户已允许站点访问 device,则在 hid相关全局对象 上, 使用 HID 设备任务源 触发一个名为 connect 的事件到 hid,并使用 HIDConnectionEvent, 其 device 属性初始化为 device

解析报告 描述符,执行以下步骤:

Note

系统通常会在设备首次连接时,为每个 HID interface 读取 report descriptor字节序列,并将其值缓存在系统注册表中。 如果 report descriptor 不可用,但系统提供了可用于重建每个报文布局的信息, 用户代理可以使用替代算法,而不是解析 report descriptor

report descriptor 的格式见 [USBIF-HID-CLASS] 第 6.2.2 节。下述算法旨在实现该节中所描述的同一解析算法。

report descriptor 包含三类条目。Main items 用于定义和分组数据字段。Global itemsLocal items 用于描述数据字段。 Local items 定义仅适用于下一个 Main item 的特性,而 Global items 定义影响其后所有 Main items 的特性。

每个条目都有一个 item data field,包含与该条目关联的 0、1、2 或 4 个字节的数据, 以及一个 bSize field 用于描述存储 item data field 所用的字节数。每个条目还有一个标记用于标识其类型。

  1. items 为将 report descriptor字节序列 转换为一个 列表 的结果, 该列表由 Main itemsGlobal itemsLocal items 组成。
  2. collections 初始化为空的 sequence,元素类型为 HIDCollectionInfo
  3. ancestors 初始化为空 列表
  4. localState 初始化为空 有序映射
  5. usages 初始化为空的 sequenceunsigned long)。
  6. stringIndices 初始化为空 列表
  7. globalStack 初始化为空
  8. initialGlobalState 初始化为空 有序映射
  9. reportId 设为 0。
  10. initialGlobalState["unitSystem"] 设为 "none"。
  11. initialGlobalState["unitExponent"] 设为 0。
  12. initialGlobalState["unitFactorLengthExponent"] 设为 0。
  13. initialGlobalState["unitFactorMassExponent"] 设为 0。
  14. initialGlobalState["unitFactorTimeExponent"] 设为 0。
  15. initialGlobalState["unitFactorTemperatureExponent"] 设为 0。
  16. initialGlobalState["unitFactorCurrentExponent"] 设为 0。
  17. initialGlobalState["unitFactorLuminousIntensityExponent"] 设为 0。
  18. initialGlobalState["logicalMinimum"] 设为 0。
  19. initialGlobalState["logicalMaximum"] 设为 0。
  20. initialGlobalState["physicalMinimum"] 设为 0。
  21. initialGlobalState["physicalMaximum"] 设为 0。
  22. 压入 initialGlobalStateglobalStack
  23. 对每个 item(属于 items):
    Note

    Main items 在 [USBIF-HID-CLASS] 第 6.2.2.4 至 6.2.2.6 节中描述。带有 Input tagOutput tagFeature tag 的条目定义输入、输出或功能报文中的一个字段。 具有 Input tagOutput tagFeature tagMain itemitem data field 是一个位字段,包含若干布尔参数用于描述该数据字段。带有 Collection tag 的条目会在当前集合内定义一个新集合, 若不存在当前集合则定义一个新的 顶级集合。 带有 Collection tagMain itemitem data field 包含 collection type。带有 End Collection tag 的条目会关闭当前集合。

要使用 itemlocalStateglobalStateusagesstringIndices 创建 HID 报告项,执行以下步骤:

  1. reportItem新的 HIDReportItem 字典。
  2. valueitem data field 作为 unsigned long 解释的结果。
  3. bitfield 为一个 列表,其布尔值自低位起表示 value 的各位。
  4. reportItem["isConstant"] 设为 bitfield[0]。
  5. reportItem["isArray"] 设为 !bitfield[1]。
  6. reportItem["isAbsolute"] 设为 !bitfield[2]。
  7. reportItem["wrap"] 设为 bitfield[3]。
  8. reportItem["isLinear"] 设为 !bitfield[4]。
  9. reportItem["hasPreferredState"] 设为 bitfield[5]。
  10. reportItem["hasNull"] 设为 bitfield[6]。
  11. reportItem["isVolatile"] 设为 bitfield[7]。
  12. reportItem["isBufferedBytes"] 设为 bitfield[8]。
  13. reportItem["usages"] 设为 usages
  14. reportItem["reportSize"] 设为 globalState["reportSize"]。
  15. reportItem["reportCount"] 设为 globalState["reportCount"]。
  16. reportItem["unitExponent"] 设为 globalState["unitExponent"]。
  17. reportItem["unitSystem"] 设为 globalState["unitSystem"]。
  18. reportItem["unitFactorLengthExponent"] 设为 globalState["unitFactorLengthExponent"]。
  19. reportItem["unitFactorMassExponent"] 设为 globalState["unitFactorMassExponent"]。
  20. reportItem["unitFactorTimeExponent"] 设为 globalState["unitFactorTimeExponent"]。
  21. reportItem["unitFactorTemperatureExponent"] 设为 globalState["unitFactorTemperatureExponent"]。
  22. reportItem["unitFactorCurrentExponent"] 设为 globalState["unitFactorCurrentExponent"]。
  23. reportItem["unitFactorLuminousIntensityExponent"] 设为 globalState["unitFactorLuminousIntensityExponent"]。
  24. reportItem["logicalMinimum"] 设为 globalState["logicalMinimum"]。
  25. reportItem["logicalMaximum"] 设为 globalState["logicalMaximum"]。
  26. 如果 usageMinimum 存在于 localState 中,则将 reportItem["usageMinimum"] 设为 localState["usageMinimum"]。

  27. 如果 usageMaximum 存在于 localState 中,则将 reportItem["usageMaximum"] 设为 localState["usageMaximum"]。

  28. reportItem["usageMinimum"] 小于 reportItem["usageMaximum"] 时, 将 reportItem["isRange"] 设为 true, 否则设为 false
  29. 如果 "stringMinimum""stringMaximum" 同时存在于 localState 中:
    1. 追加 范围localState["stringMinimum"] 到 localState["stringMaximum"] 的 条目stringIndices
  30. 对每个 属于 stringIndicesstringIndex
    1. string 为读取索引 stringIndex 处字符串描述符的结果。
    2. 追加 stringreportItem["strings"]。
  31. 返回 reportItem

当系统上某个 HID 接口变为不可用时,执行以下步骤:

  1. devicehid.[[devices]] 中表示该接口的 HIDDevice
  2. device相关 全局对象Window 对象,则令 hid 为调用该对象的 hid getter 的结果;否则令其为调用 WorkerNavigator 对象的 hid getter 的结果。
  3. hid.[[devices]] 移除 device
  4. 如果由于之前调用 requestDevice(),用户已允许站点访问 device,则在 hid相关全局对象 上, 使用 HID 设备任务源 触发一个名为 disconnect 的事件到 hid, 并使用 HIDConnectionEvent, 其 device 属性初始化为 device

6.1 getDevices() 方法

getDevices() 方法的步骤为:

  1. promise一个新的 promise
  2. documentnull
  3. 如果 this相关全局对象DedicatedWorkerGlobalScope 或者 window 对象,则将 document 设为 this相关全局对象关联 Document
  4. 如果 this相关全局对象ServiceWorkerGlobalScope 对象,且其关联的 service worker 客户端window client,则将 document 设为该关联 service worker 客户端全局对象关联 Document
  5. 如果 documentnull,或 document 不被 允许使用 名为 "hid"策略控制特性,则拒绝 promise,错误为 "SecurityError" DOMException,并返回 promise
  6. 并行 运行以下步骤:
    1. devices 为一个空的 sequence(元素类型为 HIDDevice)。
    2. 对每个 属于 this[[devices]]device
      1. 如果由于之前调用 requestDevice(), 用户已允许站点访问 device,且 device[[state]] 不为 "forgotten",则 追加 devicedevices
    3. 相关全局对象 (属于 this)上,使用 HID 设备任务源 解析 promise,其值为 devices
  7. 返回 promise

6.2 requestDevice() 方法

Note

requestDevice() 权限对话框会展示已连接设备列表,并请求用户选择一个。

如果某设备具有多个 HID 接口,则对话框 可以(MAY) 仅展示一个代表所有接口的条目。当用户选择代表多个 HID 接口 的条目时,用户代理 必须(MUST) 授予对该设备所暴露的所有 HID 接口 的访问权限。

requestDevice() 方法的步骤为:

  1. promise一个新的 promise
  2. 如果 this相关全局对象关联 Document 不被 允许使用 名为 "hid"策略控制特性,则 拒绝 promise,错误为 "SecurityError" DOMException,并返回 promise
  3. 如果 相关全局对象 (属于 this)不是 window, 则 拒绝 promise,错误为 "NotSupportedError" DOMException,并返回 promise
  4. 如果 相关全局对象 (属于 this)不具有 瞬态激活, 则 拒绝 promise,错误为 "SecurityError" DOMException,并返回 promise
  5. 如果 options["filters"] 存在, 则 对每个 属于 options["filters"] 的 filter 运行以下步骤:
    1. 如果 filter 不是 有效的过滤器, 则 拒绝 promise,错误为 TypeError, 并返回 promise
  6. 如果 options["exclusionFilters"] 存在,则运行以下步骤:
    1. 如果 options["exclusionFilters"] 为空,则 拒绝 promise,错误为 TypeError, 并返回 promise
    2. 对每个 属于 options["exclusionFilters"] 的 exclusionFilter
      1. 如果 exclusionFilter 不是 有效的过滤器, 则 拒绝 promise,错误为 TypeError, 并返回 promise
  7. 并行 运行以下步骤:
    1. availableDevices 初始化为空 列表
    2. 对每个 属于 this[[devices]]device
      1. 如果 device 匹配任一过滤器(属于 options["filters"]),且 device匹配任一过滤器(属于 options["exclusionFilters"]), 则 追加 deviceavailableDevices
    3. 通过展示 availableDevices 中的设备列表,提示用户授予站点对某个 HID 设备的访问权限。
      Note
      用户代理可在展示前修改设备列表。例如,具有多个 HID 接口 的设备 应当(SHOULD) 以单个条目表示,使得选择该条目即授予对设备暴露的所有接口的访问权限。 设备是以单个接口还是接口集合实现属于实现细节,用户可能并不知晓,不应作为设备访问权限的相关考量。
    4. devices 为一个空的 sequence(元素类型为 HIDDevice)。
    5. 如果用户未选择设备,则 相关全局对象 (属于 this)上,使用 HID 设备任务源 解析 promise,其值为 devices,并中止这些步骤。
    6. 对每个 属于 this[[devices]]device
      1. 如果 device 表示被选中设备所暴露的 HID 接口,则将 device[[state]] 设为 "closed",并 追加 devicedevices
    7. 相关全局对象 (属于 device)上,使用 HID 设备任务源 解析 promise,其值为 devices
  8. 返回 promise

6.2.1 HIDDeviceRequestOptions 字典

WebIDLdictionary HIDDeviceRequestOptions {
    required sequence<HIDDeviceFilter> filters;
    sequence<HIDDeviceFilter> exclusionFilters;
};
filters 成员
HID 设备的过滤器。
exclusionFilters 成员
HID 设备的排除过滤器。

6.2.2 HIDDeviceFilter 字典

WebIDLdictionary HIDDeviceFilter {
    unsigned long vendorId;
    unsigned short productId;
    unsigned short usagePage;
    unsigned short usage;
};
vendorId 成员
用于匹配的 厂商 ID(vendor ID)
productId 成员
用于匹配的 产品 ID(product ID)。如果未提供 vendorId 成员,则忽略 productId
usagePage 成员
用于匹配的 顶级集合usage page
usage 成员
用于匹配的 顶级集合usage ID。如果未提供 usagePage 成员, 则忽略 usage
Note

设备过滤器用于缩小在 requestDevice() 创建的选择器对话框中展示给用户的设备列表。 当未提供任何过滤器时,包含所有未匹配任何排除过滤器的已连接设备。 当提供一个或多个过滤器时,若任一过滤器匹配且没有排除过滤器匹配,则包含该设备。

所有 HIDDeviceFilter 成员均为可选。每个成员指定一条规则。要匹配一个 HIDDeviceFilter,必须满足其每一条规则。 一个空的 HIDDeviceFilter 将匹配任意设备。

设备 ID 规则用于根据设备的 厂商 ID产品 ID 选择设备。 当应用仅设计用于某个特定设备,或依赖厂商特定功能时,这很有用。包含 vendorId 规则会使过滤器仅匹配具有指定 厂商 ID 的设备。 如果同时包含 productId 规则,则过滤器仅匹配具有指定 厂商 ID产品 ID 的设备。若 productId 被指定但未指定 vendorId 规则,则忽略 productId

Usage 规则用于根据分配给设备 顶级集合HID usages 选择设备。 当应用设计用于一类标准设备时,这很有用。要匹配某个设备,至少有一个集合必须满足每条 usage 规则。 包含 usagePage 规则会使过滤器仅在设备包含具有指定 usage page 的集合时匹配。 如果同时包含 usage 规则,则过滤器仅匹配具有指定 usage pageusage ID 的设备。 若 usage 被指定但未指定 usagePage 规则,则忽略 usage

设备 ID 规则与 usage 规则可以组合使用。例如,应用可能希望匹配某个特定厂商的设备,但仅限实现了某个特定设备类别的设备。

exclusionFilters 选项允许应用从 由 requestDevice() 创建的选择器对话框中,排除某些已知不能按预期工作的设备,即便它们实现了某个特定设备类别。

当且仅当以下步骤返回 trueHIDDeviceFilterfilter 才是有效的过滤器

  1. 如果 filter 为空,则返回 false
  2. 如果 filter["productId"] 存在而 filter["vendorId"] 不存在,则返回 false
  3. 如果 filter["usage"] 存在而 filter["usagePage"] 不存在,则返回 false
  4. 返回 true

当且仅当以下步骤返回 trueHIDDevicedevice sequence filtersHIDDeviceFilter 的任一过滤器 匹配任一过滤器

  1. 如果 filters 为空,则返回 true
  2. 对每个 属于 filtersfilter
    1. 如果 filter 匹配设备 ID(属于 device),并且 filter 匹配任一集合(属于 device),则返回 true
  3. 返回 false

当且仅当以下步骤返回 trueHIDDeviceFilterfilter 匹配设备 ID(属于 device):

  1. 如果 filter 中包含 "vendorId":
    1. 如果 filter["vendorId"] 不等于 devicevendorId,则返回 false
    2. 如果 filter 中包含 "productId",且 filter["productId"] 不等于 deviceproductId,则返回 false
  2. 返回 true

当且仅当以下步骤返回 trueHIDDeviceFilterfilter 匹配任一集合(属于 device):

  1. 对每个 属于 device.collectionscollection
    1. 如果 filter 匹配集合 collection,则返回 true
  2. 返回 false

当且仅当以下步骤返回 trueHIDDeviceFilterfilter 匹配集合 collection

  1. 如果 filter 中包含 "usagePage":
    1. 如果 filter["usagePage"] 不等于 collectionusagePage,则返回 false
    2. 如果 filter 中包含 "usage",且 filter["usage"] 不等于 collectionusage,则返回 false
  2. 返回 true

7. HIDDevice 接口

WebIDL[Exposed=(DedicatedWorker,ServiceWorker,Window), SecureContext]
interface HIDDevice : EventTarget {
    attribute EventHandler oninputreport;
    readonly attribute boolean opened;
    readonly attribute unsigned short vendorId;
    readonly attribute unsigned short productId;
    readonly attribute DOMString productName;
    readonly attribute FrozenArray<HIDCollectionInfo> collections;
    Promise<undefined> open();
    Promise<undefined> close();
    Promise<undefined> forget();
    Promise<undefined> sendReport([EnforceRange] octet reportId, BufferSource data);
    Promise<undefined> sendFeatureReport(
        [EnforceRange] octet reportId,
        BufferSource data);
    Promise<DataView> receiveFeatureReport([EnforceRange] octet reportId);
};

此接口上的方法通常异步完成,在 HID 设备任务源 上排队工作。

HIDDevice 的实例带有下表所述的内部槽创建:

内部槽 初始值 说明(非规范性)
[[state]] "closed" 跟踪 HIDDevice 的活动状态
[[vendorId]] 0 设备的 vendor ID
[[productId]] 0 设备的 product ID
[[productName]] "" 设备的 product name
[[collections]] 一个空的 sequence(元素类型为 HIDCollectionInfo 解析报告描述符 创建的 顶级集合
[[pendingSendReportPromises]] 一个空的 list 挂起的 sendReport() Promise
[[pendingSendFeatureReportPromises]] 一个空的 list 挂起的 sendFeatureReport() Promise
[[pendingReceiveFeatureReportPromises]] 一个空的 list 挂起的 receiveFeatureReport() Promise
oninputreport 属性
oninputreport事件处理程序 IDL 属性, 用于 inputreport 事件类型。
opened 属性

指示 HIDDevice 已准备好传输数据的标志。

opened getter 的步骤为:

  1. 如果 this.[[state]]opened,则返回 true
  2. 返回 false
vendorId 属性

vendor ID 是由厂商 ID 来源分配的 unsigned short 值,用于标识设备制造商。

vendorId 属性是设备的 vendor ID。如果设备没有 vendor ID 或无法访问该 vendor ID,则该属性 必须(MUST) 为 0。

vendorId getter 的步骤为:

  1. 返回 this.[[vendorId]]
productId 属性

product ID 是由设备制造商分配的 unsigned short 值,用于标识产品。

productId 属性是设备的 product ID。如果设备没有 product ID 或无法访问该 product ID,则该属性 必须(MUST) 为 0。

productId getter 的步骤为:

  1. 返回 this.[[productId]]
productName 属性

标识产品的字符串。

对于 USB HID 设备,product name 应当(SHOULD) 包含设备描述符中 iProduct 索引处字符串描述符的值。对于蓝牙 HID 设备,product name 应当(SHOULD) 包含设备名称(Device Name)特征的值。 如果设备没有 product name,或 product name 为空或无法访问,则该属性 必须(MUST) 返回空字符串。

productName 字符串 不应(SHOULD NOT) 包含任何可用于唯一标识设备的标识符,如序列号或蓝牙设备地址。

productName getter 的步骤为:

  1. 返回 this.[[productName]]
collections 属性

一个 sequence(元素类型为 HIDCollectionInfo),表示 report descriptor 中的 顶级集合

collections getter 的步骤为:

  1. 返回 this.[[collections]]
Note
顶级集合 用于分组设备内用途相似的条目。 应用会查看应用于 顶级集合HID usage 来识别设备。 如果设备未遵循特定设备类型的惯例,应用可能无法识别该设备。有关标准 HID 设备的常规行为的更多信息,请参阅 [USBIF-HID-USAGE]。

当从一个 device 收到输入报告时,执行以下步骤:

  1. 如果该输入报告是一个 被阻止的报告(blocked report),则中止这些步骤。
  2. reportId 为此报告的报告 ID;如果该 HID 接口使用报告 ID, 则为 0。
  3. data 为在表示该输入报告的 字节序列 之上创建的 DataView。 如果该 HID 接口 使用报告 ID,则该 字节序列 不得(MUST NOT) 包含报告 ID 字节。
  4. 在相关全局对象上队列一个全局任务(属于 this), 使用 HID 设备任务源 触发事件 名为 inputreport,目标为 device, 事件类型为 HIDInputReportEvent,其 device 属性初始化为 devicereportId 属性初始化为 reportIddata 属性初始化为 data

7.1 open() 方法

open() 方法的步骤为:

  1. promise一个新的 promise
  2. 如果 this.[[state]] 不是 "closed",则 拒绝 promise,错误为 "InvalidStateError" DOMException, 并返回 promise
  3. this.[[state]] 设为 "opening"
  4. 并行 执行以下步骤:
    1. 调用操作系统打开该 HID 设备。
    2. 如果因任何原因失败,在相关全局对象上队列一个全局任务 (属于 this),使用 HID 设备任务源 拒绝 promise,错误为 "NetworkError" DOMException,并中止这些步骤。
    3. this.[[state]] 设为 "opened"
    4. 在相关全局对象上队列一个全局任务 (属于 this),使用 HID 设备任务源 解析 promise,其值为 undefined
  5. 返回 promise

7.2 close() 方法

close() 方法的步骤为:

  1. promise一个新的 promise
  2. 如果 this.[[state]]"forgotten""forgetting",则 拒绝 promise,错误为 "InvalidStateError" DOMException,并返回 promise
  3. this.[[state]] 设为 "closing"
  4. 对于每个 属于 this[[pendingSendReportPromises]]pendingPromise
    1. 拒绝 pendingPromise,错误为 "AbortError" DOMException
  5. 清空(Empty) this[[pendingSendReportPromises]]
  6. 对于每个 属于 this[[pendingSendFeatureReportPromises]]pendingPromise
    1. 拒绝 pendingPromise,错误为 "AbortError" DOMException
  7. 清空(Empty) this[[pendingSendFeatureReportPromises]]
  8. 对于每个 属于 this[[pendingReceiveFeatureReportPromises]]pendingPromise
    1. 拒绝 pendingPromise,错误为 "AbortError" DOMException
  9. 清空(Empty) this[[pendingReceiveFeatureReportPromises]]
  10. 并行 执行以下步骤:
    1. 调用操作系统关闭该 HID 设备并释放所有相关资源。
    2. this.[[state]] 设为 "closed"
    3. 在相关全局对象上队列一个全局任务 (属于 this),使用 HID 设备任务源 解析 promise,其值为 undefined
  11. 返回 promise

7.3 forget() 方法

Note

用户代理 可以(MAY) 决定在多个 API 间合并权限,例如将 WebHID + WebUSB 设备访问统一为一种低级设备访问权限。 因此,该方法将来也可能同时撤销其他(尚未指定的)权限。

forget() 方法的步骤为:

  1. promise一个新的 promise
  2. 并行 执行以下步骤:
    1. 对于每个 属于 this[[devices]]device
      1. 如果 device 未与该 HIDDevice 共享设备访问权限,则继续处理下一个设备。
      2. device[[state]] 设为 "forgetting"
      3. 对于每个 属于 device[[pendingSendReportPromises]]pendingPromise
        1. 拒绝 pendingPromise,错误为 "AbortError" DOMException
      4. 清空(Empty) device[[pendingSendReportPromises]]
      5. 对于每个 属于 device[[pendingSendFeatureReportPromises]]pendingPromise
        1. 拒绝 pendingPromise,错误为 "AbortError" DOMException
      6. 清空(Empty) device[[pendingSendFeatureReportPromises]]
      7. 对于每个 属于 device[[pendingReceiveFeatureReportPromises]]pendingPromise
        1. 拒绝 pendingPromise,错误为 "AbortError" DOMException
      8. 清空(Empty) device[[pendingReceiveFeatureReportPromises]]
      9. 调用用户代理撤销对 device 所暴露的所有 HID 接口 的访问权限。
      10. device[[state]] 设为 "forgotten"
    2. 在相关全局对象上队列一个全局任务 (属于 this),使用 HID 设备任务源 解析 promise,其值为 undefined
  3. 返回 promise

7.4 sendReport() 方法

Note

sendReport() 方法用于发送具有指定 reportIddata 的输出报告。 如果该 HID 接口使用报告 ID,则传递 0 代替报告 ID。

对于 使用报告 IDuse report IDs)的 HID 接口,报告 ID 值 0 保留,且不应使用。

sendReport() 方法的步骤为:

  1. promise一个新的 promise
  2. 如果 this.[[state]] 不是 "opened",则 拒绝 promise,错误为 "InvalidStateError" DOMException, 并返回 promise
  3. 如果 reportId 为 0 且 该接口(由 this 表示) 使用报告 ID, 或 reportId 不为 0 且该接口不 使用报告 ID, 则 拒绝 promise,错误为 "TypeError" DOMException,并返回 promise
  4. 追加(Append) promisethis[[pendingSendReportPromises]]
  5. 并行 执行以下步骤:
    1. 如果该报告是一个 被阻止的报告(blocked report), 则在相关全局对象上队列一个全局任务 (属于 this),使用 HID 设备任务源 拒绝 promise,错误为 "NotAllowedError" DOMException, 并中止这些步骤。
    2. 调用操作系统发送具有指定 reportIddata 的输出报告。
    3. 如果因任何原因失败,在相关全局对象上队列一个全局任务 (属于 this),使用 HID 设备任务源 拒绝 promise,错误为 "NetworkError" DOMException, 并中止这些步骤。
    4. 在相关全局对象上队列一个全局任务 (属于 this),使用 HID 设备任务源 解析 promise,其值为 undefined
  6. 返回 promise

7.5 sendFeatureReport() 方法

Note

sendFeatureReport() 方法用于发送具有指定 reportIddata 的功能报告(feature report)。如果该 HID 接口使用报告 ID,则传递 0 代替报告 ID。

对于 使用报告 IDuse report IDs)的 HID 接口,报告 ID 值 0 保留,且不应使用。

sendFeatureReport() 方法的步骤为:

  1. promise一个新的 promise
  2. 如果 this.[[state]] 不是 "opened",则 拒绝 promise,错误为 "InvalidStateError" DOMException, 并返回 promise
  3. 如果 reportId 为 0 且 该接口(由 this 表示) 使用报告 ID, 或 reportId 不为 0 且该接口不 使用报告 ID, 则 拒绝 promise,错误为 "TypeError" DOMException,并返回 promise
  4. 追加(Append) promisethis[[pendingSendFeatureReportPromises]]
  5. 并行 执行以下步骤:
    1. 如果该报告是一个 被阻止的报告(blocked report), 则在相关全局对象上队列一个全局任务 (属于 this),使用 HID 设备任务源 拒绝 promise,错误为 "NotAllowedError" DOMException, 并中止这些步骤。
    2. 调用操作系统发送具有指定 reportIddata 的功能报告。
    3. 如果因任何原因失败,在相关全局对象上队列一个全局任务 (属于 this),使用 HID 设备任务源 拒绝 promise,错误为 "NetworkError" DOMException, 并中止这些步骤。
    4. 在相关全局对象上队列一个全局任务 (属于 this),使用 HID 设备任务源 解析 promise,其值为 undefined
  6. 返回 promise

7.6 receiveFeatureReport() 方法

Note

receiveFeatureReport() 方法用于请求具有指定 reportId 的功能报告。如果该 HID 接口使用报告 ID,则传递 0 代替报告 ID。

对于 使用报告 IDuse report IDs)的 HID 接口,报告 ID 值 0 保留,且不应使用。

receiveFeatureReport() 方法的步骤为:

  1. promise一个新的 promise
  2. 如果 this.[[state]] 不是 "opened",则 拒绝 promise,错误为 "InvalidStateError" DOMException, 并返回 promise
  3. 如果 reportId 为 0 且 该接口(由 this 表示) 使用报告 ID, 或 reportId 不为 0 且该接口不 使用报告 ID, 则 拒绝 promise,错误为 "TypeError" DOMException,并返回 promise
  4. 追加(Append) promisethis[[pendingReceiveFeatureReportPromises]]
  5. 并行 执行以下步骤:
    1. 如果该报告是一个 被阻止的报告(blocked report), 则在相关全局对象上队列一个全局任务 (属于 this),使用 HID 设备任务源 拒绝 promise,错误为 "NotAllowedError" DOMException, 并中止这些步骤。
    2. data 为在表示调用操作系统读取具有指定 reportId 的功能报告所得结果的 字节序列 之上创建的 DataView
      Note
      data 将包含从操作系统接收到的任意报告数据。 如果设备 使用报告 ID, 第一个字节可能是报告 ID。包含该字节是因为设备可能用其他数据替代报告 ID 进行响应。
    3. 如果读取功能报告因任何原因失败,在相关全局对象上队列一个全局任务 (属于 this),使用 HID 设备任务源 拒绝 promise,错误为 "NetworkError" DOMException, 并中止这些步骤。
    4. 在相关全局对象上队列一个全局任务 (属于 this),使用 HID 设备任务源 解析 promise,其值为 data
  6. 返回 promise

8. HIDConnectionEvent 接口

WebIDL[Exposed=(DedicatedWorker,ServiceWorker,Window), SecureContext]
interface HIDConnectionEvent : Event {
    constructor(DOMString type, HIDConnectionEventInit eventInitDict);
    [SameObject] readonly attribute HIDDevice device;
};
device 属性
表示已连接或已断开设备的 HIDDevice 实例。

8.1 HIDConnectionEventInit 字典

WebIDLdictionary HIDConnectionEventInit : EventInit {
    required HIDDevice device;
};
device 成员
与该事件相关联的设备。

9. HIDInputReportEvent 接口

WebIDL[Exposed=(DedicatedWorker,ServiceWorker,Window), SecureContext]
interface HIDInputReportEvent : Event {
    constructor(DOMString type, HIDInputReportEventInit eventInitDict);
    [SameObject] readonly attribute HIDDevice device;
    readonly attribute octet reportId;
    readonly attribute DataView data;
};
device 属性
表示发送输入报告的 HIDDevice 实例,对应的 HID 接口
reportId 属性
此报告的一字节标识前缀;如果 HID 接口使用报告 ID,则为 0。
data 属性
一个 DataView,包含输⼊报告的数据。 如果 HID 接口 使用报告 ID,则排除 reportId 字节。

9.1 HIDInputReportEventInit 字典

WebIDLdictionary HIDInputReportEventInit : EventInit {
    required HIDDevice device;
    required octet reportId;
    required DataView data;
};
device 成员
与事件相关的设备。
reportId 成员
输入报告的报告 ID。
data 成员
输入报告的数据。

10. HIDCollectionInfo 字典

WebIDLdictionary HIDCollectionInfo {
    unsigned short usagePage;
    unsigned short usage;
    octet type;
    sequence<HIDCollectionInfo> children;
    sequence<HIDReportInfo> inputReports;
    sequence<HIDReportInfo> outputReports;
    sequence<HIDReportInfo> featureReports;
};

当设备首次连接到系统时,系统必须(MUST)为设备所暴露的每个HID 接口获取报告描述符(report descriptor)报告描述符是一个字节序列,可以展开为描述设备支持的每个报告布局的分层数据结构。该数据结构的元素称为 item。具有某种关系的一组 item 称为 collection。

HIDCollectionInfo 对象表示 报告描述符 中的一个集合(collection)。当集合中包含嵌套集合时,嵌套集合会作为 children 的元素被包含在内。

inputReportsoutputReportsfeatureReports 属性包含 序列(sequence), 元素类型为 HIDReportInfo,用于描述本集合中的每一个报告。对于顶级集合(top-level collection)HIDReportInfo 表示该报告所有组成项的扁平视图。该视图会将嵌套集合中的 item 与顶级集合本身包含的 item 混合列出。 对于嵌套集合,HIDReportInfo 仅包含该集合及其内部嵌套集合中的 item。

usagePage 成员

本集合关联的 HID usageusage page 部分。

HID usage 是应用可用于识别某个 item 或 collection 目的和含义的常量。 HID usage 是一个 unsigned long,高位为 unsigned shortusage page,低位为 unsigned shortusage ID。标准 HID usage 值见 [USBIF-HID-CLASS] 和 USB 实现者论坛等文档。

设备暴露的 顶级集合HID usage 用于标识设备的大致类型。

usage 成员

本集合关联的 HID usageusage ID 部分。

usage ID 用于在 usage page 上选中某个具体 HID usage。惯例上,0x01~0x1F 号 usage ID 预留给 顶级集合

type 成员

表示集合类型(collection type)的值。

集合类型
物理(Physical) 0x00
应用(Application) 0x01
逻辑(Logical) 0x02
报告(Report) 0x03
命名数组(Named Array) 0x04
用法切换(Usage Switch) 0x05
用法修改(Usage Modified) 0x06
保留以后扩展 0x07 到 0x7F
厂商自定义(Vendor-defined) 0x80 到 0xFF

每种集合类型代表分组 item 间不同的关系。 更多集合类型内容见 [USBIF-HID-CLASS] 6.2.2.6 节。

children 成员
一个 序列(sequence),元素类型为 HIDCollectionInfo,表示本集合内的嵌套集合。
inputReports 成员
一个 序列(sequence), 元素类型为 HIDReportInfo,表示本集合内描述的输入报告。
outputReports 成员
一个 序列(sequence), 元素类型为 HIDReportInfo,表示本集合内描述的输出报告。
featureReports 成员
一个 序列(sequence), 元素类型为 HIDReportInfo,表示本集合内描述的功能报告(feature report)。

11. HIDReportInfo 字典

WebIDLdictionary HIDReportInfo {
    octet reportId;
    sequence<HIDReportItem> items;
};

HIDReportInfo 表示报告描述符中的一个输入、输出或功能报告。

reportId 成员
如果HID 接口使用报告 ID(use report IDs), 则每个报告传输会加上一字节标识前缀。reportId 成员就是该报告的前缀,否则为 0。
items 成员
一个 序列(sequence), 元素类型为 HIDReportItem,表示该报告的所有字段。

12. HIDReportItem 字典

WebIDLdictionary HIDReportItem {
    boolean isAbsolute;
    boolean isArray;
    boolean isBufferedBytes;
    boolean isConstant;
    boolean isLinear;
    boolean isRange;
    boolean isVolatile;
    boolean hasNull;
    boolean hasPreferredState;
    boolean wrap;
    sequence<unsigned long> usages;
    unsigned long usageMinimum;
    unsigned long usageMaximum;
    unsigned short reportSize;
    unsigned short reportCount;
    byte unitExponent;
    HIDUnitSystem unitSystem;
    byte unitFactorLengthExponent;
    byte unitFactorMassExponent;
    byte unitFactorTimeExponent;
    byte unitFactorTemperatureExponent;
    byte unitFactorCurrentExponent;
    byte unitFactorLuminousIntensityExponent;
    long logicalMinimum;
    long logicalMaximum;
    long physicalMinimum;
    long physicalMaximum;
    sequence<DOMString> strings;
};
isAbsolute 成员
如果数据是绝对值(基于固定原点),则为 true,如果数据是相对值(表示与上一个报告数值的变化量),则为 false
isArray 成员
如果该项在报告中创建了数组数据域(每个数据域包含对应按下按钮或键的索引),则为 true; 如果该项创建了变量数据域(每个数据域包含一个数值),则为 false
isBufferedBytes 成员
如果该项发射固定字节流,则为 true,如果该项是一个数值类型,则为 false
isConstant 成员
如果该项是静态只读字段并且不可修改,则为 true,如果该项为可修改设备数据的报告字段,则为 false
isLinear 成员
如果该项表示测量结果与报告结果之间是线性关系,则为 true;如果数据经过处理则为 false
isRange 成员
如果该项为由 usageMinimumusageMaximum 定义的 HID 用法范围赋予用法,则为 true; 如果该项有一个 用法值序列 usages,则为 false
isVolatile 成员

如果项的数值可在主机无交互时改变,则为 true; 如果仅能被主机改变则为 false

仅用于功能项(Feature)和输出项(Output)。

hasNull 成员
如果该项存在空状态(即不发送有意义数据),则为 true;若无空状态则为 false。 处于空状态时,该项会上报超出 logicalMinimumlogicalMaximum 指定范围的值。
hasPreferredState 成员
如果该项有一个偏好状态,当用户未对控件操作时会回到该状态,则为 true;没有偏好状态则为 false
wrap 成员
如果项的数值在达到最大或最小极值时会回卷,则为 true;若不会回卷则为 false
usages 成员

isRangetrue,或此项无关联 HID 用法值,则 usages 必须(MUST) 为 undefined。

isRangefalseusages 是一个 值序列,元素为关联到此项的 HID 用法值。

usageMinimum 成员

isRangetrueusageMinimum 包含本项的用法范围的最小 HID 用法值。

isRangefalseusageMinimum 必须(MUST) 为 undefined。

usageMaximum 成员

isRangetrueusageMaximum 包含本项的用法范围的最大 HID 用法值。

isRangefalseusageMaximum 必须(MUST) 为 undefined。

reportSize 成员
每个报告数据域的位数,reportSize 必须(MUST) 大于 0。
reportCount 成员
本项在报告中包含的字段数,reportCount 必须(MUST) 大于 0。
unitExponent 成员
单位指数值,如果该项没有单位定义则为 0。
unitSystem 成员
HIDUnitSystem 枚举值,指定单位定义的单位制。 若无单位定义,则为 "none"。
unitFactorLengthExponent 成员
单位定义中长度单位(厘米、弧度、英寸或度)的指数值,没有单位定义则为 0。
unitFactorMassExponent 成员
单位定义中质量单位(克或 slug)的指数值,没有单位定义则为 0。
unitFactorTimeExponent 成员
单位定义中时间单位(秒)的指数值,没有单位定义则为 0。
unitFactorTemperatureExponent 成员
单位定义中温度单位(开尔文或华氏度)的指数值,没有单位定义则为 0。
unitFactorCurrentExponent 成员
单位定义中电流单位(安培)的指数值,没有单位定义则为 0。
unitFactorLuminousIntensityExponent 成员
单位定义中光强单位(坎德拉)的指数值,没有单位定义则为 0。
logicalMinimum 成员
该项在逻辑单位中的最小范围。这是变量项或数组项可能上报的最小值。
logicalMaximum 成员
该项在逻辑单位中的最大范围。这是变量项或数组项可能上报的最大值。
physicalMinimum 成员
该项的物理范围最小值,这表示应用了单位后的 logicalMinimum
physicalMaximum 成员
该项的物理范围最大值,这表示应用了单位后的 logicalMaximum
strings 成员
与该项有关的字符串数组。如果无字符串则为一个空的 序列

13. HIDUnitSystem 枚举

[USBIF-HID-CLASS] 第 6.2.2.7 节定义了四种标准单位制:SI 线性、SI 旋转、英制线性和英制旋转。每个条目使用这四种单位制之一、厂商自定义单位制或无单位制。

WebIDLenum HIDUnitSystem {
    "none", "si-linear", "si-rotation", "english-linear",
    "english-rotation", "vendor-defined", "reserved"
};
"none"
无单位制。表示该项没有单位定义。
"si-linear"
SI 线性单位制,采用厘米、克、秒、开尔文、安培、坎德拉。
"si-rotation"
SI 旋转单位制,采用弧度、克、秒、开尔文、安培、坎德拉。
"english-linear"
英制线性单位制,采用英寸、slug、秒、华氏度、安培、坎德拉。
"english-rotation"
英制旋转单位制,采用度、slug、秒、华氏度、安培、坎德拉。
"vendor-defined"
厂商自定义的单位制。
"reserved"
表示设备对于单位制使用了保留值。

14. 用法示例

15. HID 阻止列表

本规范依赖于 https://github.com/WICG/webhid 仓库的阻止列表文件来限制网站可访问的HID设备范围。

对于 URL url解析阻止列表 的结果是获取 url 内容并作为 JSON 解析后得到的一系列字典对象。

HID 阻止列表 即对 解析阻止列表 https://github.com/WICG/webhid/blob/main/blocklist.txt 的结果。

报告满足以下步骤则为 被阻止的报告(blocked report),步骤返回 true

  1. 遍历 HID 阻止列表 中每个 rule
    1. 如果报告 被阻止规则 rule 阻止则 返回 true
  2. 返回 false

报告被 阻止规则阻止(blocked by a blocklist rule) rule 满足下列步骤返回 true

  1. reportId 为此报告的报告 ID,如 HID 接口使用报告 ID 则为 0。
  2. reportType"input"(输入报告)、"output"(输出报告)或 "feature"(功能报告)。
  3. collection 为包含该报告的 顶级集合
  4. rule 包含 "vendor"rule["vendor"] 不等于 device.vendorId,则返回 false
  5. rule 包含 "product"rule["product"] 不等于 device.productId,则返回 false
  6. rule 包含 "reportId"rule["reportId"] 不等于 reportId,则返回 false
  7. rule 包含 "reportType"rule["reportType"] 不等于 reportType,则返回 false
  8. rule 包含 "usagePage"rule["usagePage"] 不等于 collection["usagePage"],则返回 false
  9. rule 包含 "usage"rule.["usage"] 不等于 collection["usage"],则返回 false
  10. 返回 true

16. 集成

16.1 权限策略(Permissions Policy)

本规范定义了一个特性,用于控制 hid 属性是否暴露在 Navigator 对象上。

此特性的名称为 "hid"

该特性的 默认允许列表'self'

17. 符合性

除了被标记为非规范性(non-normative)的章节,所有文档规范中的作者指导、图例、示例和注释均为非规范性内容。除此以外,规范的其它内容均为规范性内容。

本文档中的关键字 MAYMUSTMUST NOTSHOULDSHOULD NOT 应按照 BCP 14 [RFC2119],[RFC8174] 的定义方式进行解释,仅当这些词汇完全大写时才适用本文定义。

A. 致谢

以下人员为本规范文档的发展做出了贡献。

B. 参考文献

B.1 规范性参考文献

[dom]
DOM 标准. Anne van Kesteren. WHATWG. 实时标准. URL: https://dom.spec.whatwg.org/
[html]
HTML 标准. Anne van Kesteren; Domenic Denicola; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. 实时标准. URL: https://html.spec.whatwg.org/multipage/
[infra]
Infra 标准. Anne van Kesteren; Domenic Denicola. WHATWG. 实时标准. URL: https://infra.spec.whatwg.org/
[permissions-policy]
权限策略. Ian Clelland. W3C. 2024年7月24日. W3C 工作草案. URL: https://www.w3.org/TR/permissions-policy-1/
[RFC2119]
RFC 文件中的关键字用法 用以表示需求级别. S. Bradner. IETF. 1997年3月. 最佳当前实践. URL: https://www.rfc-editor.org/rfc/rfc2119
[RFC8174]
RFC2119 关键字的大小写歧义. B. Leiba. IETF. 2017年5月. 最佳当前实践. URL: https://www.rfc-editor.org/rfc/rfc8174
[service-workers]
Service Workers. Jake Archibald; Marijn Kruisselbrink. W3C. 2022年7月12日. W3C 候选推荐标准. URL: https://www.w3.org/TR/service-workers/
[USBIF-HID-CLASS]
人机接口设备(HID)类 1.11 版设备类定义. Mike Bergman 等. USB Implementers Forum. 2001年5月27日. 规范. URL: https://www.usb.org/document-library/device-class-definition-hid-111
[WEBIDL]
Web IDL 标准. Edgar Chen; Timothy Gu. WHATWG. 实时标准. URL: https://webidl.spec.whatwg.org/

B.2 参考性文献

[browserext]
浏览器扩展. Mike Pietraszak. W3C. 2016年10月. 草案社区组报告. URL: https://browserext.github.io/browserext/
[GAMEPAD]
Gamepad. Steve Agoston; Matthew Reynolds. W3C. 2024年8月9日. W3C 工作草案. URL: https://www.w3.org/TR/gamepad/
[pointerevents]
Pointer Events. Jacob Rossi; Matt Brubeck. W3C. 2019年4月4日. W3C 推荐标准. URL: https://www.w3.org/TR/pointerevents/
[uievents]
UI Events. Gary Kacmarcik; Travis Leithead. W3C. 2024年9月7日. W3C 工作草案. URL: https://www.w3.org/TR/uievents/
[USBIF-HID-USAGE]
USB 用 HID 用法表(1.22版). David Abzarian 等. USB Implementers Forum. 2021年4月6日. 规范. URL: https://www.usb.org/document-library/hid-usage-tables-122