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

如何无修饰符重放按键?pynput录制Shift/Cmd组合键问题求助

解决Pynput录制组合键异常的问题

核心问题分析

  • 你的代码当前记录的是按键生成的字符(比如Shift+1生成!),而非原始按键本身,导致重放时无法还原组合键的按下状态。
  • Cmd键属于系统级修饰键,直接记录str(key)会得到模糊的字符串标识,重放时无法正确模拟修饰键与普通键的配合逻辑。

正确解决方向

1. 记录原始按键对象而非字符/字符串

Pynput的keyboard.Key(修饰键)和keyboard.KeyCode(普通按键)对象包含按键的唯一标识(虚拟键码、扫描码),应优先记录这些原生信息,而非转换后的字符或字符串。

2. 区分修饰键与普通按键的序列化逻辑

  • 修饰键(Shift、Cmd等):记录其枚举名称(如shift、cmd)
  • 普通按键(1、2等):记录其虚拟键码(vk)或扫描码(code),确保重放时能精准定位到物理按键

3. 重放时严格遵循按键时序

重放需完全复刻录制时的按下/释放顺序,修饰键必须先按下、后释放,普通键的操作嵌套在修饰键的按下周期内。

修改后的示例代码

from pynput import keyboard
import time
import json

recording = []

def serialize_key(key):
    """将按键序列化为可存储的字典"""
    if isinstance(key, keyboard.Key):
        return {"type": "special", "name": key.name}
    elif isinstance(key, keyboard.KeyCode):
        return {"type": "normal", "vk": key.vk, "code": key.code}
    else:
        return None

def deserialize_key(data):
    """从字典反序列化为按键对象"""
    if data["type"] == "special":
        return getattr(keyboard.Key, data["name"])
    elif data["type"] == "normal":
        return keyboard.KeyCode(vk=data["vk"], code=data["code"])
    else:
        return None

def on_press(key):
    print(f"Pressed: {key}")
    key_data = serialize_key(key)
    if key_data:
        recording.append({
            "action": "pressed_key",
            "key": key_data,
            "_time": time.time()
        })
    # 按ESC结束录制
    if key == keyboard.Key.esc:
        print("Keyboard recording ended.")
        with open("recording.json", "w") as f:
            json.dump(recording, f, indent=2)
        return False

def on_release(key):
    print(f"Released: {key}")
    key_data = serialize_key(key)
    if key_data:
        recording.append({
            "action": "released_key",
            "key": key_data,
            "_time": time.time()
        })

# 启动录制
keyboard_listener = keyboard.Listener(on_press=on_press, on_release=on_release)
keyboard_listener.start()
keyboard_listener.join()

# 重放函数示例
def replay_recording(recording_path):
    with open(recording_path, "r") as f:
        recording = json.load(f)
    
    controller = keyboard.Controller()
    last_time = None
    
    for event in recording:
        key = deserialize_key(event["key"])
        if not key:
            continue
        
        # 模拟录制时的时间间隔
        if last_time is not None:
            time.sleep(event["_time"] - last_time)
        last_time = event["_time"]
        
        if event["action"] == "pressed_key":
            controller.press(key)
        elif event["action"] == "released_key":
            controller.release(key)

# 录制完成后可调用重放
# replay_recording("recording.json")

关键说明

  • serialize_key和deserialize_key实现了按键对象与可存储格式的双向转换,确保录制的是原始按键信息而非字符结果。
  • 重放时严格复刻录制时序,修饰键的按下/释放顺序会被正确还原,彻底解决Shift+1、Cmd组合键的重放异常问题。
  • macOS下的Cmd键会被识别为keyboard.Key.cmd,录制和重放逻辑完全适配系统特性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 21:55:26