void on_library_unload() { // Disable the event hook. //hook_stop(); // Cleanup native input functions. unload_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); }
void on_library_unload() { // Cleanup native input functions. unload_input_helper(); }