You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

游戏长点击模拟失效问题求助:多设备异常排查与代码优化

游戏机器人长点击模拟失效问题排查与解决

问题概述

开发游戏机器人时遇到长点击模拟异常:普通点击功能正常,但长点击运行20分钟至1小时后,原本应持续duration时长的单次按压会拆分为两次各约0.5*duration的短按压,时长还可能出现波动。该问题仅在台式机上出现,笔记本运行完全正常,更换多个点击模拟库后问题依旧,改用鼠标频率一致的while循环模拟也只是短暂有效,最终仍会崩溃,怀疑是设备驱动差异导致。

核心现象

  • 笔记本无异常,所有台式机均出现故障
  • 故障触发有延迟,运行20分钟到1小时后发作
  • 多库替换、循环模拟均无法彻底解决问题

可能原因分析

  1. 结构体字段缺失:原代码中MouseInputdxdytime等字段未赋值,部分台式机鼠标驱动对Windows API参数的容错性更低,严格要求必填字段完整。
  2. 计时精度不足:使用time.sleep控制按压时长,受系统调度、后台进程干扰大,容易出现时序偏差,长时间运行后累积误差触发异常。
  3. 驱动层面拦截/优化:台式机鼠标驱动的节能模式、输入优化或游戏专属驱动可能会拦截或篡改模拟的鼠标事件,长时间运行后触发这类机制。
  4. 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,提问作者Эмиль Сакаев

火山引擎 最新活动