如何在Python中分别读取多台USB条码扫描器的输入?
基于pywinusb.hid实现两台USB条码扫描器的独立输入读取
我有两台VID=0x0581、PID=0x011a的USB条码扫描器,唯一区分标识是设备路径。需要用pywinusb.hid库分别读取每台设备的扫描输入,输出格式为{device_path} {barcode_read}。
完整实现代码
import pywinusb.hid as hid # HID键盘按键码到ASCII字符的映射(基础常用集,可根据扫描器补充特殊字符) HID_KEY_MAP = { 0x04: 'a', 0x05: 'b', 0x06: 'c', 0x07: 'd', 0x08: 'e', 0x09: 'f', 0x0a: 'g', 0x0b: 'h', 0x0c: 'i', 0x0d: 'j', 0x0e: 'k', 0x0f: 'l', 0x10: 'm', 0x11: 'n', 0x12: 'o', 0x13: 'p', 0x14: 'q', 0x15: 'r', 0x16: 's', 0x17: 't', 0x18: 'u', 0x19: 'v', 0x1a: 'w', 0x1b: 'x', 0x1c: 'y', 0x1d: 'z', 0x1e: '1', 0x1f: '2', 0x20: '3', 0x21: '4', 0x22: '5', 0x23: '6', 0x24: '7', 0x25: '8', 0x26: '9', 0x27: '0', 0x28: '\n', 0x29: '\t', 0x2a: ' ', 0x2b: '-', 0x2c: '=', 0x2d: '[', 0x2e: ']', 0x2f: '\\', 0x30: '#', 0x31: ';', 0x32: '\'', 0x33: '`', 0x34: ',', 0x35: '.', 0x36: '/' } # Shift按下时的大写/特殊字符映射 HID_KEY_SHIFT_MAP = { 0x04: 'A', 0x05: 'B', 0x06: 'C', 0x07: 'D', 0x08: 'E', 0x09: 'F', 0x0a: 'G', 0x0b: 'H', 0x0c: 'I', 0x0d: 'J', 0x0e: 'K', 0x0f: 'L', 0x10: 'M', 0x11: 'N', 0x12: 'O', 0x13: 'P', 0x14: 'Q', 0x15: 'R', 0x16: 'S', 0x17: 'T', 0x18: 'U', 0x19: 'V', 0x1a: 'W', 0x1b: 'X', 0x1c: 'Y', 0x1d: 'Z', 0x1e: '!', 0x1f: '@', 0x20: '#', 0x21: '$', 0x22: '%', 0x23: '^', 0x24: '&', 0x25: '*', 0x26: '(', 0x27: ')', 0x2a: ' ', 0x2b: '_', 0x2c: '+', 0x2d: '{', 0x2e: '}', 0x2f: '|', 0x30: '~', 0x31: ':', 0x32: '"', 0x33: '`', 0x34: '<', 0x35: '>', 0x36: '?' } # 为每个设备单独维护条码缓存 device_barcode_buffers = {} def barcode_callback(device_path, data): # HID报告结构:第1字节=修饰键,第2字节=保留,第3-8字节=按键码 modifier = data[0] key_codes = data[2:8] # 判断是否按下Shift键 shift_pressed = (modifier & 0x01) != 0 or (modifier & 0x20) != 0 for code in key_codes: if code == 0: continue # 跳过空按键 # 根据Shift状态获取对应字符 if shift_pressed and code in HID_KEY_SHIFT_MAP: char = HID_KEY_SHIFT_MAP[code] elif code in HID_KEY_MAP: char = HID_KEY_MAP[code] else: char = '' # 未映射的按键忽略 if char == '\n': # 扫描完成,输出结果并清空缓存 barcode = device_barcode_buffers.get(device_path, '') if barcode: print(f"{device_path} {barcode}") device_barcode_buffers[device_path] = '' else: # 追加字符到对应设备的缓存 if device_path not in device_barcode_buffers: device_barcode_buffers[device_path] = '' device_barcode_buffers[device_path] += char def setup_scanner(device): device.open() # 通过lambda传递设备路径到回调函数 device.set_raw_data_handler(lambda data: barcode_callback(device.device_path, data)) print(f"已连接扫描器: {device.device_path}") if __name__ == "__main__": target_vid = 0x0581 target_pid = 0x011a all_devices = hid.find_all_hid_devices() scanner_devices = [dev for dev in all_devices if dev.vendor_id == target_vid and dev.product_id == target_pid] if not scanner_devices: print("未找到目标扫描器设备") else: print(f"找到 {len(scanner_devices)} 台扫描器") for dev in scanner_devices: setup_scanner(dev) print("等待扫描输入...按Ctrl+C退出") try: while True: pass except KeyboardInterrupt: print("\n程序退出") # 关闭所有设备 for dev in scanner_devices: if dev.is_opened(): dev.close()
关键实现说明
- 设备区分:用
device.device_path作为每台扫描器的唯一标识,在回调函数中绑定该路径,确保输出时能明确来源。 - HID数据解析:条码扫描器模拟键盘输入,HID报告包含修饰键和按键码,通过映射表转换为可读字符。
- 扫描结束判断:多数扫描器会在条码末尾发送回车(
\n),以此作为扫描完成的触发标志。 - 状态隔离:用字典
device_barcode_buffers为每个设备单独缓存扫描字符,避免多设备输入混淆。
内容的提问来源于stack exchange,提问作者João Galdino
相关产品推荐
相关产品推荐

