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

请求:捕获第一人称3D游戏内鼠标移动用于强化学习行为克隆

解决3D游戏内鼠标位移捕获问题(用于行为克隆数据采集)

问题核心在于:多数第一人称3D游戏会锁定系统光标在窗口中心并隐藏,pyautogui/mouse这类工具读取的是系统层面的光标绝对位置,自然捕获不到实际的鼠标移动——因为系统光标根本没动,游戏内部直接读取的是鼠标的原始相对位移(delta值)。

下面是几个可行的解决方向:

1. 调用系统原始输入API(Windows平台)

直接读取Windows的Raw Input数据,绕过系统光标位置,获取鼠标的原生位移。用Python的ctypes就能实现,无需额外第三方库:

import ctypes
from ctypes import wintypes

# 定义Windows API所需的结构体和常量
user32 = ctypes.WinDLL('user32', use_last_error=True)

RAWINPUTDEVICE = wintypes.STRUCTURE
class RAWINPUTDEVICE(RAWINPUTDEVICE):
    _fields_ = [("usUsagePage", wintypes.WORD),
                ("usUsage", wintypes.WORD),
                ("dwFlags", wintypes.DWORD),
                ("hwndTarget", wintypes.HWND)]

RAWINPUTHEADER = wintypes.STRUCTURE
class RAWINPUTHEADER(RAWINPUTHEADER):
    _fields_ = [("dwType", wintypes.DWORD),
                ("dwSize", wintypes.DWORD),
                ("hDevice", wintypes.HANDLE),
                ("wParam", wintypes.WPARAM)]

RAWMOUSE = wintypes.STRUCTURE
class RAWMOUSE(RAWMOUSE):
    _fields_ = [("usFlags", wintypes.WORD),
                ("ulButtons", wintypes.DWORD),
                ("usButtonFlags", wintypes.WORD),
                ("usButtonData", wintypes.WORD),
                ("ulRawButtons", wintypes.DWORD),
                ("lLastX", wintypes.LONG),
                ("lLastY", wintypes.LONG),
                ("ulExtraInformation", wintypes.DWORD)]

RAWINPUT = wintypes.STRUCTURE
class RAWINPUT(RAWINPUT):
    _fields_ = [("header", RAWINPUTHEADER),
                ("mouse", RAWMOUSE)]

RID_INPUT = 0x10000003

def register_raw_input():
    rid = RAWINPUTDEVICE()
    rid.usUsagePage = 0x01
    rid.usUsage = 0x02  # 鼠标设备
    rid.dwFlags = 0
    rid.hwndTarget = None
    if not user32.RegisterRawInputDevices(ctypes.byref(rid), 1, ctypes.sizeof(rid)):
        raise ctypes.WinError(ctypes.get_last_error())

def get_mouse_delta():
    data_size = wintypes.DWORD()
    user32.GetRawInputBuffer(None, ctypes.byref(data_size), ctypes.sizeof(RAWINPUTHEADER))
    
    buffer = ctypes.create_string_buffer(data_size.value)
    num_events = user32.GetRawInputBuffer(buffer, ctypes.byref(data_size), ctypes.sizeof(RAWINPUTHEADER))
    
    delta_x, delta_y = 0, 0
    for i in range(num_events):
        raw_input = ctypes.cast(buffer + i * data_size.value, ctypes.POINTER(RAWINPUT))
        if raw_input.contents.header.dwType == 0:  # 鼠标输入
            delta_x += raw_input.contents.mouse.lLastX
            delta_y += raw_input.contents.mouse.lLastY
    return delta_x, delta_y

# 示例用法
if __name__ == "__main__":
    register_raw_input()
    while True:
        dx, dy = get_mouse_delta()
        if dx != 0 or dy != 0:
            print(f"鼠标位移: X={dx}, Y={dy}")

这段代码会直接捕获鼠标的原生相对位移,不受游戏光标锁定的影响。

2. 利用游戏引擎内置API(如果有权限访问引擎)

如果目标游戏是用Unity/Unreal等引擎开发的,直接在引擎内编写脚本捕获输入是最可靠的方式:

  • Unity:在Update函数中用Input.GetAxis("Mouse X")和Input.GetAxis("Mouse Y")获取帧间位移,然后将数据写入文件。
  • Unreal:在PlayerController的Tick函数中读取GetInputMouseDelta(X, Y),保存位移数据。
    这种方式能直接拿到游戏内部使用的鼠标输入数据,完全避免系统层面的兼容性问题。

3. 内存读取(进阶方案,谨慎使用)

如果无法访问游戏引擎,可以尝试读取游戏进程内存中存储鼠标位移的变量。但这个方法需要逆向分析游戏内存结构,且可能触发反作弊系统,仅适合非线上游戏或有开发权限的场景。


内容的提问来源于stack exchange,提问作者Snykral fa Ashama

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 23:55:24