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

在PyCharm中开发键鼠录制与循环重复的宏脚本需求

宏录制与回放脚本:问题修复与实现方案

原代码核心问题

  1. 未导入pyautogui库,回放阶段会触发NameError
  2. 仅轮询活动窗口的鼠标位置,未捕获鼠标点击、拖拽及键盘按键、组合键等关键操作
  3. 完全缺失键盘事件的录制与回放逻辑
  4. 轮询式录制生成大量重复鼠标位置数据,导致回放冗余、卡顿
  5. 热键停止逻辑依赖循环轮询,响应延迟且占用系统资源

修正后的完整代码

我们使用pynput实现事件驱动的精准录制,pyautogui处理回放动作,keyboard实现可靠的热键停止:

import time
from pynput import mouse, keyboard
import pyautogui

# 全局变量:存储录制的事件,标记录制状态
recorded_events = []
is_recording = False

def on_mouse_event(x, y, button, pressed):
    """监听鼠标事件:移动、点击、拖拽"""
    global recorded_events
    if not is_recording:
        return False  # 停止监听

    event_type = None
    event_data = None

    if button is not None:
        # 处理点击/拖拽事件
        action = "press" if pressed else "release"
        event_type = f"mouse_{action}"
        event_data = (x, y, str(button))
    else:
        # 处理鼠标移动事件
        event_type = "mouse_move"
        event_data = (x, y)

    recorded_events.append(("mouse", time.time(), event_type, event_data))

def on_keyboard_event(key, pressed):
    """监听键盘事件:按键按下/释放"""
    global recorded_events
    if not is_recording:
        return False  # 停止监听

    if pressed:
        try:
            # 普通字符按键
            key_str = key.char
        except AttributeError:
            # 特殊按键(如Ctrl、Shift、Enter等)
            key_str = str(key).replace("Key.", "")
        recorded_events.append(("keyboard", time.time(), "press", key_str))
    else:
        # 记录按键释放(用于处理组合键)
        try:
            key_str = key.char
        except AttributeError:
            key_str = str(key).replace("Key.", "")
        recorded_events.append(("keyboard", time.time(), "release", key_str))

def stop_recording():
    """停止录制的回调函数:按下热键'9'触发"""
    global is_recording
    is_recording = False
    print("\n录制已停止")

def main():
    global is_recording, recorded_events

    # 注册停止录制的热键
    keyboard.add_hotkey('9', stop_recording)

    # 开始录制
    print("开始录制,按下热键'9'停止...")
    is_recording = True
    recorded_events.clear()

    # 启动鼠标和键盘监听线程
    mouse_listener = mouse.Listener(on_move=on_mouse_event, on_click=on_mouse_event, on_scroll=lambda x,y,dx,dy: None)
    keyboard_listener = keyboard.Listener(on_press=lambda key: on_keyboard_event(key, True), on_release=lambda key: on_keyboard_event(key, False))
    
    mouse_listener.start()
    keyboard_listener.start()

    # 等待录制停止
    while is_recording:
        time.sleep(0.1)

    # 停止监听线程
    mouse_listener.stop()
    keyboard_listener.stop()
    keyboard.remove_hotkey('9')

    # 获取重复次数
    try:
        repetitions = int(input("输入重复次数:"))
    except ValueError:
        print("输入无效,默认重复1次")
        repetitions = 1

    # 回放录制的事件
    if repetitions > 0 and recorded_events:
        print(f"开始重复执行{repetitions}次...")
        for _ in range(repetitions):
            prev_timestamp = recorded_events[0][1]
            for event in recorded_events:
                event_type, timestamp, action, data = event
                # 保持原操作的时间间隔
                time.sleep(timestamp - prev_timestamp)
                prev_timestamp = timestamp

                if event_type == "mouse":
                    x, y = data[:2]
                    pyautogui.moveTo(x, y)
                    if action == "mouse_press":
                        button = data[2]
                        if button == "Button.left":
                            pyautogui.mouseDown(button='left')
                        elif button == "Button.right":
                            pyautogui.mouseDown(button='right')
                        elif button == "Button.middle":
                            pyautogui.mouseDown(button='middle')
                    elif action == "mouse_release":
                        button = data[2]
                        if button == "Button.left":
                            pyautogui.mouseUp(button='left')
                        elif button == "Button.right":
                            pyautogui.mouseUp(button='right')
                        elif button == "Button.middle":
                            pyautogui.mouseUp(button='middle')
                elif event_type == "keyboard":
                    if action == "press":
                        if len(data) == 1:
                            # 普通字符直接输入
                            pyautogui.press(data)
                        else:
                            # 特殊按键(如enter、ctrl等)
                            pyautogui.press(data)
        print("执行完成")
    else:
        print("无录制事件或重复次数无效")

if __name__ == '__main__':
    main()

代码说明

  1. 依赖安装:先执行以下命令安装所需库
    pip install pynput pyautogui keyboard
    
  2. 事件录制:
    • 鼠标监听:捕获移动、左键/右键/中键的按下/释放,记录坐标、按键类型及时序
    • 键盘监听:捕获普通字符与特殊按键的按下/释放,支持组合键录制
    • 热键停止:按下9键立即终止录制,响应及时
  3. 事件回放:
    • 严格按照录制时的时间间隔执行操作,还原原操作节奏
    • 鼠标操作:移动到对应坐标,执行按下/释放动作(支持拖拽)
    • 键盘操作:模拟按键按下/释放,支持普通字符与特殊按键

注意事项

  • 运行脚本时需授予系统控制输入设备的权限(如Windows的管理员权限、Mac的辅助功能权限)
  • 避免在录制时使用9键以外的热键冲突,可自行修改stop_recording中的热键
  • 拖拽操作会自动记录为"按下→移动→释放"的连续事件,回放时会完整还原

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 11:54:53