You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 06:05:34