I've implemented a hook procedure that catches some Alt+letter
key combinations and injects predefined strings. An example of a hook procedure is shown below. It detects the hotkeys LeftAlt+Q
and LeftAlt+A
and injects the string ABCD1234
in both cases, using the WinAPI function SendInput()
.
#include <windows.h>
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
void DisplayString()
{
INPUT in[24] = { 0 };
int i;
for (i = 0; i < ARRAYSIZE(in); i++) in[i].type = INPUT_KEYBOARD;
i = 0;
in[i++].ki.wVk = VK_CONTROL; // CTRL
in[i].ki.wVk = VK_CONTROL; // CTRL Up
in[i++].ki.dwFlags = KEYEVENTF_KEYUP;
in[i].ki.wVk = VK_LMENU; // LeftAlt Up
in[i++].ki.dwFlags = KEYEVENTF_KEYUP;
in[i++].ki.wVk = VK_LSHIFT; // LeftShift down
in[i++].ki.wVk = 'A';
in[i].ki.wVk = 'A';
in[i++].ki.dwFlags = KEYEVENTF_KEYUP;
in[i++].ki.wVk = 'B';
in[i].ki.wVk = 'B';
in[i++].ki.dwFlags = KEYEVENTF_KEYUP;
in[i++].ki.wVk = 'C';
in[i].ki.wVk = 'C';
in[i++].ki.dwFlags = KEYEVENTF_KEYUP;
in[i++].ki.wVk = 'D';
in[i].ki.wVk = 'D';
in[i++].ki.dwFlags = KEYEVENTF_KEYUP;
in[i].ki.wVk = VK_LSHIFT; // LeftShift Up
in[i++].ki.dwFlags = KEYEVENTF_KEYUP;
in[i++].ki.wVk = '1';
in[i].ki.wVk = '1';
in[i++].ki.dwFlags = KEYEVENTF_KEYUP;
in[i++].ki.wVk = '2';
in[i].ki.wVk = '2';
in[i++].ki.dwFlags = KEYEVENTF_KEYUP;
in[i++].ki.wVk = '3';
in[i].ki.wVk = '3';
in[i++].ki.dwFlags = KEYEVENTF_KEYUP;
in[i++].ki.wVk = '4';
in[i].ki.wVk = '4';
in[i++].ki.dwFlags = KEYEVENTF_KEYUP;
in[i++].ki.wVk = VK_CONTROL; // CTRL
in[i++].ki.wVk = VK_LMENU; // LeftAlt Down
in[i].ki.wVk = VK_CONTROL; // CTRL Up
in[i++].ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(ARRAYSIZE(in), in, sizeof(INPUT));
}
HHOOK hHook{ NULL };
#define VK_HOT_1 0x51
#define VK_HOT_2 0x41
extern "C" __declspec(dllexport)
LRESULT CALLBACK KeyboardHookProc(int code, WPARAM wParam, LPARAM lParam)
{
if (code < 0) return CallNextHookEx(hHook, code, wParam, lParam);
// If LeftAlt pressed
if (wParam == WM_SYSKEYDOWN && (GetAsyncKeyState(VK_LMENU) & 0x80000000))
{
DWORD vkCode = ((KBDLLHOOKSTRUCT*)lParam)->vkCode; // virtual-key code
if (vkCode == VK_HOT_1 || vkCode == VK_HOT_2)
{
DisplayString();
return 1;
}
}
return CallNextHookEx(hHook, code, wParam, lParam);
}
The hook procedure is installed using the function SetWindowsHookExW()
.
The program works as expected in a broad range of applications. I've tested it with WordPad, Notepad++, Chrome, Edge, Command Prompt, PowerShell, and Visual Studio. However, the program exhibits unexplained behavior when the string is injected into Notepad. Only 2-4 characters come up, and the rest appear when additional keys are pressed on the keyboard, with a couple of characters following each key down.
This behavior is new. I used Notepad to test this program during development some weeks ago, and Notepad worked fine. I'm using this program on several PCs, and some work problem-free. All the PCs use Windows 11.
EDIT: AutoHotkey
is an advanced Windows app for implementing user-defined hotkeys. The user configures the key combinations to use, and the action to perform when a hotkey is pressed. I've configured AutoHotkey
for the same hotkeys and actions as in my application and tested it on a Windows 11 PC. AutoHotkey's
behavior is the same as that of my application: injecting text works fine in all tested apps but Notepad
.
Moreover, the behavior I observe now is different. The whole string comes out intermittently, two characters at a time, seemingly at the rate of cursor blinks.
I find that if I turn off the Autocorrect setting in Notepad then all my SendInput text appears.
It seems that if the text you send creates a spelling error (to which Notepad will put a red squiggly line), then autocorrect will interrupt the input stream and not all the text will be sent to the window.
I'm using Notepad v11.2410.21.0.
I've registered a Microsoft Feedback issue here: https://aka.ms/AAums69
In Notepad it also appears that the spellcheck will interrupt the input stream. i.e. To allow SendInput to work in Notepad both spellcheck and autocorrect need to be turned off.