How to repeat key strokes with SendInput? - c++

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.

Related

How to use DeviceIOControl to send keyboard press to a video game?

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,

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.

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.

Handling keyboard input in win32, WM_CHAR or WM_KEYDOWN/WM_KEYUP?

So in the text editor program that i've been working on, I've used WM_CHAR to process input from the keyboard. However, I found that some of the character mesages are not recorded. For example, if I use [shift]+ number key to type a symbol such as % or &, some re recorded while others such as [shift]+9 (which results in ')'), are not recorded. So, I'm wondering if I should use WM_KEYDOWN/WMKEYUP pair to handle keyboard input. I once wrote a keylogger in assembly(actually it was just a tutorial that i was trying out) and had used WM_KEYDOWN/WM_KEYUP pairs and that worked out quite good. So, should I move on to this, or is it something unusual that is happening with my program?
Thanks,
Devjeet
This is really a long reply to your comment above, but putting it in an answer because it's too long for a comment :)
The core issue to understand here is that keys and characters are not quite the same thing. Some (but not all) keys generate characters; some keys generate different characters depending on shift or other keyboard state. And to implement an editor, you need to handle both textual input and also non-textual keyboard input like arrow keys. Now the long-winded version, picking off from what seems to be an incorrect assumption:
Apparently, windows works in really strange ways. [...] It seems that when you press [shift]+9, windows sends a VK_LEFT in the wParam of message WM_CHAR
Sounds like you might be mixing two things up here. The thing with WM_CHAR is that it gives you character codes for textual characters: so if someone presses the 9 key, you'll get '9'. If someone presses SHIFT+9, Windows will take the shift state into account - and you get '(' (if using US keyboard). But you won't ever get a WM_CHAR for arrow keys, HOME, END, and so on, since they are not textual characters. WM_KEYDOWN, on the other hand, does not deal in characters, but in VK_ codes; so pressing 9 gives you VK_9 regardless of shift state; and left arrow gives you VK_LEFT - again regardles of shift state.
The things is that WM_CHAR and WM_KEYDOWN both give you two parts to the overall input picture - but you really have to handle both to get the full picture. And have to be aware that the wParam is a very different thing in both cases. It's a character code for WM_CHAR, but a VK_ code for WM_KEYDOWN. Don't mix the two.
And to make things more confusing, VK_ values share the same values as valid characters. Open up WinUser.h (it's in the include dir under the compiler installation dir), and look for VK_LEFT:
#define VK_LEFT 0x25
Turns out that 0x25 is also the code for the '%' character (see any ascii/unicode table for details). So if WM_CHAR gets 0x25, it means shift-5 was pressed (assuming US keyboard) to create a '%'; but if WM_KEYDOWN gets 0x25, it means left arrow (VK_LEFT) was pressed. And to add a bit more confusion, the Virtual Key codes for the A-Z keys and 0-9 keys happen to be the same as the 'A'-'Z' and '0'-'9' characters - which makes it seem like chars and VK_'s are interchangable. But they're not: the code for lower case 'a', 0x61, is VK_NUMPAD1! (So getting 0x61 in WM_CHAR does mean 'a', getting it in WM_KEYDOWN means NUMPAD1. And if a user does hit the 'A' key in unshifted state, what you actually get is first a VK_A (same value as 'A') in WM_KEYDOWN, which gets translated to WM_CHAR of 'a'.)
So tying all this together, the typical way to handle keyboard is to use all of the following:
Use WM_CHAR to handle textual input: actual text keys. wParam is the character that you want to append to your string, or do whatever else with. This does all the shift- processing for you.
Use WM_KEYDOWN to handle 'meta' keys - like arrow keys, home, end, page up, and so on. Pass all the A-Z/0-9 values through, the default handling will turn them into WM_CHARs that you can handle in your WM_CHAR handler. (You can also handle numpad keys here if you want to use them for special functionality; otherwise they 'fall through' to end up as numeric WM_CHARs, depending on numlock state. Windows takes care of this, just as it handles shift state for the alphabetic keys.)
If you want to handle ALT- combos explicitly (rather than using an accelerator table), you'll get those via WM_SYSKEYDOWN.
I think there are some keys that might show up in both - Enter might show up as both a WM_KEYDOWN of VK_RETURN and as either \r or \n WM_CHAR - but my preference would be to handle it in WM_KEYDOWN, to keep editing key handling separate from text keys.
Spy++ will show you the messages being sent to a window, so you can experiment and see what messages are appropriate for your application.
If you have Visual Studio installed, it should be in your Start menu, under Programs -> Microsoft Visual Studio -> Visual Studio Tools -> Spy++.
WM_CHAR
WM_KEYDOWN
The helpful message above inspired me to create this snippet, which gives you a human-readable indication of what key was pressed from any WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP independent of the state of the modifier keys.
// get the keyboard state
BYTE keyState[256];
GetKeyboardState(keyState);
// clear all of the modifier keys so ToUnicode will ignore them
keyState[VK_CONTROL] = keyState[VK_SHIFT] = keyState[VK_MENU] = 0;
keyState[VK_LCONTROL] = keyState[VK_LSHIFT] = keyState[VK_LMENU] = 0;
keyState[VK_RCONTROL] = keyState[VK_RSHIFT] = keyState[VK_RMENU] = 0;
// convert the WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP to characters
UINT scanCode = (inLParam >> 16) & 0xFF;
int i = ToUnicode(inWParam, scanCode, keyState, outBuf, inOutBufLenCharacters, 0);
outBuf[i] = 0;
By modifying the keyState array so that all the modifier keys are clear, ToUnicode will always output the unshifted key you pressed. (So, on the English keyboard you'll never get '%' but always '5') as long as it's a human readable key. You still have to do the VK_XXX checking to sense the arrow and other non-human readable keys however.
(I was trying to rig up a user editable "hot key" system in my app, and the distinction between WM_KEYXXX and WM_CHAR was making me nuts. The code above solved that problem.)