Skip to content

Instantly share code, notes, and snippets.

@vizee
Last active October 9, 2020 10:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vizee/edf96b836c4daf4583502024c34741e3 to your computer and use it in GitHub Desktop.
Save vizee/edf96b836c4daf4583502024c34741e3 to your computer and use it in GitHub Desktop.
hook Apps key to switch IME
/*
gcc -std=c99 -O3 -Wall -Werror \
-DUNICODE \
-o $@ $^ \
-lkernel32 -luser32 \
-Wl,--subsystem,windows,--gc-sections,--strip-all
*/
#include <windows.h>
#define WM_USER_SWITCH_IME (WM_USER + 1)
static HHOOK kbd_hook = NULL;
static int modifiers = 0;
static int shortcut_prefix = 0;
void switch_ime() {
INPUT inputs[4] = {0};
inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki.wVk = VK_LWIN;
inputs[1].type = INPUT_KEYBOARD;
inputs[1].ki.wVk = VK_SPACE;
inputs[2].type = INPUT_KEYBOARD;
inputs[2].ki.wVk = VK_LWIN;
inputs[2].ki.dwFlags = KEYEVENTF_KEYUP;
inputs[3].type = INPUT_KEYBOARD;
inputs[3].ki.wVk = VK_SPACE;
inputs[3].ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(4, inputs, sizeof(INPUT));
}
LRESULT CALLBACK kbd_proc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
KBDLLHOOKSTRUCT *hs = (KBDLLHOOKSTRUCT *)lParam;
switch (hs->vkCode) {
case VK_LSHIFT:
case VK_RSHIFT:
if (wParam == WM_KEYDOWN) {
modifiers |= 1;
} else {
modifiers &= ~1;
}
break;
case VK_LCONTROL:
case VK_RCONTROL:
if (wParam == WM_KEYDOWN) {
modifiers |= 2;
} else {
modifiers &= ~2;
}
break;
case VK_LMENU:
case VK_RMENU:
if (wParam == WM_KEYDOWN) {
modifiers |= 4;
} else {
modifiers &= ~4;
}
break;
case VK_LWIN:
case VK_RWIN:
if (wParam == WM_KEYDOWN) {
modifiers |= 8;
} else {
modifiers &= ~8;
}
break;
case 'Q':
if (wParam == WM_KEYDOWN && modifiers == 7) {
// handle ctrl+alt+shift+q
if (!shortcut_prefix) {
shortcut_prefix = 1;
} else {
UnhookWindowsHookEx(kbd_hook);
PostQuitMessage(0);
}
}
break;
case VK_APPS:
if (wParam == WM_KEYUP && modifiers == 0) {
PostMessage(NULL, WM_USER_SWITCH_IME, 0, 0);
}
if (modifiers != 8) {
return 1;
}
default:
shortcut_prefix = 0;
}
}
return CallNextHookEx(kbd_hook, nCode, wParam, lParam);
}
int main() {
kbd_hook = SetWindowsHookEx(WH_KEYBOARD_LL, kbd_proc, NULL, 0);
if (kbd_hook == NULL) {
return 1;
}
MSG msg;
while (GetMessageW(&msg, NULL, 0, 0)) {
switch (msg.message) {
case WM_USER_SWITCH_IME:
switch_ime();
break;
}
}
return (int)msg.wParam;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment