Windows下Python按键时捕获设备ID及多键盘区分问题求助
区分Windows下主键盘与外接数字键盘的解决方案
我完全懂你的困扰——在Windows上用keyboard库的时候,KeyboardEvent.device始终返回None,根本没法区分主键盘和外接数字键盘,这直接卡了宏程序的核心功能。其实这个问题的根源是keyboard库在Windows平台的底层实现没有暴露设备识别的相关信息,所以得换个思路来处理。
下面给你两个可行的方案,从简单到进阶,你可以根据自己的技术能力选择:
方案一:用inputs库快速实现设备区分
inputs库是专门针对Windows和Linux的输入设备监听工具,它封装了Windows的Raw Input API,能直接获取每个按键对应的设备信息。操作起来很简单:
- 先安装库:
pip install inputs
- 示例代码(监听外接数字键盘的按键):
from inputs import get_keyboard_events from pynput.mouse import Button, Controller import time mouse = Controller() tab_pos = (1639, 16) # 先枚举所有键盘设备,找到你的外接数字键盘的标识(比如设备名称) def list_keyboards(): for device in inputs.devices.keyboards: print(f"键盘设备: {device.name}, 句柄: {device._device_handle}") # 先运行一次这个函数,找到你的外接数字键盘的名称 list_keyboards() # 假设你的外接数字键盘名称包含"Numeric Keypad"(实际根据你输出的结果修改) TARGET_KEYBOARD_NAME = "你的外接数字键盘名称" def handle_key_event(event): # 只处理按下事件,且来自目标键盘 if event.ev_type == "Key" and event.state == 1 and event.device.name == TARGET_KEYBOARD_NAME: # 这里判断具体按键,比如外接键盘的"A"键(根据实际键值调整) if event.code == "KEY_A": prev_pos = mouse.position mouse.position = tab_pos mouse.click(Button.left, 1) mouse.position = prev_pos print("触发外接键盘的宏操作") while True: try: for event in get_keyboard_events(): handle_key_event(event) except Exception as e: print(f"出错了: {e}") time.sleep(0.1)
这个方案的好处是不用写复杂的底层代码,inputs已经帮你封装好了设备识别的逻辑,你只需要找到目标键盘的名称就行。
方案二:直接调用Windows Raw Input API(进阶)
如果你需要更精细的控制,或者不想依赖第三方库,可以用ctypes直接调用Windows的Raw Input API。这个方法需要你了解一点Windows API的基础知识,但能完全掌控设备识别的过程。
核心步骤是:
- 注册Raw Input设备,告诉系统你要监听键盘输入
- 处理
WM_INPUT消息,解析输入数据中的设备ID - 对比设备ID,区分主键盘和外接键盘
这里给你一个简化的示例框架:
import ctypes from ctypes import wintypes from pynput.mouse import Button, Controller mouse = Controller() tab_pos = (1639, 16) # 定义Windows Raw Input的相关结构体和函数 user32 = ctypes.WinDLL('user32', use_last_error=True) class RAWINPUTDEVICE(ctypes.Structure): _fields_ = [ ("usUsagePage", wintypes.WORD), ("usUsage", wintypes.WORD), ("dwFlags", wintypes.DWORD), ("hwndTarget", wintypes.HWND) ] class RAWINPUTHEADER(ctypes.Structure): _fields_ = [ ("dwType", wintypes.DWORD), ("dwSize", wintypes.DWORD), ("hDevice", wintypes.HANDLE), ("wParam", wintypes.WPARAM) ] # 注册键盘设备 RIDEV_INPUTSINK = 0x00000100 kbd_device = RAWINPUTDEVICE() kbd_device.usUsagePage = 0x01 kbd_device.usUsage = 0x06 kbd_device.dwFlags = RIDEV_INPUTSINK kbd_device.hwndTarget = user32.GetForegroundWindow() user32.RegisterRawInputDevices(ctypes.byref(kbd_device), 1, ctypes.sizeof(kbd_device)) # 获取设备名称的函数 def get_device_name(hDevice): buf_size = wintypes.DWORD(0) user32.GetRawInputDeviceInfoW(hDevice, 0x20000007, None, ctypes.byref(buf_size)) buf = ctypes.create_unicode_buffer(buf_size.value) user32.GetRawInputDeviceInfoW(hDevice, 0x20000007, buf, ctypes.byref(buf_size)) return buf.value # 监听消息循环 msg = wintypes.MSG() while user32.GetMessageW(ctypes.byref(msg), None, 0, 0) != 0: if msg.message == 0x00FF: # WM_INPUT hRawInput = msg.lParam header_size = ctypes.sizeof(RAWINPUTHEADER) buf = ctypes.create_string_buffer(header_size) user32.GetRawInputData(hRawInput, 0x10000003, buf, ctypes.byref(wintypes.DWORD(header_size)), ctypes.sizeof(RAWINPUTHEADER)) header = RAWINPUTHEADER.from_buffer(buf) device_name = get_device_name(header.hDevice) # 判断是否是目标外接键盘 if "你的外接数字键盘名称" in device_name: # 这里可以进一步解析按键数据,判断具体按下的键 print("来自外接键盘的输入") # 执行宏操作 prev_pos = mouse.position mouse.position = tab_pos mouse.click(Button.left, 1) mouse.position = prev_pos user32.TranslateMessage(ctypes.byref(msg)) user32.DispatchMessageW(ctypes.byref(msg))
这个方案更底层,适合需要高度定制的场景,但需要你根据自己的设备调整设备名称的判断逻辑。
小提示
- 不管用哪个方案,第一步都要先找到你的外接数字键盘的设备标识(名称或ID),可以通过设备管理器或者代码枚举的方式获取。
- 如果你用
inputs库遇到权限问题,试试以管理员身份运行脚本。
内容的提问来源于stack exchange,提问作者Emanuel Elliott
相关产品推荐
相关产品推荐

