HID(Human Interface Device)是面向键盘、鼠标、触控板、游戏手柄、遥控器、扫描枪和控制面板等人机输入/控制设备的一类设备模型和协议体系。
工程上说 HID,通常不是泛指“所有能给人用的设备”,而是指主机能通过标准 HID 类驱动理解的一套设备描述、数据报告和用途语义。常见承载方式有 USB HID、Bluetooth Classic HID 和 HOGP(HID over GATT Profile)。
核心问题
如果每个键盘、鼠标、手柄或扫描枪都要求操作系统安装厂商专用驱动,外设生态会非常脆弱。主机需要一种通用机制来回答:
- 这个设备是键盘、鼠标、手柄,还是厂商自定义控制器?
- 它会上报哪些输入字段,例如按键、坐标、滚轮、触点、摇杆轴?
- 每个字段在字节流中的偏移、长度、单位和含义是什么?
- 哪些数据是设备发给主机,哪些是主机发给设备?
HID 解决的是“设备如何自描述自己的输入/输出数据格式,让通用主机驱动不用为每个厂商重写”的问题。
核心对象
| 对象 | 含义 | 工程关注点 |
|---|---|---|
| HID device | 真实外设或嵌入式设备中的 HID 接口 | 键盘、鼠标、手柄、扫描枪、自定义控制板 |
| HID host | 读取并解释 HID 数据的一方 | PC、手机、平板、主控系统、操作系统 HID 栈 |
| HID Report Descriptor | 描述 report 字节布局和语义的结构 | usage、collection、report size/count、input/output/feature |
| Input report | 设备上报给主机的数据 | 按键状态、鼠标位移、触点坐标、手柄轴值 |
| Output report | 主机下发给设备的数据 | 键盘 LED、震动马达、指示灯、简单控制 |
| Feature report | 配置或状态类双向数据 | 校准、模式、厂商自定义配置 |
| Usage Page / Usage | 字段所属用途和具体含义 | 键盘按键、鼠标按钮、X/Y 轴、Consumer Control |
| Report ID | 区分同一接口内多种 report | 多报告设备必须解析 ID 与长度 |
| Transport | 承载 HID report 的链路 | USB、Bluetooth Classic、BLE GATT、I2C 等 |
HID 的关键思想是:设备不只发“字节”,还要先告诉主机这些字节如何解释。
核心机制
1. 设备先暴露描述信息
以 USB HID 为例,主机枚举设备时会读取设备、配置、接口、HID 类描述符和 report descriptor。report descriptor 告诉主机后续 report 的结构。流程可以简化为:
device connected
-> host enumerates interface
-> host reads HID descriptor
-> host reads report descriptor
-> host parses usages and report layout
-> device and host exchange reportsBluetooth HID 的承载方式不同,但也需要让主机知道设备支持的 HID service、report map 和 report 数据含义。
2. report 是运行时真正交换的数据
一个 HID 鼠标 input report 可以近似理解为:
byte 0: buttons bitmask
byte 1: dx
byte 2: dy
byte 3: wheel这里 buttons bitmask 是多个按钮状态压缩成的位字段,dx 和 dy 通常表示相对位移,不是屏幕绝对坐标;wheel 是滚轮增量。主机能正确解析这些字段,是因为 report descriptor 事先描述了字段长度、顺序、用途和取值范围。
3. Usage Page 和 Usage 给字段赋语义
HID 不只关心字段有几个 bit,还关心这些 bit 代表什么。可以把字段语义写成:
field_meaning = usage_page + usage + logical_range + report_offsetusage_page是用途大类,例如 Generic Desktop、Keyboard/Keypad、Button、Consumer。usage是大类下的具体用途,例如 X、Y、Mouse、Keyboard a/A、Volume Up。logical_range描述上报值的逻辑范围,例如按钮是 0/1,轴值可能是 -127 到 127。report_offset是字段在 report 字节流中的位置。
这个表达式不是协议里的单个字段,而是解释主机如何把“某几个 bit”变成“鼠标 X 位移”或“音量加键”的工程模型。
4. HID 类驱动把 report 转成操作系统事件
运行时路径通常是:
physical action
-> device firmware builds HID report
-> transport sends report
-> OS HID class driver parses report
-> input subsystem produces key/mouse/gamepad event
-> application receives event对应用来说,它通常不直接读原始 HID 字节,而是通过操作系统输入事件、Raw Input、evdev、IOKit、hidraw 或游戏控制器 API 获取结果。只有调试自定义 HID、产测工具或嵌入式主机场景,才经常直接处理 HID report。
工程用途
- 免驱外设:键盘、鼠标、触控板、手柄、扫描枪等用通用 HID 类驱动接入主机。
- 嵌入式控制器:把旋钮、按钮、脚踏、遥控器或工控面板模拟成标准输入设备。
- 厂商自定义通信:用 Vendor-defined Usage Page 做少量控制或配置,获得免驱优势。
- BLE 输入设备:通过 HOGP(HID over GATT Profile) 实现低功耗键盘、遥控器、鼠标。
- 测试和产线工具:用 HID feature/output report 读写简单配置或执行设备测试命令。
观察 HID 问题时,重点看枚举是否成功、report descriptor 是否能被主机解析、report 长度是否一致、Report ID 是否匹配、轮询/连接间隔是否满足延迟、权限是否允许应用访问 hidraw,以及操作系统是否把设备绑定到预期类驱动。
边界与常见坑
- HID 不等于 USB:USB 只是最常见承载方式之一;HID 也可以跑在 Bluetooth、BLE GATT、I2C 等链路上。
- HID 不等于键鼠:键鼠是典型 HID,但游戏手柄、触控屏、扫描枪、Consumer Control、厂商自定义控制器也可以是 HID。
- 自定义 HID 不等于主机自动懂业务语义:免驱只说明类驱动能收发 report;应用仍要按 report descriptor 或约定解释厂商自定义字段。
- report descriptor 错一点就会全局错:字段长度、Report ID、usage、padding 或 logical range 写错,会导致主机解析错位。
- Boot Protocol 只覆盖简化键盘/鼠标:BIOS/UEFI 启动阶段可能只支持简单键鼠,不支持复杂自定义 report。
- Output report 不是可靠控制总线:HID 适合低速控制和输入,不适合大吞吐流式数据。
- 安全边界不能忽略:HID 键盘可以注入按键,USB/Bluetooth 配对、物理接入和主机授权必须纳入威胁模型。
- 车灯语境的 HID 是另一件事:汽车照明里 HID 常指 High Intensity Discharge,高强度气体放电灯,不是 Human Interface Device。
相关术语
- USB HID
- HID Report Descriptor
- HOGP(HID over GATT Profile)
- BLE
- GATT
- Bluetooth UUID
- 设备驱动
- Wire Protocol