static DWORD WINAPI hook_thread_proc(LPVOID lpParameter) { DWORD status = UIOHOOK_FAILURE; // Create the native hooks. keyboard_event_hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hook_event_proc, hInst, 0); mouse_event_hhook = SetWindowsHookEx(WH_MOUSE_LL, hook_event_proc, hInst, 0); // If we did not encounter a problem, start processing events. if (keyboard_event_hhook != NULL && mouse_event_hhook != NULL) { logger(LOG_LEVEL_DEBUG, "%s [%u]: SetWindowsHookEx() successful.\n", __FUNCTION__, __LINE__); // Check and setup modifiers. initialize_modifiers(); // Set the exit status. status = UIOHOOK_SUCCESS; // Signal that we have passed the thread initialization. SetEvent(hook_control_handle); // Block until the thread receives an WM_QUIT request. MSG message; while (GetMessage(&message, (HWND) -1, 0, 0) > 0) { TranslateMessage(&message); DispatchMessage(&message); } } else { logger(LOG_LEVEL_ERROR, "%s [%u]: SetWindowsHookEx() failed! (%#lX)\n", __FUNCTION__, __LINE__, (unsigned long) GetLastError()); status = UIOHOOK_ERROR_SET_WINDOWS_HOOK_EX; } // Destroy the native hooks. if (keyboard_event_hhook != NULL) { UnhookWindowsHookEx(keyboard_event_hhook); keyboard_event_hhook = NULL; } if (mouse_event_hhook != NULL) { UnhookWindowsHookEx(mouse_event_hhook); mouse_event_hhook = NULL; } logger(LOG_LEVEL_DEBUG, "%s [%u]: Something, something, something, complete.\n", __FUNCTION__, __LINE__); // Make sure we signal that we have passed any exception throwing code. // This should only make a difference if we had an initialization exception. SetEvent(hook_control_handle); ExitThread(status); }
// Callback function that handles events. void CALLBACK win_hook_event_proc(HWINEVENTHOOK hook, DWORD event, HWND hWnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime) { switch (event) { case EVENT_OBJECT_NAMECHANGE: logger(LOG_LEVEL_INFO, "%s [%u]: Restarting Windows input hook on window event: %#X.\n", __FUNCTION__, __LINE__, event); // Remove any keyboard or mouse hooks that are still running. if (keyboard_event_hhook != NULL) { UnhookWindowsHookEx(keyboard_event_hhook); } if (mouse_event_hhook != NULL) { UnhookWindowsHookEx(mouse_event_hhook); } // Restart the event hooks. keyboard_event_hhook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_hook_event_proc, hInst, 0); mouse_event_hhook = SetWindowsHookEx(WH_MOUSE_LL, mouse_hook_event_proc, hInst, 0); // Re-initialize modifier masks. initialize_modifiers(); // FIXME We should compare the modifier mask before and after the restart // to determine if we should synthesize missing events. // Check for event hook error. if (keyboard_event_hhook == NULL || mouse_event_hhook == NULL) { logger(LOG_LEVEL_ERROR, "%s [%u]: SetWindowsHookEx() failed! (%#lX)\n", __FUNCTION__, __LINE__, (unsigned long) GetLastError()); } break; default: logger(LOG_LEVEL_INFO, "%s [%u]: Unhandled Windows window event: %#X.\n", __FUNCTION__, __LINE__, event); } }
UIOHOOK_API int hook_run(event_type _eventsToHook) { int status = UIOHOOK_FAILURE; eventsToHook = _eventsToHook; // Set the thread id we want to signal later. hook_thread_id = GetCurrentThreadId(); // Spot check the hInst incase the library was statically linked and DllMain // did not receive a pointer on load. if (hInst == NULL) { logger(LOG_LEVEL_INFO, "%s [%u]: hInst was not set by DllMain().\n", __FUNCTION__, __LINE__); HINSTANCE hInstPE = GetModuleHandle(NULL); if (hInstPE != NULL) { DllMain(hInstPE, DLL_PROCESS_ATTACH, NULL); } else { logger(LOG_LEVEL_ERROR, "%s [%u]: Could not determine hInst for SetWindowsHookEx()! (%#lX)\n", __FUNCTION__, __LINE__, (unsigned long) GetLastError()); status = FALSE; } } bool wantsAnyKeyEvents = wants_any_key_events(), wantsAnyMouseEvents = wants_any_mouse_events(); if (!wantsAnyKeyEvents && !wantsAnyMouseEvents) return UIOHOOK_FAILURE;//...maybe? // Create the native hooks. if (wantsAnyKeyEvents) keyboard_event_hhook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_hook_event_proc, hInst, 0); if (wantsAnyMouseEvents) mouse_event_hhook = SetWindowsHookEx(WH_MOUSE_LL, mouse_hook_event_proc, hInst, 0); // Create a window event hook to listen for capture change. win_event_hhook = SetWinEventHook( EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE, NULL, win_hook_event_proc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); bool success = true; if (wantsAnyKeyEvents && keyboard_event_hhook == NULL) success = false; if (wantsAnyMouseEvents && mouse_event_hhook == NULL) success = false; // If we did not encounter a problem, start processing events. if ( success ) { if (win_event_hhook == NULL) { logger(LOG_LEVEL_WARN, "%s [%u]: SetWinEventHook() failed!\n", __FUNCTION__, __LINE__); } logger(LOG_LEVEL_DEBUG, "%s [%u]: SetWindowsHookEx() successful.\n", __FUNCTION__, __LINE__); // Check and setup modifiers. initialize_modifiers(); // Set the exit status. status = UIOHOOK_SUCCESS; // Windows does not have a hook start event or callback so we need to // manually fake it. hook_start_proc(); // Block until the thread receives an WM_QUIT request. MSG message; while (GetMessage(&message, (HWND) NULL, 0, 0) > 0) { TranslateMessage(&message); DispatchMessage(&message); } } else { logger(LOG_LEVEL_ERROR, "%s [%u]: SetWindowsHookEx() failed! (%#lX)\n", __FUNCTION__, __LINE__, (unsigned long) GetLastError()); status = UIOHOOK_ERROR_SET_WINDOWS_HOOK_EX; } // Stop the event hook and any timer still running. if (win_event_hhook != NULL) { UnhookWinEvent(win_event_hhook); win_event_hhook = NULL; } // Destroy the native hooks. if (keyboard_event_hhook != NULL) { UnhookWindowsHookEx(keyboard_event_hhook); keyboard_event_hhook = NULL; } if (mouse_event_hhook != NULL) { UnhookWindowsHookEx(mouse_event_hhook); mouse_event_hhook = NULL; } // We must explicitly call the cleanup handler because Windows does not // provide a thread cleanup method like POSIX pthread_cleanup_push/pop. hook_stop_proc(); return status; }
UIOHOOK_API int hook_run() { int status = UIOHOOK_FAILURE; // Set the thread id we want to signal later. hook_thread_id = GetCurrentThreadId(); // Spot check the hInst incase the library was statically linked and DllMain // did not receive a pointer on load. if (hInst == NULL) { logger(LOG_LEVEL_INFO, "%s [%u]: hInst was not set by DllMain().\n", __FUNCTION__, __LINE__); hInst = GetModuleHandle(NULL); if (hInst != NULL) { // Initialize native input helper functions. load_input_helper(); } else { logger(LOG_LEVEL_ERROR, "%s [%u]: Could not determine hInst for SetWindowsHookEx()! (%#lX)\n", __FUNCTION__, __LINE__, (unsigned long) GetLastError()); status = UIOHOOK_ERROR_GET_MODULE_HANDLE; } } // Create the native hooks. keyboard_event_hhook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_hook_event_proc, hInst, 0); mouse_event_hhook = SetWindowsHookEx(WH_MOUSE_LL, mouse_hook_event_proc, hInst, 0); // Create a window event hook to listen for capture change. win_event_hhook = SetWinEventHook( EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE, NULL, win_hook_event_proc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); // If we did not encounter a problem, start processing events. if (keyboard_event_hhook != NULL && mouse_event_hhook != NULL) { if (win_event_hhook == NULL) { logger(LOG_LEVEL_WARN, "%s [%u]: SetWinEventHook() failed!\n", __FUNCTION__, __LINE__); } logger(LOG_LEVEL_DEBUG, "%s [%u]: SetWindowsHookEx() successful.\n", __FUNCTION__, __LINE__); // Check and setup modifiers. initialize_modifiers(); // Set the exit status. status = UIOHOOK_SUCCESS; // Windows does not have a hook start event or callback so we need to // manually fake it. hook_start_proc(); // Block until the thread receives an WM_QUIT request. MSG message; while (GetMessage(&message, (HWND) NULL, 0, 0) > 0) { TranslateMessage(&message); DispatchMessage(&message); } } else { logger(LOG_LEVEL_ERROR, "%s [%u]: SetWindowsHookEx() failed! (%#lX)\n", __FUNCTION__, __LINE__, (unsigned long) GetLastError()); status = UIOHOOK_ERROR_SET_WINDOWS_HOOK_EX; } // Unregister any hooks that may still be installed. unregister_running_hooks(); // We must explicitly call the cleanup handler because Windows does not // provide a thread cleanup method like POSIX pthread_cleanup_push/pop. hook_stop_proc(); return status; }