static void flushKeyEvents (KeyboardInstanceObject *kio) { const KeyEventEntry *event = kio->events.buffer; while (kio->events.count) { logKeyEvent("flushing", event->code, event->press); forwardKeyEvent(kio, event->code, event->press); event += 1; kio->events.count -= 1; } memset(kio->deferred.mask, 0, kio->deferred.size); kio->deferred.modifiersOnly = 0; }
LRESULT CALLBACK keyevent(int code, WPARAM wparam, LPARAM lparam) { static bool shiftPressed = false; static bool mod3Pressed = false; static bool mod4Pressed = false; KBDLLHOOKSTRUCT keyInfo; if (code == HC_ACTION && (wparam == WM_SYSKEYUP || wparam == WM_KEYUP || wparam == WM_SYSKEYDOWN || wparam == WM_KEYDOWN)) { keyInfo = *((KBDLLHOOKSTRUCT *) lparam); if (keyInfo.flags & LLKHF_INJECTED) { // process injected events like normal, because most probably we are injecting them logKeyEvent("injected", keyInfo); return CallNextHookEx(NULL, code, wparam, lparam); } } if (bypassMode) return CallNextHookEx(NULL, code, wparam, lparam); if (code == HC_ACTION && (wparam == WM_SYSKEYUP || wparam == WM_KEYUP)) { logKeyEvent("key up", keyInfo); if (isShift(keyInfo)) { shiftPressed = false; keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0); return -1; } else if (isMod3(keyInfo)) { mod3Pressed = false; return -1; } else if (isMod4(keyInfo)) { mod4Pressed = false; return -1; } } else if (code == HC_ACTION && (wparam == WM_SYSKEYDOWN || wparam == WM_KEYDOWN)) { logKeyEvent("key down", keyInfo); unsigned level = 1; if (shiftPressed) level = 2; if (mod3Pressed) level = 3; if (mod4Pressed) level = 4; if (isShift(keyInfo)) { shiftPressed = true; keybd_event(VK_SHIFT, 0, 0, 0); return -1; } else if (isMod3(keyInfo)) { mod3Pressed = true; return -1; } else if (isMod4(keyInfo)) { /* ALTGR triggers two keys: LCONTROL and RMENU we don't want to have any of those two here effective but return -1 seems to change nothing, so we simply send keyup here. */ keybd_event(VK_RMENU, 0, KEYEVENTF_KEYUP, 0); mod4Pressed = true; return -1; } else if (level == 1 && handleLayer1SpecialCases(keyInfo)) { return -1; } else if (level == 4 && handleLayer4SpecialCases(keyInfo)) { return -1; } else { TCHAR key = mapScanCodeToChar(level, keyInfo.scanCode); if (key != 0 && (keyInfo.flags & LLKHF_INJECTED) == 0) { // if key must be mapped printf("Mapped %d->%c (level %u)\n", keyInfo.scanCode, key, level); //BYTE state[256]; //GetKeyboardState(state); sendChar(key, keyInfo); //SetKeyboardState(state); return -1; } } } return CallNextHookEx(NULL, code, wparam, lparam); }
void handleKeyEvent (KeyboardInstanceObject *kio, int code, int press) { KeyTableState state = KTS_UNBOUND; logKeyEvent("received", code, press); if (kio->kmo->isActive) { if ((code >= 0) && (code < keyCodeCount)) { const KeyValue *kv = &keyCodeMap[code]; if ((kv->group != KBD_GROUP(SPECIAL)) || (kv->number != KBD_KEY(SPECIAL, Unmapped))) { if ((kv->group == KBD_GROUP(SPECIAL)) && (kv->number == KBD_KEY(SPECIAL, Ignore))) return; state = kio->kmo->handleKeyEvent(kv->group, kv->number, press); } } } if (state == KTS_HOTKEY) { logKeyEvent("ignoring", code, press); } else { typedef enum { WKA_NONE, WKA_CURRENT, WKA_ALL } WriteKeysAction; WriteKeysAction action = WKA_NONE; if (press) { kio->deferred.modifiersOnly = state == KTS_MODIFIERS; if (state == KTS_UNBOUND) { action = WKA_ALL; } else { if (kio->events.count == kio->events.size) { unsigned int newSize = kio->events.size? kio->events.size<<1: 0X1; KeyEventEntry *newBuffer = realloc(kio->events.buffer, (newSize * sizeof(*newBuffer))); if (newBuffer) { kio->events.buffer = newBuffer; kio->events.size = newSize; } else { logMallocError(); } } if (kio->events.count < kio->events.size) { KeyEventEntry *event = &kio->events.buffer[kio->events.count++]; event->code = code; event->press = press; BITMASK_SET(kio->deferred.mask, code); logKeyEvent("deferring", code, press); } else { logKeyEvent("discarding", code, press); } } } else if (kio->deferred.modifiersOnly) { kio->deferred.modifiersOnly = 0; action = WKA_ALL; } else if (BITMASK_TEST(kio->deferred.mask, code)) { KeyEventEntry *to = kio->events.buffer; const KeyEventEntry *from = to; unsigned int count = kio->events.count; while (count) { if (from->code == code) { logKeyEvent("dropping", from->code, from->press); } else if (to != from) { *to++ = *from; } else { to += 1; } from += 1, count -= 1; } kio->events.count = to - kio->events.buffer; BITMASK_CLEAR(kio->deferred.mask, code); } else { action = WKA_CURRENT; } switch (action) { case WKA_ALL: flushKeyEvents(kio); case WKA_CURRENT: logKeyEvent("forwarding", code, press); forwardKeyEvent(kio, code, press); case WKA_NONE: break; } } }