【问题标题】:(Windows C++) How to simulate mouse movement in FPS games?(Windows C++) 如何在 FPS 游戏中模拟鼠标移动?
【发布时间】:2020-07-15 17:58:10
【问题描述】:

我正在尝试模拟 FPS 游戏中的鼠标移动,更具体地说是 Valorant。我知道 SetCursorPos() 函数和 mouse_event() 函数都可以很好地改变光标的位置。这适用于使用不断居中光标技术的 FPS 游戏,但 Valorant 似乎没有这样做。我编写了一个程序来不断检查我的光标位置(使用GetCursorPos())并且我的光标永远不会居中,如果我将鼠标移动到一个角落然后继续移动它,我的角色会一直旋转。那么,Valorant 如何在光标位置不变的情况下感知我正在移动鼠标,以及如何在 Valorant 中对此进行反击并模拟鼠标移动?

顺便说一句,别担心 - 我不是想作弊,只是想在 freecam 中为电影镜头做出流畅的动作。

【问题讨论】:

  • 仅供参考,mouse_event() 已弃用,请改用SendInput()。但是您可能仍然会遇到同样的问题。我不知道 Valorant 是如何跟踪鼠标移动的。也许它只是看到鼠标移动到无法再移动的角落,并假设您想继续朝那个方向“移动”,直到鼠标移出角落?
  • 当我的光标位置没有改变时,Valorant 如何感知我正在移动鼠标 我不确定 Valorant 是如何实现的, 但是你可以使用RegisterRawInputDevicesusUsage = 0x02(鼠标), 这里有一个sample (你需要将usUsage改为0x02)来使用它。
  • @DrakeWu-MSFT 有趣!看了一点,但找不到太多关于 RegisterRawInputDevices 的信息,我将如何注册一个新的输入设备,然后“控制”那个输入设备?
  • RegisterRawInputDevices 可用于检测您描述的鼠标移动。对于“控制”,您可以使用SendInput 与相对坐标进行模拟。

标签: c++ windows winapi


【解决方案1】:

我不确定 Valorant 是如何实现的,但我可以在光标位置不变时使用 RegisterRawInputDevices 获取鼠标事件:

#include <windows.h>
#include <iostream>

using namespace std;
BOOL registerTouchpadForInput(HWND hWnd)
{
    RAWINPUTDEVICE rid;
    rid.dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK;
    rid.usUsagePage = 1;                            
    rid.usUsage = 2;
    rid.hwndTarget = hWnd;
    return RegisterRawInputDevices(&rid, 1, sizeof(rid));
}

static LRESULT CALLBACK NVTouch_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    BOOL  registrationStatus = false;
    switch (message)
    {
    case WM_CREATE:
        registrationStatus = registerTouchpadForInput(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_INPUT:
        printf("WM_INPUT ");
        return DefWindowProc(hwnd, message, wParam, lParam);
    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

int main()
{
    WNDCLASSEX wndclass = {
        sizeof(WNDCLASSEX),
        CS_DBLCLKS,
        NVTouch_WindowProc,
        0,
        0,
        GetModuleHandle(0),
        LoadIcon(0,IDI_APPLICATION),
        LoadCursor(0,IDC_ARROW),
        HBRUSH(COLOR_WINDOW + 1),
        0,
        L"myclass",
        LoadIcon(0,IDI_APPLICATION)
    };
    bool isClassRegistered = false;
    isClassRegistered = RegisterClassEx(&wndclass);
    if (isClassRegistered)
    {
        HWND window = CreateWindow(wndclass.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(0), NULL);
        if (window)
        {
            ShowWindow(window, SW_SHOWDEFAULT);
            MSG msg;
            while (GetMessage(&msg, 0, 0, 0))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    }
}

然后,使用SendInput 模拟鼠标在屏幕边缘的相对移动:

INPUT buffer;
ZeroMemory(&buffer, sizeof(buffer));
buffer.type = INPUT_MOUSE;
buffer.mi.dx = 10;
buffer.mi.dy = 10;
buffer.mi.mouseData = 0;
buffer.mi.dwFlags = MOUSEEVENTF_MOVE;
buffer.mi.time = 0;
buffer.mi.dwExtraInfo = 0;
while (1)
{
    Sleep(1000);
    SendInput(1, &buffer, sizeof(INPUT));
}

【讨论】:

  • 感谢代码!但是,SendInput() 似乎没有发送 raw 鼠标输入,所以它不会在游戏中移动我,我将如何模拟 raw 鼠标输入?
  • 用户无法模拟原始输入。 WM_INPUT 消息只能由系统分发。我使用原始输入的示例只是一个示例,用于说明“当我的光标位置没有改变时,应用程序如何感知我正在移动鼠标”。当您调用SendInput 时,请确保鼠标焦点位于您的窗口上。 Valorant似乎有自己的反作弊系统,如果它阻止了SendInput的注入(见LLMHF_INJECTED),那么你可能需要创建一个系统驱动api来模拟。
猜你喜欢
  • 1970-01-01
  • 2018-11-02
  • 2012-12-15
  • 2012-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多