jmassey
jmassey

Reputation: 131

Programatically send keyboard input to graphical application (game) in Windows

I would like to be able to use a program / script to automatically send keyboard controls to a very simple video game. There are only 3 buttons that need to work, and they can be any 3 keyboard buttons (the key bindings can be changed in the game). The controls are basically left, right, shoot.

Things I have tried: Python:

C++:

Pretty much any way I've googled this problem, everybody points to the above approaches. They all work wonderfully for getting text into Notepad or other text inputs (e.g. up arrow works fine in a command prompt, bringing up the last command input). They also do just fine sending characters to the game in the area where you'd put your name in the high score list.

I can also successfully send F12 while the game is running (this turns sound on and off). This at least shows that while in actual gameplay, it is receiving keyboard commands and apparently interpreting them correctly.

What I can't make happen is just simple action commands (left, right, shoot - the only commands the simple game really has). I have tried it with commands set to arrow keys (default) and 'a','d','w' in the game, and verified with other apps that those commands are being sent, as well as (in the case of letter keys) the high score input screen within the game itself. But it just does not register them when in actual gameplay.

I can use the on-screen keyboard from the accessibility menu to send keystrokes to play the game. If that works, it seems like there has got to be some way to accomplish this seemingly simple task, but I am at a complete loss, and search results are flooded with broken advice (the methods listed above).

Can anybody point me in the direction of something that is likely to work and not one of the things listed above that I have already tried, which all answers to questions similar to this one seem to suggest?

It would be ideal if there's a way to do this from Python directly, but I could deal with other languages if really need be.

A quick code snippet for example:

#include <windows.h>

int main()
{   
    INPUT ip;

    // Time to focus the program
    Sleep(5000);

    ip.type = INPUT_KEYBOARD;
    ip.ki.dwFlags = KEYEVENTF_SCANCODE;

    //'w'
    ip.ki.wScan = 0x11;
    SendInput(1, &ip, sizeof(INPUT));

    ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
    SendInput(1, &ip, sizeof(INPUT));
    return 0;
}

This simple program will, after 5 seconds, type the letter 'w' into Notepad (or cmd or your browser's address bar or whatever - any text input seems to work fine.) Now, in the game, if I have 'shoot' set to 'w', it works fine. If I use the on-screen keyboard and press 'w' there, it works. But the above program will not cause the 'shoot' action to occur in the game. However, if I change the scancode to 0x58 ('F12'), the program will appropriately cause the sound to come on in the game, just as if I pressed F12 on my actual keyboard.

Upvotes: 1

Views: 3285

Answers (2)

PierreBhs
PierreBhs

Reputation: 11

I had the same problem as you and stumbled upon your question. I might be almost 8 years late but I found the solution to your problem.

If you want to send inputs to your game, you actually have use the DirectInput component of the Microsoft DirectX API. You can still map them to the Virtual-Key Codes if you'd rather use them.

#include <windows.h>
#include <dinput.h> // Keyboard mapping from DirectInput

int main(void)    
{    
    INPUT ip;
    ip.type = INPUT_KEYBOARD;
    ip.ki.wVk = 0;
    ip.ki.wScan = DIKEYBOARD_W;
    ip.ki.dwFlags = KEYEVENTF_SCANCODE;
    ip.ki.time = 0;
    ip.ki.dwExtraInfo = 0;

    SendInput(1, &ip, sizeof(INPUT));
    Sleep(50);
    ip.ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(1, &ip, sizeof(INPUT));
    
    return 0;
}

I've tested it on a few AAA games and it worked on all of them. If you want longer key presses, increase the duration of the Sleep between the two calls to SendInput.

Upvotes: 1

jmassey
jmassey

Reputation: 131

It appears that the problem is that while text input generally pulls input from a buffer, realtime games will miss keypresses that come and go as fast as a virtual keyboard can press them. The solution is simply adding a short call to Sleep() between the keypress and the keyup.

Additionally, for anybody working in Python who like me tried the often-suggested SendKeys.py with no success, look for the 'playkeys' function in the code and add time.sleep(pause) after key_down(vk) , this should resolve the problem (it worked for me).

Upvotes: 2

Related Questions