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
相关产品推荐
相关产品推荐

