【问题标题】:Sending Mouse Click to DirectX Game Running as Admin将鼠标点击发送到以管理员身份运行的 DirectX 游戏
【发布时间】:2017-07-02 06:16:17
【问题描述】:

我一直在构建一个与游戏相关的程序,该程序需要向游戏发送模拟输入(这是屏幕上的顶部窗口并以全屏模式运行)。经过一番挣扎,我终于让鼠标移动(光标拖动)和键盘输入正常工作,但由于某种原因,游戏无法响应模拟鼠标点击。

我尝试了以下方法:

#if TRUE // SendInput works for keyboard simulation and mouse drag, but not clicks:
    INPUT mouse = {0};
    mouse.type = INPUT_MOUSE;
    mouse.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
    SendInput(1, &mouse, sizeof(INPUT));

    Sleep(100);

    ZeroMemory(&mouse, sizeof INPUT);
    mouse.type = INPUT_MOUSE;
    mouse.mi.dwFlags = MOUSEEVENTF_LEFTUP;
    SendInput(1, &mouse, sizeof(INPUT));
#else // tried this, but it did not work:
    mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
    Sleep(75);
    mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
#endif

我遇到的第一个难题是一般发送消息,但我意识到这个问题是由游戏进程权限>发送应用程序权限引起的。在此之后,我遇到了另一个问题,按键只能在某些游戏窗口/屏幕上注册,但经过一番搜索,我能够使用扫描码来克服这个问题。例如:

void SendSpacePress(bool bHardwareLevel){
    INPUT space = {0};
    space.type = INPUT_KEYBOARD;
    space.ki.time = 0;
    space.ki.dwExtraInfo = 0;

    if(!bHardwareLevel){
        space.ki.wVk = VK_SPACE;
    }else{
        space.ki.wScan = 0x39; // physical keyboard scan code
    }

    space.ki.dwFlags = bHardwareLevel ? KEYEVENTF_SCANCODE : 0;
    SendInput(1, &space, sizeof(INPUT));

    Sleep(rand()%25 + 25);

    space.ki.dwFlags = bHardwareLevel ? KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP : KEYEVENTF_KEYUP;
    SendInput(1, &space, sizeof(INPUT));
}

我还可以使用 INPUT 进行鼠标移动,如下所示:

void PanMouse(){
    INPUT mouse = {0};
    mouse.type = INPUT_MOUSE;
    mouse.mi.time = 0;
    mouse.mi.mouseData = 0;
    mouse.mi.dwExtraInfo = 0;
    mouse.mi.dwFlags = MOUSEEVENTF_MOVE;
    mouse.mi.dx = rand()%10 -5;
    mouse.mi.dy = rand()%10 -5;
    SendInput(1, &mouse, sizeof(INPUT));
}

现在最大的问题是游戏拒绝注册我的模拟鼠标点击。我希望有一种无需深入挂钩即可发送鼠标输入的方法。 (游戏有多种客户端反作弊机制,所以我大胆猜测任何类型的外部进程挂钩或 DLL 注入都会触发保护。)根据我的阅读,我可能需要编写一个自定义驱动程序一个模拟的硬件鼠标,因此输入来自内核级别。不是更好的选择,但如果需要,sobeit。 (如果需要,任何人都可以为此提供有用的信息吗?我从来没有搞砸过编写驱动程序,但我想的一切都是第一次。)

TL;DR:在似乎忽略非硬件输入的游戏中,我需要做什么才能让模拟鼠标点击注册? (即,我怎样才能让游戏认为鼠标点击是合法的,类似于在模拟键盘输入时使用KEYEVENTF_SCANCODE?)

【问题讨论】:

  • 为什么游戏一开始是以管理员身份运行的?
  • @ChuckWalbourn,游戏的运行方式。可能是为了防止其他进程修改它。不幸的是,它不能以较低的权限级别运行。
  • 以管理员身份运行并不能保护您免受其他以管理员身份运行的进程的影响。我之所以这么问,是因为 MSFT 在过去的 12 年里一直在告诉游戏开发者不需要管理员权限来运行他们的游戏。管理员安装,当然。管理员运行,没有那么多。见User Account Control for Game Developers
  • @ChuckWalbourn,我不是在争论。我没有编写游戏,我当然不能代表游戏的开发者。我只是需要以某种方式与游戏交互以复制用户的第三方。无论他们需要管理员权限的原因是什么(也许是作为监视其他进程是否有可疑活动的一种手段?)都极有可能可以忽略不计。

标签: c++ windows winapi directx directinput


【解决方案1】:

您需要注入一对鼠标输入,并将time 成员适当地设置为指示“多长时间”,而不是在输入之间休眠。

这里有一些接近你想要的东西。这将模拟 100ms 的鼠标左键单击当前光标位置。

INPUT inputs[2] = {};

inputs[0].type = INPUT_MOUSE;
inputs[0].mi.time = 0;
inputs[0].mi.dx = 0;
inputs[0].mi.dy = 0;
inputs[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;

inputs[1].type = INPUT_MOUSE;
inputs[1].mi.time = 100;
inputs[1].mi.dx = 0;
inputs[1].mi.dy = 0;
inputs[1].mi.dwFlags = MOUSEEVENTF_LEFTUP;

SendInput(2, inputs, sizeof(INPUT));

鼠标事件不会立即发生。它会在不久之后“排队”发生。

您应该对键盘事件使用相同的技术。不要叫“睡眠”。

【讨论】:

  • 感谢您的意见和建议。我会试试看。
  • 嗯。我只是试了一下,但它仍然没有在游戏过程中注册点击(或者至少没有响应鼠标点击)。我知道这不是进程升级问题,因为我在常规键盘点击中离开了,并且仍然可以正常工作,所以它似乎必须是忽略虚假MOUSEEVENTF 的进程的问题。
猜你喜欢
  • 2022-01-08
  • 2012-12-15
  • 2017-01-03
  • 1970-01-01
  • 2012-11-22
  • 2016-09-20
  • 2010-11-26
  • 2012-05-28
  • 2011-03-24
相关资源
最近更新 更多