游戏长点击模拟失效问题求助:多设备异常排查与代码优化
游戏机器人长点击模拟失效问题排查与解决
问题概述
开发游戏机器人时遇到长点击模拟异常:普通点击功能正常,但长点击运行20分钟至1小时后,原本应持续duration时长的单次按压会拆分为两次各约0.5*duration的短按压,时长还可能出现波动。该问题仅在台式机上出现,笔记本运行完全正常,更换多个点击模拟库后问题依旧,改用鼠标频率一致的while循环模拟也只是短暂有效,最终仍会崩溃,怀疑是设备驱动差异导致。
核心现象
- 笔记本无异常,所有台式机均出现故障
- 故障触发有延迟,运行20分钟到1小时后发作
- 多库替换、循环模拟均无法彻底解决问题
可能原因分析
- 结构体字段缺失:原代码中
MouseInput的dx、dy、time等字段未赋值,部分台式机鼠标驱动对Windows API参数的容错性更低,严格要求必填字段完整。 - 计时精度不足:使用
time.sleep控制按压时长,受系统调度、后台进程干扰大,容易出现时序偏差,长时间运行后累积误差触发异常。 - 驱动层面拦截/优化:台式机鼠标驱动的节能模式、输入优化或游戏专属驱动可能会拦截或篡改模拟的鼠标事件,长时间运行后触发这类机制。
- API调用无错误检查:原代码未校验
SendInput的返回值,无法及时发现调用失败的情况,导致事件发送不完整。
解决方案与改进代码
改进点说明
- 严格按照Windows API定义结构体,补全所有必填字段
- 使用
time.perf_counter实现高精度计时,替代误差较大的time.sleep - 添加
SendInput调用的错误检查,及时捕获调用失败的情况 - 调用
GetMessageExtraInfo获取系统要求的额外信息,提升事件的合法性
import ctypes import time from ctypes import wintypes # 严格按照Windows API定义结构体 class MOUSEINPUT(ctypes.Structure): _fields_ = [ ("dx", wintypes.LONG), ("dy", wintypes.LONG), ("mouseData", wintypes.DWORD), ("dwFlags", wintypes.DWORD), ("time", wintypes.DWORD), ("dwExtraInfo", wintypes.LPVOID) ] class INPUT(ctypes.Structure): _fields_ = [ ("type", wintypes.DWORD), ("mi", MOUSEINPUT) ] INPUT_MOUSE = 0 MOUSEEVENTF_LEFTDOWN = 0x0002 MOUSEEVENTF_LEFTUP = 0x0004 # 获取系统要求的额外输入信息 def get_input_extra_info(): return ctypes.windll.user32.GetMessageExtraInfo() def press_mouse(): mouse_input = MOUSEINPUT( dx=0, dy=0, mouseData=0, dwFlags=MOUSEEVENTF_LEFTDOWN, time=0, dwExtraInfo=get_input_extra_info() ) input_event = INPUT(type=INPUT_MOUSE, mi=mouse_input) # 检查SendInput调用是否成功 send_result = ctypes.windll.user32.SendInput(1, ctypes.byref(input_event), ctypes.sizeof(INPUT)) if send_result != 1: raise RuntimeError(f"按压鼠标事件发送失败,错误码: {ctypes.GetLastError()}") def release_mouse(): mouse_input = MOUSEINPUT( dx=0, dy=0, mouseData=0, dwFlags=MOUSEEVENTF_LEFTUP, time=0, dwExtraInfo=get_input_extra_info() ) input_event = INPUT(type=INPUT_MOUSE, mi=mouse_input) send_result = ctypes.windll.user32.SendInput(1, ctypes.byref(input_event), ctypes.sizeof(INPUT)) if send_result != 1: raise RuntimeError(f"释放鼠标事件发送失败,错误码: {ctypes.GetLastError()}") def mouse_click(duration): time.sleep(1) press_mouse() # 用高精度计时器控制按压时长 start_timestamp = time.perf_counter() while time.perf_counter() - start_timestamp < duration: # 短暂休眠避免CPU占用过高 time.sleep(0.001) release_mouse()
额外调试建议
- 关闭台式机鼠标驱动的提高指针精确度、鼠标加速等功能,部分游戏驱动会拦截模拟输入
- 以管理员权限运行程序,避免权限不足导致
SendInput调用被系统拦截 - 长时间运行时,添加日志记录
SendInput的调用结果和计时偏差,定位故障触发的具体节点 - 尝试更新台式机的鼠标驱动,或改用通用的微软鼠标驱动测试是否解决问题
内容的提问来源于stack exchange,提问作者Эмиль Сакаев




