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

如何解决Python中使用pynput库松开鼠标后光标持续抖动问题

鼠标松开后光标抖动无法停止的问题修复

你的代码核心问题是鼠标释放事件没有被正确捕获:pynput的mouse.Listener并没有on_release这个参数,你错误地绑定了不存在的回调参数,导致松开鼠标时on_mouse_release函数根本不会执行,is_aiming始终为True,抖动自然停不下来。

另外还有几处逻辑细节需要调整,以下是修复后的完整代码,附修改说明:

import random
import tkinter as tk
from pynput import keyboard, mouse
import win32api
import win32con
from pynput.mouse import Listener

# Global variables
is_aiming = False
current_key = None
move_cursor_id = None


def on_key_press(key):
    global is_aiming, current_key
    if isinstance(key, keyboard.KeyCode):
        target_key = key_entry.get().lower()
        if key.char.lower() == target_key and not is_aiming:
            current_key = key
            is_aiming = True
            move_cursor()


def on_key_release(key):
    global is_aiming
    if isinstance(key, keyboard.KeyCode) and key == current_key:
        is_aiming = False
        if move_cursor_id is not None:
            window.after_cancel(move_cursor_id)
            move_cursor_id = None


def on_mouse_click(x, y, button, pressed):
    global is_aiming, current_key
    target_btn = key_entry.get().lower()
    if isinstance(button, mouse.Button) and button.name.lower() == target_btn:
        if pressed:
            if not is_aiming:
                current_key = button
                is_aiming = True
                move_cursor()
        else:
            if button == current_key:
                is_aiming = False
                if move_cursor_id is not None:
                    window.after_cancel(move_cursor_id)
                    move_cursor_id = None


def on_mouse_move(x, y):
    global move_cursor_id
    # 仅在aiming状态且没有调度任务时启动,避免重复触发
    if is_aiming and move_cursor_id is None:
        move_cursor_id = window.after(10, move_cursor)


def move_cursor():
    global move_cursor_id
    if is_aiming:
        offset_x = random.randint(-1, 1)
        offset_y = random.randint(-1, 1)
        current_x, current_y = win32api.GetCursorPos()
        new_x = current_x + offset_x
        new_y = current_y + offset_y
        win32api.SetCursorPos((new_x, new_y))
        move_cursor_id = window.after(10, move_cursor)
    else:
        if move_cursor_id is not None:
            window.after_cancel(move_cursor_id)
            move_cursor_id = None


# Create Tkinter window
window = tk.Tk()
window.title("Cursor Aiming")

# Create a label and entry field for the key
key_label = tk.Label(window, text="Key:")
key_label.pack()
key_entry = tk.Entry(window)
key_entry.pack()

# Start listening for key and mouse events
key_listener = keyboard.Listener(
    on_press=on_key_press, on_release=on_key_release)
key_listener.start()

# 修正鼠标监听器参数:用on_click处理按下/释放,移除无效的on_release参数
mouse_listener = Listener(
    on_click=on_mouse_click, on_move=on_mouse_move)
mouse_listener.start()

# Start the Tkinter event loop
window.mainloop()

关键修改说明:

  1. 修复鼠标事件监听:将原来的on_mouse_press和on_mouse_release合并为on_mouse_click,利用on_click回调的pressed参数判断是按下还是释放操作,确保释放事件被正确处理。
  2. 移除无效参数:删除了mouse.Listener中不存在的on_release参数,避免回调失效。
  3. 统一状态清理逻辑:在键盘释放时也加入了取消调度的逻辑,保持按键和鼠标操作的行为一致。
  4. 优化变量赋值时机:仅在触发条件满足时才设置current_key,避免不必要的全局变量修改。

内容的提问来源于stack exchange,提问作者max.4

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:07:54