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

Python中如何同时实现手持条码扫描器与键盘输入功能?

合并条码扫描与键盘事件监听的解决方案

方案1:多线程分离监听逻辑

由于evdev的read_loop()和pygame的事件循环都是阻塞式的,直接合并会导致一方抢占资源,另一方无法响应。用多线程将两个监听逻辑分离,让它们独立运行即可解决冲突。

示例代码

import threading
import evdev
import pygame

# 原有evdev扫描函数
def getScan():
    # 替换为你的条码扫描器设备路径
    device = evdev.InputDevice('/dev/input/eventX')
    current_barcode = ""
    for event in device.read_loop():
        if event.type == evdev.ecodes.EV_KEY and event.value == 1:
            key_code = event.code
            # 处理按键映射,比如将KEY_0转为'0',KEY_ENTER作为条码结束符
            if key_code == evdev.ecodes.KEY_ENTER:
                print(f"扫描完成: {current_barcode}")
                current_barcode = ""
            else:
                key_char = evdev.ecodes.KEY[key_code].replace("KEY_", "")
                # 处理大小写,比如条码扫描器默认输出大写
                current_barcode += key_char.lower() if len(key_char) == 1 else ""

# 原有pygame键盘监听函数
def getScan1():
    pygame.init()
    pygame.display.set_mode((100, 100))  # 必须创建窗口才能监听事件
    while True:
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                print(f"键盘触发: {pygame.key.name(event.key)}")
            elif event.type == pygame.QUIT:
                pygame.quit()
                return

if __name__ == "__main__":
    # 创建守护线程,主线程退出时自动终止子线程
    scan_thread = threading.Thread(target=getScan, daemon=True)
    keyboard_thread = threading.Thread(target=getScan1, daemon=True)
    
    scan_thread.start()
    keyboard_thread.start()
    
    # 主线程保持存活,等待用户主动退出
    input("按回车键退出程序...\n")

方案2:异步IO实现非阻塞监听

如果偏好异步编程模型,可以用asyncio结合evdev的异步读取接口,同时将pygame的阻塞事件循环放到线程池中执行,避免阻塞异步任务。

示例代码

import asyncio
import evdev
import pygame
from concurrent.futures import ThreadPoolExecutor

async def async_scan():
    device = evdev.InputDevice('/dev/input/eventX')
    current_barcode = ""
    async for event in device.async_read_loop():
        if event.type == evdev.ecodes.EV_KEY and event.value == 1:
            key_code = event.code
            if key_code == evdev.ecodes.KEY_ENTER:
                print(f"扫描完成: {current_barcode}")
                current_barcode = ""
            else:
                key_char = evdev.ecodes.KEY[key_code].replace("KEY_", "")
                current_barcode += key_char.lower() if len(key_char) == 1 else ""

def pygame_key_listen():
    pygame.init()
    pygame.display.set_mode((100, 100))
    while True:
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                print(f"键盘触发: {pygame.key.name(event.key)}")
            elif event.type == pygame.QUIT:
                pygame.quit()
                return

async def main():
    executor = ThreadPoolExecutor(max_workers=1)
    loop = asyncio.get_event_loop()
    # 同时运行异步扫描任务和pygame监听任务
    await asyncio.gather(
        async_scan(),
        loop.run_in_executor(executor, pygame_key_listen)
    )

if __name__ == "__main__":
    asyncio.run(main())

关键注意点

  • 确认evdev的设备路径正确,可通过evdev.list_devices()枚举系统输入设备,找到你的条码扫描器对应的路径。
  • 若需统一处理扫描结果和键盘输入,使用线程安全的queue.Queue在两个线程/任务间传递数据,避免数据竞争。
  • pygame必须创建窗口才能正常监听键盘事件,即使窗口最小化也不影响。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 10:52:27