3

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.

4 Answers 4

2

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)); 
Sign up to request clarification or add additional context in comments.

3 Comments

Yes, I think that's what I need to do. But oddly, those key_up events cannot be seen from the hook function. So if you're using the real keyboard, it really only sends (down, down, up) and not (down, up, down, up). I was hoping I could send events the same way as they can be recorded. The next question then is after what key events to insert a key_up event. Obviously, when pressing the Alt key, holding it and then pressing a letter, inserting key_ups is not desired as it could focus the menu or something.
Thanks @Jan, btw you mean .Itype or .type? I couldn't figure out reference on .Itype for C++, but .Itype come up with delphi codes.
If you're doing this in Delphi, you need to set input[n].Itype := INPUT_KEYBOARD. type is a reserved keyword in Delphi, so the field was renamed to Itype.
2

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:

  1. Call SendInput() with only a single INPUT structure.
  2. 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

1 Comment

I encounter the same problem, If I use SendInput() to simulate typed "XX" for example, then only one "X" char appeared, the second key stroke events seemed combined with previous events. I do not know why this API does so, it is very confusing.
1

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

2 Comments

Unfortunately, SendInput doesn't allow delays. You just give it the key events to send, as INPUT[], and it sends them right away - in one piece, with no other events coming in between them. SendWait is a .NET method, I'm not using .NET here. Also, that "wait" doesn't affect the actual SendInput call as can be seen with .NET Reflector.
(was over limit) Sending a key once always works, no problem here. It just doesn't always work to send it repeatedly, like in your syntax: sendinput 3 keydown; sendinput 3 keydown; sendinput 3 keydown; sendinput 3 keyup. (This is the sequence in which the hook function reports repeated key strokes by the user.)
0

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.

2 Comments

Sorry, I don't understand what you mean. I'm sending the exact events I record from the hook function to SendInput(). There's a time member in that data structure but it doesn't seem to have any effect.
The time member is for a timestamp, not a duration. You want to simulate the user holding down a key for 350ms, then you send a key down, wait 350ms, and send a key up.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.