How to use DeviceIOControl to send keyboard press to a video game? - c++

I am trying to make a way of passing keyboard and mouse inputs over a LAN connection. While I have been successful at doing this using the SendInput() function for things like Notepad and Visual Studio, the inputs are not registered in many video games. After doing some research, it appears that I'll need to use DeviceIOControl to accomplish the task, however I have no idea how I am supposed to do this when the keycodes have to be determined at runtime.
I'm not sure if I can just arbitrarily set the hDevice parameter to the incoming keycode or not, or what the code would look like in the end.
If it helps, the below code is what is currently being used to input key presses. The server receives a string which is parsed out to determine the key press and the state of the key (whether it's a key up or key down event). This information is passed as the parameters to this function:
void keyPress(WORD k, int state)
{
INPUT Inputs;
std::cout<<"Key="<<k<<", state="<<state<<std::endl;
Inputs.type=INPUT_KEYBOARD;
Inputs.ki.wVk=k;
if(state==1)
{
Inputs.ki.dwFlags=0;
SendInput(1, &Inputs, sizeof(INPUT));
}
else
{
Inputs.ki.dwFlags=KEYEVENTF_KEYUP;
SendInput(1, &Inputs, sizeof(INPUT));
}
if((int)k!=0) //Keycode of 0 means that the last key pressed is being held down.
{
LastKey=k;
key[ 0]=LastKey;
}
}
Also, if I am going down the wrong rabbit hole and there is a better solution, please let me know!
Thank you,

Related

SendInput doesn't work with Print Screen key

I'm making a front end for various emulators and triggering their various functionality such as save/load state, save screenshot, but with a unified interface. FS-UAE annoyingly uses "Print Screen" as its screenshot key, and I'd like to avoid the user having to change emulators from their default hotkey settings.
I've managed to simulate any key press I want with SendInput, except for the "Print Screen" key.
I haven't had any luck with using virtual key codes, I think that doesn't work with full screen applications. Hence that part of the code is commented out. (EDIT: better explanation - Virtual Key codes are ignored by DirectInput software)
Using scan codes, I can get any key to press - almost. Print Screen seems to be the odd one out.
Here's the reference I'm using for the scan codes;
https://msdn.microsoft.com/en-us/library/aa299374(v=vs.60).aspx
Below is the minimum viable code to reproduce the problem. If you run it, press a key then quickly switch to notepad and wait 2 seconds, it should press the letter "q" into notepad, then quit.
Change the scan code from 0x10 (q) to 0x37 (Print Screen), be sure to do it in both places - KEY DOWN, and KEY UP.
Now run it again, press a key and wait. To see if Print Screen worked, open MS Paint or whatever and press CTRL+V, see if you get a screenshot of your desktop. It doesn't work! But if you manually press Print Screen, and CTRL+V into MS Paint, it will work.
Why doesn't the Print Screen key work?
#include "stdafx.h"
//For create process & keyboard codes
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
int main()
{
INPUT ip = {};
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0;
ip.ki.wVk = 0;
ip.ki.dwExtraInfo = 0;
ip.ki.dwFlags = 0;
printf("Press a key, then taskswitch.\n");
system("pause");
Sleep(2000);
//KEY DOWN
ip.ki.wScan = 0x10; //0x37 PrintScreen, 0x10 Q
ip.ki.dwFlags = KEYEVENTF_SCANCODE;
//ip.ki.wVk = VK_SNAPSHOT;
//ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
//KEY UP
ip.ki.wScan = 0x10;
ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
//ip.ki.wVk = VK_SNAPSHOT;
//ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
printf("Done.\n");
system("pause");
return 0;
}
Use wVk instead of wScan, and make sure KEYEVENTF_SCANCODE is not set because that ignores wVk. You have to use VK_SNAPSHOT
INPUT ip[2] = { 0 };
ip[0].type = INPUT_KEYBOARD;
ip[0].ki.wVk = VK_SNAPSHOT;
ip[1] = ip[0];
ip[1].ki.dwFlags |= KEYEVENTF_KEYUP;
SendInput(2, ip, sizeof(INPUT));
Okay I'm answering my own question here;
So I've done some more research, found this amazing post by someone who's nutted out the details of scan codes, and it seems that Print Screen is a weird one, requiring a special sequence to be triggered properly;
https://handmade.network/forums/t/2011-keyboard_inputs_-_scancodes,_raw_input,_text_input,_key_names
(And for additional reading, there is this article on the history of the 3 different scan code sets, which gives some insight as to why some keys might be weird, as new keys were added to the standard) http://www.quadibloc.com/comp/scan.htm
However, I still couldn't get it to work trying the variety of code sequences in that article - in the end, I managed to work around my original problem by learning that FS-UAE supports an ALTERNATE key sequence for saving a screenshot: F12-S, which I am using instead and it's working great.
So I may have avoided the issue this time, but woe be the person who needs to legitimately simulate a Print Screen key press at the scan code level WITHOUT using "Virtual Key codes"... it is a mysterious arcane task that I have still not achieved.

Get any key from keyboard in C++ including keys like control

I'm programming in C++ and have run into a wall.
I need to get input from the keyboard. The problem is that I also need to get input from keys like control, scroll lock, windows key, etc. I also need to be able to differentiate between the numpad and regular numbers 0-9.
I tried using _getch(). While it can get keys like arrow keys and the numpad, I can't get keys like control, shift and scroll lock.
Does anyone have any suggestions?
There is no standard way to do this because C++ does not assume the system even has all those things.
A good solution for what you are trying to do is the SDL library. Look here:
https://www.libsdl.org/
I see the word "windows key" so I'm assuming you're programming for Windows
Use WinAPI ReadConsoleInput
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
INPUT_RECORD ir;
DWORD read;
if (!ReadConsoleInput(hInput, &ir, 1, &read) || read == 0) {
// Something went wrong
}
if (ir.EventType == KEY_EVENT) {
// Do stuff here
}
Refer to KEY_EVENT_RECORD for more information. You can get control keys states from
ir.Event.KeyEvent.dwControlKeyState
This is an example provided by Microsoft.

SendInput not working for hold key C++

I have this bit of code which uses SendInput to send a key press but it doesn't work for when I want to long hold a key (eg long hold 'a' would return 'aaaaaaaaa' in notepad).
Now I have looked all over google and the only way I can see to get around this is to keep sending the input if I want a long hold. I don't want to do that as this will just simulate 'a' being pressed over and over again.
keyboard.wVk = 0;
keyboard.wScan = MapVirtualKey(key, 0);
keyboard.dwFlags = KEYEVENTF_SCANCODE;
if (index_vector_no)
pressed[index_vector_no] = true;
keyboard.dwExtraInfo = 0;
input.type = INPUT_KEYBOARD;
input.ki = keyboard;
SendInput(1, &input, sizeof (input));
So I would like some answers to the following questions:
A) Am I right in thinking there is no way around this using SendInput and why doesn't it work for long hold?
B) What is an alternative method for successfully being able to send key down and key up signals. Preferably sending the keys to windows and not just to a particular application.
C) Is there a good lightweight C++ library I can use that handles global keyboard and mouse simulation?
Thanks in advance! =)
EDIT: Take a look at this post for more details of my problem: http://www.experts-exchange.com/Programming/Languages/Visual_Basic/Q_20833788.html
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().

Creating Alt Codes on a Laptop Without Them

My laptop has a number pad, but it does not have a NumLock key, and the numpad is actually just a copy of the row of numbers above the letters. This is confirmed by the virtual key codes sent when I press these keys.
I'm trying to develop a small program to mimic alt codes when the alt key and regular numbers are pressed. I use a low-level keyboard hook (I have a similar format working in another program), and first check to see if either alt key is down. If either is, I loop through the VK codes 0x30-0x39 (0-9 keys). If one of those is pressed down at that moment, I discard the actual keystroke by returning a value of 1, and instead send a numpad version of that key instead (alt is still pressed down at this time).
I can confirm that the hook is being reached, and that the alt key being down is being recognized successfully. However, when I check for matches on 0-9, either only a couple are printed before nothing matches after that, or I have to lift up and press down the alt key every time I press a number. Additionally, one number may be printed 16 times after releasing alt having pressed a number, and then holding down alt and pressing another (this one is 16x).
Also, I can confirm the SendInput sequence works via copying the part from the hook, putting it into the main function and replacing i with 0x30. Upon running, a 0 will be typed onto the text document.
When holding down ALT(down)+6+5+ALT(up) in a text document, "65" is what shows. If I add another ALT(down)+6, 16 sixes appear.
Hook Procedure:
LRESULT CALLBACK proc (int code, WPARAM wParam, LPARAM event) //hook proc
{
if (code < HC_ACTION) //don't process if not meant to
return CallNextHookEx (0, code, wParam, event);
if (GetAsyncKeyState (VK_MENU) & 0x8000) //if either alt is down
{
for (int i = 0x30; i <= 0x39; ++i) //loop 0-9
{
if (GetAsyncKeyState (i) & 0x8000) //if index is down
{
cout << "MATCH\n"; //debug
input.ki.wVk = i + 0x30; //set VK code to numpad version of index
input.ki.dwFlags = 0; //key is being pressed
SendInput (1, &input, sizeof (INPUT)); //send keystroke down
input.ki.dwFlags = KEYEVENTF_KEYUP; //key is being released
SendInput (1, &input, sizeof (INPUT)); //send keystroke up
while (GetAsyncKeyState (i) & 0x8000) //wait for normal key to be released
Sleep (10); //don't hog CPU
return 1; //discard normal key
} //end if match
} //end for
} //end if alt
return CallNextHookEx (0, code, wParam, event); //if any key not handled, pass on
} //end function
Well, I finally came back to this and after some more testing I discovered that programmatically sending [ALT ] [num6] [num5] [ALT ] does nothing whatsoever. I find this odd because I am able to simulate the volume control keys on the Mac keyboards despite not having those keys.
Since the computer simply can't send alt codes, I declare this helpful tool royally screwed unless I map thousands of characters.
EDIT:
Here's what you need to do to get the number pad working on the G74SX-XA1:
Download the BIOS 203 (I don't know if 202 works or not, I went from 201 to 203).
Put the file on a FAT32-formatted flash drive.
Restart the computer and either press F4 to go right into EasyFlash, or navigate to it through the BIOS. The Winflash program that comes with it doesn't work.
Select the updated BIOS file on the flash drive.
Now the numlock light will always be on and the number pad will have the virtual key codes of a number pad, not the numbers above the letters. This naturally includes ALT codes working.

How to repeat key strokes with SendInput?

I'm writing a little tool in VC++ to record key strokes to replay them later, a macro recorder. It works quite nice already, using a keyboard hook function that reads each and every key press and release event. The playback works with the SendInput() function and generally also works fine - except for repeating key strokes. Pressing a key several times after releasing it every time is no problem. But pressing it and holding it down, for the input character to be repeated, can be recorded but can only be replayed in some applications. Some accept and enter the character multiple times, some do it only once. (It is reproducible which does which.) The macro recorder itself also sees the held down key pressed just a single time during playback, through its monitoring hook.
So, how can I make SendInput send multiple subsequent key strokes of a single key without adding key release events on my own in between? Sending a sequence of [press] [press] [press] ... [release] doesn't always work.
You could send Multiple keys in one SendInput calls, but you will still need to set keyup flags on every char to get same results on every type of keystrokes.
if you need to send "aa", you can do like this.
INPUT input[4];
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = 0;
input[0].ki.wScan = 'a';
input[0].ki.dwFlags = 0;
input[1].type = INPUT_KEYBOARD;
input[1].ki.wVk = 0;
input[1].ki.wScan = 'a';
input[1].ki.dwFlags = KEYEVENTF_KEYUP;
input[2].type = INPUT_KEYBOARD;
input[2].ki.wVk = 0;
input[2].ki.wScan = 'a';
input[2].ki.dwFlags = 0;
input[3].type = INPUT_KEYBOARD;
input[3].ki.wVk = 0;
input[3].ki.wScan = 'a';
input[3].ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(4, input, sizeof(INPUT));
I'm not sure about your exact sequence of keystrokes, but I had a similar issue recently. I wrote a tiny Win32 tool [1] to send keys when a global shortcut key is pressed. When characters were repeated, e.g., "aaabc", the repeated characters were lost. I tried many combinations of KeyDown and KeyUp, but repeated characters were always lost.
Then I found this blog post: https://batchloaf.wordpress.com/2014/10/02/using-sendinput-to-type-unicode-characters/
While the author does not specifically discuss repeating characters, it inspired me to try SendInput() with only a single INPUT structure. This technique works very well for me.
In short:
Call SendInput() with only a single INPUT structure.
To simulate a single typed (regular) key, e.g., z, try this:
Send single KeyDown event: ki.dwFlags = KEYEVENTF_UNICODE
Send single KeyUp event: ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP
[1] https://github.com/kevinarpe/win32/tree/master/send_input
Many people experience issues with the keyup and keydown calls being "dismissed" or "dropped", and alot of people have resolved their problems by placing a small buffer amount of time between the two, to assure that all commands are transfered:
sendinput alt keydown
sendinput 3 keydown
sleep 50
sendinput 3 keyup
sendinput alt keyup
There's also a SendInput.SendWait command....
Cheers
As far as I know, the way it works is if a key down event is received with no key up event for a certain period of time (the repeat delay), the key is considered "repeating" until a key up occurs.
Since sending press, press, press, release doesn't work always, have you tried recording the time between the key down and key up, then repeating the commands in that same time? It becomes real time, but it should trigger the same repeat actions that way.
I can't think of any other way to end up with the same amount of "key repeats" as the original since those aren't recorded as individual key presses.