/** * Gets a raw key press from user and converts it to a string. * * @param self Pointer to self. * args The arguments passed from python program, must * be parsed by python's parse tuple function. * @return PyObject version of string. */ static PyObject * getkeypress(PyObject * self, PyObject *args) { char * returnString = ""; rootCheck(); Config config; getDeviceFile(&config); int kbd_fd = openKeyboardDeviceFile(config.deviceFile); assert(kbd_fd > 0); // Daemonize process. Don't change working directory but redirect standard // inputs and outputs to /dev/null // if (daemon(1, 0) == -1) { // LOG_ERROR("%s", strerror(errno)); // exit(-1); // } uint8_t shift_pressed = 0; input_event event; while (read(kbd_fd, &event, sizeof(input_event)) > 0) { if (event.type == EV_KEY) { if (event.value == KEY_PRESS) { char *name = getKeyText(event.code, shift_pressed); if (isShift(event.code)) { shift_pressed++; } else if (strcmp(name, UNKNOWN_KEY) != 0) { //LOG("%s", name); returnString = strdup(name); break; } } else if (event.value == KEY_RELEASE) { if (isShift(event.code)) { shift_pressed--; } } } assert(shift_pressed >= 0 && shift_pressed <= 2); } Config_cleanup(&config); close(kbd_fd); return Py_BuildValue("s", returnString); }
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); }