You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于Python的HIDAPI输出解析及USB扫码枪数据读取问题

解析USB HID扫码枪数据:Python HIDAPI在OS X上的常见疑问

背景

我目前在OS X系统中尝试用Python的HIDAPI读取USB HID扫码枪的字符串,已经完成了基础适配:成功调用h.open(),能打印厂商和产品字符串,也通过EVDEV验证了扫描码。现在的核心问题是如何解析HIDAPI返回的数据并映射为ASCII字符串。

参考示例代码

from __future__ import print_function
import hid
import time

print("Opening the device")
h = hid.device()
h.open(1118, 2048)  # A Microsoft wireless combo keyboard & mouse

print("Manufacturer: %s" % h.get_manufacturer_string())
print("Product: %s" % h.get_product_string())
print("Serial No: %s" % h.get_serial_number_string())

try:
    while True:
        d = h.read(64)
        if d:
            print('read: "{}"'.format(d))
finally:
    print("Closing the device")
    h.close()

执行结果(sudo python try.py

Opening the device
Manufacturer: Microsoft
Product: Microsoft® Nano Transceiver v2.0
Serial No: None
read: "[0, 0, 0, 0, 0, 0, 0, 0]"
read: "[0, 0, 0, 0, 0, 0, 0, 0]"
read: "[0, 0, 0, 0, 0, 0, 0, 0]"
--8<-- snip lots of repeated lines --8<--
read: "[0, 0, 0, 0, 0, 0, 0, 0]"
read: "[0, 0, 0, 0, 0, 0, 0, 0]"
read: "[0, 0, 21, 0, 0, 0, 0, 0]"
read: "[0, 0, 21, 0, 0, 0, 0, 0]"
read: "[0, 0, 21, 0, 0, 0, 0, 0]"
read: "[0, 0, 21, 0, 0, 0, 0, 0]"
read: "[0, 0, 0, 0, 0, 0, 0, 0]"
read: "[0, 0, 4, 0, 0, 0, 0, 0]"
read: "[0, 0, 4, 22, 0, 0, 0, 0]"
read: "[0, 0, 4, 22, 0, 0, 0, 0]"
read: "[0, 0, 4, 22, 0, 0, 0, 0]"
read: "[0, 0, 4, 22, 0, 0, 0, 0]"
read: "[0, 0, 4, 22, 0, 0, 0, 0]"
read: "[0, 0, 4, 0, 0, 0, 0, 0]"
read: "[0, 0, 4, 0, 0, 0, 0, 0]"
read: "[0, 0, 4, 9, 0, 0, 0, 0]"
read: "[0, 0, 4, 9, 0, 0, 0, 0]"
read: "[0, 0, 4, 9, 0, 0, 0, 0]"
read: "[0, 0, 4, 9, 0, 0, 0, 0]"
read: "[0, 0, 4, 9, 7, 0, 0, 0]"
read: "[0, 0, 4, 9, 7, 0, 0, 0]"
read: "[0, 0, 7, 0, 0, 0, 0, 0]"
^Closing the device
Traceback (most recent call last):
  File "try.py", line 17, in <module>
    d = h.read(64)
KeyboardInterrupt

我找不到像EVDEV那样的优质示例文档,导致解析输出很困难。h.read()返回一个列表,我有以下技术疑问:


疑问解答

1. 为何h.read()选择参数64?当参数替换为1-8时,列表元素数量不变;参数≥9时,列表仅含8个元素。

这个参数是你请求读取的最大字节数,但实际返回的字节数由HID设备的报告描述符决定。你的扫码枪(或者这里的微软收发器)使用的是8字节的HID报告,所以不管你请求1-64字节,它只会返回固定的8字节报告。当你请求≥9字节时,底层HIDAPI还是只会返回设备规定的8字节报告长度,所以列表始终是8个元素。

2. 变量d为何是包含8个元素的输出列表?代码中未指定该长度。

这完全由你的HID设备决定。每个USB HID设备都会通过报告描述符定义它的输入报告长度——你的设备定义的是8字节,所以每次read()调用都会返回8个元素的列表(每个元素对应1字节的数值)。你可以通过调用h.get_report_descriptor()方法获取设备的报告描述符来确认这一点。

3. 每个输出列表代表什么?是否对应一个输入字符?

不一定。HID输入报告是设备发送的状态快照:

  • 大部分全0的列表是设备的“空报告”,用来维持连接或者表示没有按键动作。
  • 非空报告可能对应按键按下/释放的状态:比如你看到的[0,0,21,0,0,0,0,0]可能是某个修饰键或者扫描码的按下事件,后续的全0报告则是按键释放的标记。
  • 扫码枪通常模拟键盘输入,所以每个有效字符可能对应多个报告:按下报告、可能的重复报告、释放报告。

4. 列表中每个元素分别代表/编码什么内容?

对于键盘类HID设备(扫码枪属于这类),标准8字节报告的格式通常是:

  • 第1个字节:修饰键位掩码(比如Shift、Ctrl、Alt等,每个位对应一个修饰键)。
  • 第2个字节:通常为保留位(固定为0)。
  • 第3到第8个字节:扫描码(最多支持6个同时按下的按键,适配多键输入场景)。
    你看到的[0,0,21,0,0,0,0,0]里的21就是某个按键的扫描码,[0,0,4,22,0,0,0,0]里的4和22则是同时触发的两个扫描码(可能是修饰键+普通键,或者设备自定义的格式)。

5. 是否有公开的对照表可将这些数值映射为键盘字符?

有的,USB组织定义了HID键盘扫描码对照表(称为Usage ID)。标准的键盘扫描码可以参考HID Usage Tables文档里的Keyboard/Keypad Page(Page 0x07),常见映射示例:

  • 扫描码4对应字母'A'(未按Shift),22对应'G',9对应'I',7对应'9'(按下Shift时则对应'(')。
  • 你需要先判断修饰键的状态(比如Shift是否按下),再将扫描码映射为对应的ASCII字符。另外,多数扫码枪会发送回车(扫描码0x28)作为一次扫描完成的标记,你可以通过这个标记来拼接完整的扫描字符串。

内容的提问来源于stack exchange,提问作者gatorback

火山引擎 最新活动