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

Windows平台下Python指定键盘输入读取与宏转换问题求助

在Windows下用Python识别特定键盘输入的方案

方案1:使用Raw Input API(推荐,原生支持设备区分)

Windows的Raw Input API是区分不同输入设备的可靠方式,通过pywin32库即可调用,步骤如下:

1. 枚举所有键盘设备,定位目标键盘

先获取所有连接的键盘设备信息,找到旧键盘对应的设备句柄或名称:

import win32api
import win32con
from ctypes import windll, Structure, c_int, c_void_p, POINTER, sizeof

class RAWINPUTDEVICELIST(Structure):
    _fields_ = [("hDevice", c_void_p), ("dwType", c_int)]

def enum_keyboard_devices():
    devices = []
    count = c_int(0)
    # 获取设备列表长度
    windll.user32.GetRawInputDeviceList(None, count, sizeof(RAWINPUTDEVICELIST))
    device_list = (RAWINPUTDEVICELIST * count.value)()
    windll.user32.GetRawInputDeviceList(device_list, count, sizeof(RAWINPUTDEVICELIST))
    
    for i in range(count.value):
        device = device_list[i]
        if device.dwType == win32con.RIM_TYPEKEYBOARD:
            # 获取设备名称缓冲区大小
            buf_size = c_int(0)
            windll.user32.GetRawInputDeviceInfo(device.hDevice, win32con.RIDI_DEVICENAME, None, buf_size)
            name_buf = (c_int * buf_size.value)()
            windll.user32.GetRawInputDeviceInfo(device.hDevice, win32con.RIDI_DEVICENAME, name_buf, buf_size)
            device_name = win32api.GetUnicodeString(name_buf)
            devices.append({"hDevice": device.hDevice, "name": device_name})
    return devices

# 运行获取所有键盘设备,找到目标旧键盘的条目
keyboards = enum_keyboard_devices()
for kb in keyboards:
    print(kb["name"])

运行后会输出所有键盘设备的名称,记录目标键盘的hDevice值。

2. 监听目标键盘的输入

注册Raw Input监听,只处理目标设备的输入(需管理员权限运行):

import win32api
import win32gui
import win32con
from ctypes import windll, Structure, c_ushort, c_int, c_void_p, POINTER, sizeof

class RAWINPUTHEADER(Structure):
    _fields_ = [
        ("dwType", c_int),
        ("dwSize", c_int),
        ("hDevice", c_void_p),
        ("wParam", c_int)
    ]

class RAWKEYBOARD(Structure):
    _fields_ = [
        ("MakeCode", c_ushort),
        ("Flags", c_ushort),
        ("Reserved", c_ushort),
        ("VKey", c_ushort),
        ("Message", c_int),
        ("ExtraInformation", c_int)
    ]

class RAWINPUT(Structure):
    _fields_ = [
        ("header", RAWINPUTHEADER),
        ("data", RAWKEYBOARD)
    ]

# 替换为目标键盘的hDevice
TARGET_DEVICE_HANDLE = None

def raw_input_proc(hwnd, msg, wparam, lparam):
    if msg == win32con.WM_INPUT:
        buf_size = c_int(0)
        windll.user32.GetRawInputData(lparam, win32con.RID_INPUT, None, buf_size, sizeof(RAWINPUTHEADER))
        raw_input_buf = (c_int * buf_size.value)()
        windll.user32.GetRawInputData(lparam, win32con.RID_INPUT, raw_input_buf, buf_size, sizeof(RAWINPUTHEADER))
        raw_input = RAWINPUT.from_buffer(raw_input_buf)
        
        # 过滤目标设备的输入
        if raw_input.header.hDevice == TARGET_DEVICE_HANDLE:
            vkey = raw_input.data.VKey
            key_char = win32api.MapVirtualKey(vkey, win32con.MAPVK_VK_TO_CHAR)
            print(f"目标键盘输入: {chr(key_char) if key_char else vkey}")
            # 此处添加宏输出逻辑,比如用win32api模拟按键
            # win32api.keybd_event(win32con.VK_RETURN, 0, 0, 0)
            # win32api.keybd_event(win32con.VK_RETURN, 0, win32con.KEYEVENTF_KEYUP, 0)
    return win32gui.DefWindowProc(hwnd, msg, wparam, lparam)

# 创建隐藏窗口接收消息
wc = win32gui.WNDCLASS()
wc.lpfnWndProc = raw_input_proc
wc.lpszClassName = "RawInputListener"
wc.hInstance = win32api.GetModuleHandle(None)
class_atom = win32gui.RegisterClass(wc)
hwnd = win32gui.CreateWindow(class_atom, "", 0, 0, 0, 0, 0, 0, 0, wc.hInstance, None)

# 注册Raw Input监听键盘
raw_input_device = win32gui.RAWINPUTDEVICE()
raw_input_device.usUsagePage = 1
raw_input_device.usUsage = 6  # 键盘设备的Usage ID
raw_input_device.dwFlags = win32con.RIDEV_INPUTSINK
raw_input_device.hwndTarget = hwnd
win32gui.RegisterRawInputDevices([raw_input_device])

# 消息循环保持监听
while True:
    win32gui.PumpWaitingMessages()

方案2:使用pynput库(更简洁)

pynput封装了底层API,可快速实现特定设备监听:

1. 枚举设备并定位目标

from pynput import keyboard

for device in keyboard.Device.list():
    print(f"设备: {device}, 名称: {device.name}")

找到旧键盘对应的device对象。

2. 监听目标设备

from pynput import keyboard

# 替换为目标键盘的名称关键词
target_device = None
for d in keyboard.Device.list():
    if "旧键盘名称关键词" in d.name:
        target_device = d
        break

def on_press(key):
    print(f"目标键盘按下: {key}")
    # 宏输出逻辑示例:模拟回车
    # controller = keyboard.Controller()
    # controller.press(keyboard.Key.enter)
    # controller.release(keyboard.Key.enter)

def on_release(key):
    pass

# 启动仅监听目标设备的监听器
listener = keyboard.Listener(
    on_press=on_press,
    on_release=on_release,
    device=target_device)
listener.start()
listener.join()

方案3:修复hid库的使用问题

若之前用hid库失败,大概率是未获取正确的设备VID/PID或权限不足:

  1. 打开设备管理器,找到旧键盘→属性→详细信息→硬件ID,提取VID_XXXX和PID_XXXX(转为十进制)。
  2. 使用hidapi连接并读取:
import hid

# 替换为目标设备的VID和PID(十六进制转十进制)
VID = 0xXXXX
PID = 0xXXXX

device = hid.device()
device.open(VID, PID)
device.set_nonblocking(True)

while True:
    data = device.read(64)
    if data:
        # 按HID键盘协议解析数据:第2位为修饰键,第4位起为按键码
        print(f"收到原始数据: {data}")
        # 此处可添加按键解析和宏输出逻辑
device.close()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 21:55:05