对于 USB 接口的 HID 设备,有一套协议。
HID 设备有如下描述符:
对于鼠标,HOST 可以通过中断端点读到数据。
通过中断传输可以读到键盘数据,它是 8 字节的数据,格式如下:
偏移 | 大小 | 描述 |
---|---|---|
0 | 1字节 | "Modifier |
keys status",就是ctrl、alt、shift等按键的状态 | ||
1 | 1字节 | 保留 |
2 | 1字节 | 第1个按键的键值 |
3 | 1字节 | 第2个按键的键值 |
4 | 1字节 | 第3个按键的键值 |
5 | 1字节 | 第4个按键的键值 |
6 | 1字节 | 第5个按键的键值 |
7 | 1字节 | 第6个按键的键值 |
第 0 个字节中每一位都表示一个按键的状态,某位等于 1
时,表示对应的按键被按下,格式如下:
位 | 长度 | 描述 |
---|---|---|
0 | 1 | Left |
Ctrl | ||
1 | 1 | Left |
Shift | ||
2 | 1 | Left |
Alt | ||
3 | 1 | Left |
GUI(Windows/Super key) | ||
4 | 1 | Right |
Ctrl | ||
5 | 1 | Right |
Shift | ||
6 | 1 | Right |
Alt | ||
7 | 1 | Right |
GUI(Windows/Super key) |
读到的键盘数据里有 6 个按键值,每个按键值都是 8 位的数据。如果某个按键值不等于
0,就表示某个按键被按下了。按键值跟按键的对应关系,请看后面的《1.2.4 扫描码》。
示例:按键"A"、"B"、"C"、"X"的按键值分别是 4、5、6、0x1B。
按下了"A",USB 键盘上报的数据为:
00 00 04 00 00 00 00 00
松开"A",USB 键盘上报的数据为:
00 00 00 00 00 00 00 00
按下"A"、"B",USB 键盘上报的数据为:
00 00 04 05 00 00 00 00
保持"A"、"B"不松开,继续按下"C",USB 键盘上报的数据为:
00 00 04 05 06 00 00 00
松开"A",但是保持"B"、"C"不松开,USB 键盘上报的数据为:
00 00 05 06 00 00 00 00
USB
键盘上报的数据里,哪个按键先被按下,就先记录它的按键值。在上面的例子里,"A"松开后只有"B"、"C"这两个按键,"B"、"C"的按键值挪到了前面。
按下"Left shift"、并且按下"X",USB 键盘上报的数据为:
02 00 1B 00 00 00 00 00
USB
键盘只能上报 6 个按键值,如果有超过 6 个按键被按下,那么它将上报"phantom condition"(6 个按键值都是
1),但是"Modifier keys status"还是有效的。比如"Right Shift"被按下,另外超过 6 个的按键也被按下时,USB
键盘上报的数据为:
20 00 01 01 01 01 01 01
我们还可控制键盘的 LED,需要发出一个控制传输请求:SetReport ,使用这个请求发送一个字节的数据。
这个字节的数据格式如下,某位为 1 时,会点亮相应的 LED:
位 | 长度 | 描述 |
---|---|---|
0 | 1 | Num |
Lock | ||
1 | 1 | Caps |
Lock | ||
2 | 1 | Scroll |
Lock | ||
3 | 1 | Compose |
4 | 1 | Kana |
5 | 1 | 保留,写为0 |
发出的 SetReport,是一个控制传输的"setup packet",格式如下:
以 libusb 的函数描述它的参数,如下:
int LIBUSB_CALL libusb_control_transfer(libusb_device_handle *dev_handle,
uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
unsigned char *data, uint16_t wLength, unsigned int timeout);
/* 示例代码 */
unsigned char data = (1< < 1); /* 点亮Caps Lock */
uint16_t wValue = (0x02< < 8)|0; // 0x02: 发给设备, 0: report ID
uint16_t wIndex = 0; // 一般是0, the interface number of the USB keyboard
libusb_control_transfer(dev_handle, 0x21, 0x09, wValue, wIndex, &data, 1, timeout);
鼠标
通过中断传输可以读到鼠标数据,它是
8 字节的数据,格式如下:
偏移 | 大小 | 描述 |
---|---|---|
0 | 1字节 | |
1 | 1字节 | 按键状态 |
2 | 2字节 | X |
位移 | ||
4 | 2字节 | Y |
位移 | ||
6 | 1字节或2字节 | 滚轮 |
按键状态里,每一位对应鼠标的一个按键,等
1 时表示对应按键被点击了,格式如下:
位 | 长度 | 描述 |
---|---|---|
0 | 1 | 鼠标的左键 |
1 | 1 | 鼠标的右键 |
2 | 1 | 鼠标的中间键 |
3 | 5 | 保留,设备自己定义bit3: |
鼠标的侧边按键bit4: |
X
位移、Y 位移都是 8 位的有符号数。对于 X 位移,负数表示鼠标向左移动,正数表示鼠标向右移动,移动的幅度就使用这个 8 位数据表示。对于 Y
位移,负数表示鼠标向上移动,正数表示鼠标向下移动,移动的幅度就使用这个 8 位数据表示。
USB 规范里为每个按键定义了 16 位的按键值,注意:它是 16 位的,但是 USB 键盘只使用 8
位表示按键值。所以有些按键需要通过"Modifier keys status"来确定。比如"Left Ctrl"的按键值是 224,这无法通过 8
位数据来表示,在 USB 键盘上报的数据里,使用第 0 字节的 bit4 来表示。
libusb
有同步接口和异步接口,异步接口可以同时支持多个鼠标使用。
全部0条评论
快来发表一下你的评论吧 !