void on_library_load() { // Display the copyright on library load. COPYRIGHT(); // Initialize Native Input Functions. load_input_helper(); }
void on_library_load() { // Initialize Native Input Functions. load_input_helper(); }
static void *hook_thread_proc(void *arg) { int *status = (int *) arg; *status = UIOHOOK_FAILURE; bool accessibilityEnabled = false; // FIXME Move to osx_input_helper.h after testing. #ifdef USE_WEAK_IMPORT // Check and make sure assistive devices is enabled. if (AXIsProcessTrustedWithOptions != NULL) { // New accessibility API 10.9 and later. const void * keys[] = { kAXTrustedCheckOptionPrompt }; const void * values[] = { kCFBooleanTrue }; CFDictionaryRef options = CFDictionaryCreate( kCFAllocatorDefault, keys, values, sizeof(keys) / sizeof(*keys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); accessibilityEnabled = AXIsProcessTrustedWithOptions(options); } else { // Old accessibility check 10.8 and older. accessibilityEnabled = AXAPIEnabled(); } #else // Dynamically load the application services framework for examination. const char *dlError = NULL; void *libApplicaitonServices = dlopen("/System/Library/Frameworks/ApplicationServices.framework/ApplicationServices", RTLD_LAZY); dlError = dlerror(); if (libApplicaitonServices != NULL && dlError == NULL) { // Check for the new function AXIsProcessTrustedWithOptions(). *(void **) (&AXIsProcessTrustedWithOptions_t) = dlsym(libApplicaitonServices, "AXIsProcessTrustedWithOptions"); dlError = dlerror(); if (AXIsProcessTrustedWithOptions_t != NULL && dlError == NULL) { // Check for property kAXTrustedCheckOptionPrompt CFStringRef kAXTrustedCheckOptionPrompt_t = (CFStringRef) dlsym(libApplicaitonServices, "kAXTrustedCheckOptionPrompt"); dlError = dlerror(); if (kAXTrustedCheckOptionPrompt_t != NULL && dlError == NULL) { // New accessibility API 10.9 and later. // FIXME This is causing a segfault on 10.9 probably due to an invalid pointer type. const void * keys[] = { kAXTrustedCheckOptionPrompt_t }; const void * values[] = { kCFBooleanTrue }; CFDictionaryRef options = CFDictionaryCreate( kCFAllocatorDefault, keys, values, sizeof(keys) / sizeof(*keys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); accessibilityEnabled = (*AXIsProcessTrustedWithOptions_t)(options); } } else { logger(LOG_LEVEL_DEBUG, "%s [%u]: Falling back to AXAPIEnabled(). (%s)\n", __FUNCTION__, __LINE__, dlError); // Check for the fallback function AXAPIEnabled(). *(void **) (&AXAPIEnabled_t) = dlsym(libApplicaitonServices, "AXAPIEnabled"); dlError = dlerror(); if (AXAPIEnabled_t != NULL && dlError == NULL) { // Old accessibility check 10.8 and older. accessibilityEnabled = (*AXAPIEnabled_t)(); } else { // Could not load the AXAPIEnabled function! logger(LOG_LEVEL_ERROR, "%s [%u]: Failed to locate AXAPIEnabled()! (%s)\n", __FUNCTION__, __LINE__, dlError); } } dlclose(libApplicaitonServices); } else { // Could not load the ApplicationServices framework! logger(LOG_LEVEL_ERROR, "%s [%u]: Failed to lazy load the ApplicationServices framework! (%s)\n", __FUNCTION__, __LINE__, dlError); } #endif if (accessibilityEnabled == true) { logger(LOG_LEVEL_DEBUG, "%s [%u]: Accessibility API is enabled.\n", __FUNCTION__, __LINE__); // Setup the event mask to listen for. CGEventMask event_mask = CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp) | CGEventMaskBit(kCGEventFlagsChanged) | CGEventMaskBit(kCGEventLeftMouseDown) | CGEventMaskBit(kCGEventLeftMouseUp) | CGEventMaskBit(kCGEventLeftMouseDragged) | CGEventMaskBit(kCGEventRightMouseDown) | CGEventMaskBit(kCGEventRightMouseUp) | CGEventMaskBit(kCGEventRightMouseDragged) | CGEventMaskBit(kCGEventOtherMouseDown) | CGEventMaskBit(kCGEventOtherMouseUp) | CGEventMaskBit(kCGEventOtherMouseDragged) | CGEventMaskBit(kCGEventMouseMoved) | CGEventMaskBit(kCGEventScrollWheel); #ifdef USE_DEBUG event_mask |= CGEventMaskBit(kCGEventNull); #endif CFMachPortRef event_port = CGEventTapCreate( kCGSessionEventTap, // kCGHIDEventTap kCGHeadInsertEventTap, // kCGTailAppendEventTap kCGEventTapOptionListenOnly, // kCGEventTapOptionDefault See Bug #22 event_mask, hook_event_proc, NULL ); if (event_port != NULL) { logger(LOG_LEVEL_DEBUG, "%s [%u]: CGEventTapCreate Successful.\n", __FUNCTION__, __LINE__); event_source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, event_port, 0); if (event_source != NULL) { logger(LOG_LEVEL_DEBUG, "%s [%u]: CFMachPortCreateRunLoopSource successful.\n", __FUNCTION__, __LINE__); event_loop = CFRunLoopGetCurrent(); if (event_loop != NULL) { logger(LOG_LEVEL_DEBUG, "%s [%u]: CFRunLoopGetCurrent successful.\n", __FUNCTION__, __LINE__); // Initialize Native Input Functions. load_input_helper(); // Create run loop observers. CFRunLoopObserverRef observer = CFRunLoopObserverCreate( kCFAllocatorDefault, kCFRunLoopEntry | kCFRunLoopExit, //kCFRunLoopAllActivities, true, 0, hook_status_proc, NULL ); if (observer != NULL) { // Set the exit status. *status = UIOHOOK_SUCCESS; start_message_port_runloop(); CFRunLoopAddSource(event_loop, event_source, kCFRunLoopDefaultMode); CFRunLoopAddObserver(event_loop, observer, kCFRunLoopDefaultMode); CFRunLoopRun(); // Lock back up until we are done processing the exit. CFRunLoopRemoveObserver(event_loop, observer, kCFRunLoopDefaultMode); CFRunLoopRemoveSource(event_loop, event_source, kCFRunLoopDefaultMode); CFRunLoopObserverInvalidate(observer); stop_message_port_runloop(); } else { // We cant do a whole lot of anything if we cant // create run loop observer. logger(LOG_LEVEL_ERROR, "%s [%u]: CFRunLoopObserverCreate failure!\n", __FUNCTION__, __LINE__); // Set the exit status. *status = UIOHOOK_ERROR_OBSERVER_CREATE; } // Cleanup Native Input Functions. unload_input_helper(); } else { logger(LOG_LEVEL_ERROR, "%s [%u]: CFRunLoopGetCurrent failure!\n", __FUNCTION__, __LINE__); // Set the exit status. *status = UIOHOOK_ERROR_GET_RUNLOOP; } // Clean up the event source. CFRelease(event_source); } else { logger(LOG_LEVEL_ERROR, "%s [%u]: CFMachPortCreateRunLoopSource failure!\n", __FUNCTION__, __LINE__); // Set the exit status. *status = UIOHOOK_ERROR_CREATE_RUN_LOOP_SOURCE; } // Stop the CFMachPort from receiving any more messages. CFMachPortInvalidate(event_port); CFRelease(event_port); } else { logger(LOG_LEVEL_ERROR, "%s [%u]: Failed to create event port!\n", __FUNCTION__, __LINE__); // Set the exit status. *status = UIOHOOK_ERROR_EVENT_PORT; } } else { logger(LOG_LEVEL_ERROR, "%s [%u]: Accessibility API is disabled!\n", __FUNCTION__, __LINE__); // Set the exit status. *status = UIOHOOK_ERROR_AXAPI_DISABLED; } 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. pthread_mutex_unlock(&hook_control_mutex); pthread_exit(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; }