使用pynput的mouse.Listener()时如何解决鼠标卡顿问题?
解决pynput鼠标监听时的卡顿问题
你的鼠标卡顿根本不是pynput的必然结果,核心原因是主线程被无限循环里的全屏截图+OpenCV显示操作占满了CPU,导致系统无法及时响应鼠标事件。pynput的监听线程是后台运行的,但主线程CPU跑满后,系统分配给鼠标事件处理的资源被挤压,自然出现卡顿。
具体解决方案
把耗时的截图+显示逻辑从主线程剥离,放到单独线程中,并添加帧率控制,减少不必要的资源占用:
from PIL import ImageGrab import cv2 import numpy as np from pynput import mouse import threading import time side_button_held = False # 用事件对象控制截图线程的启停 screenshot_trigger = threading.Event() def on_click(x, y, button, pressed): global side_button_held if button == mouse.Button.x2 and pressed: side_button_held = True screenshot_trigger.set() # 开启截图 print("侧键已按下") elif button == mouse.Button.x2: side_button_held = False screenshot_trigger.clear() # 停止截图 cv2.destroyWindow("Screen") # 及时销毁窗口释放资源 print("侧键已松开") def screenshot_task(): # 控制截图帧率,每秒30帧足够,避免无意义的高频操作 target_fps = 30 frame_interval = 1 / target_fps while True: if screenshot_trigger.is_set(): start_time = time.time() # 截图与格式转换 screenshot = ImageGrab.grab(bbox=None) img = np.array(screenshot) rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) cv2.imshow("Screen", rgb_img) cv2.waitKey(1) # 计算剩余时间,保证帧率稳定 elapsed = time.time() - start_time if elapsed < frame_interval: time.sleep(frame_interval - elapsed) else: # 未触发时低负载等待 time.sleep(0.01) # 启动截图线程(守护线程,随主程序退出) screenshot_thread = threading.Thread(target=screenshot_task, daemon=True) screenshot_thread.start() # 启动鼠标监听 listener = mouse.Listener(on_click=on_click) listener.start() # 主线程保持运行,等待监听线程结束 listener.join()
优化说明
- 线程分离:把截图和显示逻辑放到独立线程,主线程只负责处理鼠标事件,不会被CPU密集型操作阻塞。
- 帧率控制:固定30帧的截图频率,既保证显示流畅,又避免无限制占用CPU。
- 资源清理:释放侧键时及时销毁OpenCV窗口,避免残留资源占用。
额外优化建议
- 若追求更低的CPU占用,可以替换
ImageGrab为mss库,它的截图效率更高。 - 如果不需要全屏截图,给
grab()指定bbox参数缩小截图区域,进一步降低资源消耗。
内容的提问来源于stack exchange,提问作者drlife
相关产品推荐
相关产品推荐

