简体   繁体   English

C#p / Invoke如何使用SendInput模拟DirectX游戏的keyPRESS事件

[英]C# p/Invoke How to simulate a keyPRESS event using SendInput for DirectX games

I've often struggled with simulating keyboard press events for various bots, or other GUI automating programs. 我经常在模拟各种机器人的键盘按下事件或其他GUI自动化程序方面遇到困难。

I've managed to simulate keydown events using: 我设法使用以下方法模拟按键事件:

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)));

OR 要么

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)));

and keyup events using: 和键盘事件使用:

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)));

OR 要么

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)));

And while my attempts to combine the two as: 而我尝试将两者结合为:

//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)));

Have had varying degrees of success, I was never actually capable of emulating a key hold/press event where a DirectX (or other 3d) game would see my input in quite the way a human with a physical keyboard would... 取得了不同程度的成功,但我从来没有真正能够模拟按键保持/按下事件,而DirectX(或其他3d)游戏会像使用物理键盘的人那样看待我的输入...

How would one, using SendInput, emulate a key press/hold event as seen by a DirectX game? 如何使用SendInput模拟DirectX游戏中看到的按键/按住事件?

To simulate keyboard events in directX games you need wrapper for a keyboard driver. 要在DirectX游戏中模拟键盘事件,您需要包装键盘驱动程序。 I had the same issue, and neither of this methods (SendInput, SendKeys class) doesn't help me. 我遇到了同样的问题,而且这两种方法(SendInput,SendKeys类)都不能帮上忙。 Try to use this wrapper , to me it was successfully. 尝试使用此包装器 ,对我而言已成功。

Now I think a lot of this actually depends on the specifics of the game/3d application you are trying to 'fool'. 现在,我认为这实际上取决于您要“傻瓜”的游戏/ 3d应用程序的具体情况。

For some odd case in my first attempt to trick the particular game I was working on it would accept merely a single SCANCODE as enough of a keypress to toggle a skill, as long as the game window itself was regaining focus. 在某种奇怪的情况下,我第一次尝试欺骗正在开发的特定游戏时,只要游戏窗口本身重新获得了焦点,它仅接受一个SCANCODE就足以切换技能。 (IE you have a web browser open, your application switches to the game window and then fires the SCANCODE event). (即,您已打开Web浏览器,您的应用程序将切换到游戏窗口,然后触发SCANCODE事件)。

However, for some odd reason, while I could get this to work for the first time after the window regained focus, I couldn't get the event to repeatedly fire at all after that. 但是,出于某种奇怪的原因,虽然我可以在窗口重新获得焦点后第一次使它工作,但是之后我再也无法重复触发该事件。

This puzzled me, until eventually I came to a post on here stating "Repeating keystrokes is a feature of the keyboard controller, not of Windows or SendInput. You can certainly emulate it with a timer, repeatedly calling SendInput()." 这让我感到困惑,直到最终我在这里发表了一篇文章,指出“重复击键是键盘控制器的功能,而不是Windows或SendInput的功能。您当然可以使用计时器来模拟它,重复调用SendInput()。”

Which gave me the idea that instead of sending just one keystroke, or two inputs (one extended key down, the other a key up), why not attempt to send a stream of inputs the way a hardware device MIGHT (which I don't actually know for sure if it does, but it all seemed like a good idea at the time) 这给了我一个想法,而不是发送一个击键或两个输入(一个向下扩展键,另一个向上键),为什么不尝试以硬件设备MIGHT的方式发送输入流(我不这样做)确实知道是否可以,但是当时一切似乎都是个好主意)

So eventually, and there were failures (mainly trying to send X amount of single INPUT 1 ), what I came up with, was this: 因此最终,出现了故障(主要是尝试发送X数量的单个INPUT 1 ),我想到的是:

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)));

And this seems to work well enough for me for the game I am current trying to 'fool' with it. 对于我目前试图“弄混”它的游戏来说,这似乎对我来说足够好。 This is the first time I have been able to simulate a key being held with SendInput the way that a human might hold one. 这是我第一次能够模拟人类用SendInput握住的键。

Now please note that in my example, my Input array is of size 30. This isn't 30 because 30 is some magic value, it's 30 because because 30 was the first and only number I had to pick to achieve the result I desired. 现在请注意,在我的示例中,我的Input数组的大小为30。这不是30,因为30是一些神奇的值,而它是30,因为因为30是我必须选择的第一个也是唯一的数字,才能获得所需的结果。

Using this code, I have been able to emulate the long sought after keyboard key being held event. 使用此代码,我已经能够模拟键盘按键被按住事件所追寻的时间。 I hope that this will help others who have been trying to achieve this effect. 我希望这将对其他尝试实现此效果的人有所帮助。 I hope that this works for others. 我希望这对其他人有用。 And I hope that people more technically inclined than myself, can explain how hardware actually simulates a key held event in the input stream and how send input can be made to more closely do the same. 我希望人们比我更倾向于技术方面,可以解释硬件如何实际模拟输入流中的关键事件以及如何使发送输入更紧密地执行相同操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM