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

北城余情 提交于 2019-12-31 06:57:33

问题


I've often struggled with simulating keyboard press events for various bots, or other GUI automating programs.

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...

How would one, using SendInput, emulate a key press/hold event as seen by a DirectX game?


回答1:


To simulate keyboard events in directX games you need wrapper for a keyboard driver. I had the same issue, and neither of this methods (SendInput, SendKeys class) doesn't help me. Try to use this wrapper, to me it was successfully.




回答2:


Now I think a lot of this actually depends on the specifics of the game/3d application you are trying to 'fool'.

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. (I.E. you have a web browser open, your application switches to the game window and then fires the SCANCODE event).

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()."

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)

So eventually, and there were failures (mainly trying to send X amount of single INPUT1), what I came up with, was this:

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.

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.

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.



来源:https://stackoverflow.com/questions/17781021/c-sharp-p-invoke-how-to-simulate-a-keypress-event-using-sendinput-for-directx-ga

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!