I am trying to write video game reviews after I have finished a game and I like to add some impressions in the form of screenshots to the reviews. There is one problem though: sometimes it is impossible to press the keyboard shortcut to capture a screenshot because the game requires my full attention – and all my fingers. Therefore, I miss out on a lot of action sequences. What does a programmer do in such a situation? Write a tool that scratches the itch.
I decided to not write a tool that takes the screenshot itself, which is way more complex and time consuming, but rather initiates the hotkey that triggers the capture tool. I may or may not polish the tool and put it up on Github once it is worthy of being shown. The key component is the use of the Windows API, and more specific, the SendInput function. Through that you can emulate button press events and thus trigger any hotkey. Here is a quick guide on how to use it.
If you are familiar with the Windows API then this is straight forward. There is one catch though, which is why it is worth a separate blog post. First, let me show you some code on how to use it. This snippet will emulate "Win + Alt + PrintScreen" to make use of Windows’ built-in screenshot capture that can be enabled with the Xbox Game Bar.
// (1) Emulate the hotkey by pressing all keys.
auto input1 = INPUT{};
input1.type = INPUT_KEYBOARD;
input1.ki.wVk = VK_LWIN;
auto input2 = INPUT{};
input2.type = INPUT_KEYBOARD;
input2.ki.wVk = VK_MENU;
auto input3 = INPUT{};
input3.type = INPUT_KEYBOARD;
input3.ki.wVk = VK_SNAPSHOT;
// (2) Emulate releasing all keys.
auto input4 = INPUT{};
input4.type = INPUT_KEYBOARD;
input4.ki.wVk = VK_LWIN;
input4.ki.dwFlags = KEYEVENTF_KEYUP;
auto input5 = INPUT{};
input5.type = INPUT_KEYBOARD;
input5.ki.wVk = VK_MENU;
input5.ki.dwFlags = KEYEVENTF_KEYUP;
auto input6 = INPUT{};
input6.type = INPUT_KEYBOARD;
input6.ki.wVk = VK_SNAPSHOT;
input6.ki.dwFlags = KEYEVENTF_KEYUP;
// (3)
INPUT inputs[] = {input1, input2, input3, input4, input5, input6};
// (4) “Press” the hotkeys.
auto result = SendInput(6, inputs, sizeof(INPUT));
Let us quickly go through it:
- Create three INPUT structures for all the keys that
need to be pressed and set the minimum required values:
-
type
: INPUT_KEYBOARD (there is also mouse input, among other things) -
ki.wVk
:VK_LWIN
,VK_MENU
andVK_SNAPSHOT
Since keyboard actions are emulated the KEYBDINPUT structure
ki
needs to be set. Here you only need to specify the virtual key codewVk
of the button.
-
- It is not enough to just “push” the buttons. This will
trigger the shortcut alright, but the buttons will remain pressed. It
is therefore important to create three new INPUT structures
with the same settings as in 1) and an additional
ki.dwFlags = KEYEVENTF_KEYUP
. Otherwise, further invocations will not work, and Windows will also behave weird until you have managed to depress the individual buttons (e.g. by pressing them on the keyboard). - Create an array that contains all the key input emulations.
- Call the Windows SendInput function. If all goes well, it returns the number of key events it has sent – six in this example.
That is all there is to it. The important part is 2), so keep that in mind. Whenever you want to emulate a regular button press like a human would do it, you also must depress it.
[…] a blog post in 2020, I described how to utilize the WinAPI SendInput() function to emulate hotkey presses to […]
LikeLike
[…] to focus on the game and press a keyboard shortcut to take an image of on-screen action. Therefore, I hacked something that would do the job but was not quite baked to be open-sourced as an application. I have changed that now, and boy, was […]
LikeLike