【问题标题】:C# p/Invoke How to simulate a keyPRESS event using SendInput for DirectX gamesC# p/Invoke 如何使用 SendInput 为 DirectX 游戏模拟 keyPRESS 事件
【发布时间】:2013-07-20 19:13:35
【问题描述】:

我经常为各种机器人或其他 GUI 自动化程序模拟键盘按下事件而苦恼。

我已经设法使用以下方法模拟 keydown 事件:

INPUT[] kInput = new INPUT[1];
kInput[j].type = SendInputEventType.InputKeyboard;
kInput[j].mkhi.ki.wVk = 0;
kInput[j].mkhi.ki.wScan = (ushort) MapVirtualKey((uint) Keys.D5, 0);
kInput[j].mkhi.ki.dwFlags = KeyboardEventFlags.SCANCODE;
kInput[j].mkhi.ki.time = 0;
kInput[j].mkhi.ki.dwExtraInfo = IntPtr.Zero;
SendInput(1, kInput, Marshal.SizeOf(typeof(INPUT)));

INPUT[] kInput = new INPUT[1];
kInput[1].type = SendInputEventType.InputKeyboard;
kInput[1].mkhi.ki.wVk = '5';
kInput[1].mkhi.ki.wScan = 0;
kInput[1].mkhi.ki.dwFlags = 0;
kInput[1].mkhi.ki.time = 0;
kInput[1].mkhi.ki.dwExtraInfo = IntPtr.Zero;
SendInput(1, kInput, Marshal.SizeOf(typeof(INPUT)));

和 keyup 事件使用:

kInput[1].type = SendInputEventType.InputKeyboard;
kInput[1].mkhi.ki.wVk = 0;
kInput[1].mkhi.ki.wScan = (ushort)MapVirtualKey((uint)Keys.D5, 0);
kInput[1].mkhi.ki.dwFlags = KeyboardEventFlags.KEYUP;
kInput[1].mkhi.ki.time = 0;
kInput[1].mkhi.ki.dwExtraInfo = IntPtr.Zero;
SendInput(1, kInput, Marshal.SizeOf(typeof(INPUT)));

kInput[1].type = SendInputEventType.InputKeyboard;
kInput[1].mkhi.ki.wVk = '5';
kInput[1].mkhi.ki.wScan = 0;
kInput[1].mkhi.ki.dwFlags = KeyboardEventFlags.KEYUP;
kInput[1].mkhi.ki.time = 0;
kInput[1].mkhi.ki.dwExtraInfo = IntPtr.Zero;
SendInput(1, kInput, Marshal.SizeOf(typeof(INPUT)));

虽然我尝试将两者结合为:

//key down
INPUT kInput = new INPUT[2];
kInput[0].type = SendInputEventType.InputKeyboard;
kInput[0].mkhi.ki.wVk = 0;
kInput[0].mkhi.ki.wScan = (ushort) MapVirtualKey((uint) Keys.D5, 0);
kInput[0].mkhi.ki.dwFlags = KeyboardEventFlags.SCANCODE;
kInput[0].mkhi.ki.time = 0;
kInput[0].mkhi.ki.dwExtraInfo = IntPtr.Zero;

//Key Up
kInput[1].type = SendInputEventType.InputKeyboard;
kInput[1].mkhi.ki.wVk = 0;
kInput[1].mkhi.ki.wScan = (ushort)MapVirtualKey((uint)Keys.D5, 0);
kInput[1].mkhi.ki.dwFlags = KeyboardEventFlags.KEYUP;
kInput[1].mkhi.ki.time = 0;
kInput[1].mkhi.ki.dwExtraInfo = IntPtr.Zero;

//sendinput
SendInput(1, kInput, Marshal.SizeOf(typeof(INPUT)));

我已经取得了不同程度的成功,但我实际上从来没有能力模拟一个按键按住/按下事件,在这种情况下,DirectX(或其他 3d)游戏会像使用物理键盘的人那样看到我的输入...

如何使用 SendInput 模拟 DirectX 游戏中看到的按键/按住事件?

【问题讨论】:

    标签: c# pinvoke keypress sendinput


    【解决方案1】:

    要在 directX 游戏中模拟键盘事件,您需要一个键盘驱动程序的包装器。我遇到了同样的问题,并且这些方法(SendInput、SendKeys 类)都对我没有帮助。尝试使用这个wrapper,对我来说它是成功的。

    【讨论】:

      【解决方案2】:

      现在我认为这在很大程度上取决于您试图“愚弄”的游戏/3d 应用程序的具体情况。

      对于我第一次尝试欺骗我正在开发的特定游戏的一些奇怪情况,只要游戏窗口本身重新获得焦点,只需一个 SCANCODE 就足以切换技能。 (即,您打开了一个 Web 浏览器,您的应用程序切换到游戏窗口,然后触发 SCANCODE 事件)。

      但是,出于某种奇怪的原因,虽然我可以在窗口重新获得焦点后第一次让它工作,但在那之后我根本无法让事件重复触发。

      这让我很困惑,直到最终我在here 上发了一个帖子 陈述 “重复击键是键盘控制器的功能,而不是 Windows 或 SendInput 的功能。您当然可以使用计时器来模拟它,重复调用 SendInput()。”

      这让我想到,与其只发送一个按键或两个输入(一个扩展键按下,另一个按键向上),不如尝试以硬件设备可能的方式发送输入流(我实际上并不确定是否确实如此,但当时这一切似乎都是个好主意)

      所以最终,出现了失败(主要是尝试发送X个单INPUT1),我想出的是这样的:

      INPUT[] kInput = new INPUT[30];
      for (int j = 0; j < kInput.Length - 1; j++)
      {
          //activate skill
          //INPUT[] kInput = new INPUT[2];
          kInput[j].type = SendInputEventType.InputKeyboard;
          kInput[j].mkhi.ki.wVk = 0;
          kInput[j].mkhi.ki.wScan = (ushort) MapVirtualKey((uint) Keys.D5, 0);
          kInput[j].mkhi.ki.dwFlags = KeyboardEventFlags.SCANCODE;
          kInput[j].mkhi.ki.time = 0;
          kInput[j].mkhi.ki.dwExtraInfo = IntPtr.Zero;
      }
      kInput[kInput.Length - 1].type = SendInputEventType.InputKeyboard;
      kInput[kInput.Length - 1].mkhi.ki.wVk = 0;
      kInput[kInput.Length - 1].mkhi.ki.wScan = (ushort)MapVirtualKey((uint)Keys.D5, 0);
      kInput[kInput.Length - 1].mkhi.ki.dwFlags = KeyboardEventFlags.KEYUP;
      kInput[kInput.Length - 1].mkhi.ki.time = 0;
      kInput[kInput.Length - 1].mkhi.ki.dwExtraInfo = IntPtr.Zero;
      SendInput((uint)kInput.Length, kInput, Marshal.SizeOf(typeof(INPUT)));
      

      对于我目前试图“愚弄”它的游戏,这似乎对我来说足够好。这是我第一次能够模拟人类可能持有的方式使用 SendInput 持有的键。

      现在请注意,在我的示例中,我的输入数组的大小为 30。这不是 30,因为 30 是一个神奇的值,而是 30,因为 30 是我必须选择的第一个也是唯一的数字才能获得结果我想要。

      使用此代码,我能够模拟长期以来备受追捧的键盘按键被按住事件。我希望这将有助于其他一直试图达到这种效果的人。我希望这对其他人有用。我希望比我更有技术倾向的人能够解释硬件如何实际模拟输入流中的按键事件,以及如何使发送输入更接近地做同样的事情。

      【讨论】:

        猜你喜欢
        • 2012-07-20
        • 2018-11-02
        • 2012-12-15
        • 2012-05-09
        • 2010-11-20
        • 1970-01-01
        • 2017-01-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多