optimize darwin check accessibility not loop

This commit is contained in:
vcaesar 2019-02-19 11:47:56 -04:00
parent 9fa8b6c408
commit 3f023c292f

View File

@ -1110,235 +1110,234 @@ CGEventRef hook_event_proc(CGEventTapProxy tap_proxy, CGEventType type, CGEventR
IOHOOK_API int hook_run() { IOHOOK_API int hook_run() {
int status = IOHOOK_SUCCESS; int status = IOHOOK_SUCCESS;
do { // Check for accessibility each time we start the loop.
// Reset the restart flag... if (is_accessibility_enabled()) {
restart_tap = false; logger(LOG_LEVEL_DEBUG, "%s [%u]: Accessibility API is enabled.\n",
__FUNCTION__, __LINE__);
// Check for accessibility each time we start the loop. do {
if (is_accessibility_enabled()) { // Reset the restart flag...
logger(LOG_LEVEL_DEBUG, "%s [%u]: Accessibility API is enabled.\n", restart_tap = false;
__FUNCTION__, __LINE__);
// Initialize starting modifiers. // Initialize starting modifiers.
initialize_modifiers(); initialize_modifiers();
// Try and allocate memory for hook_info. // Try and allocate memory for hook_info.
hook_info *hook = malloc(sizeof(hook_info)); hook_info *hook = malloc(sizeof(hook_info));
if (hook != NULL) { if (hook != NULL) {
// Setup the event mask to listen for. // Setup the event mask to listen for.
#ifdef USE_DEBUG #ifdef USE_DEBUG
CGEventMask event_mask = kCGEventMaskForAllEvents; CGEventMask event_mask = kCGEventMaskForAllEvents;
#else #else
CGEventMask event_mask = CGEventMaskBit(kCGEventKeyDown) | CGEventMask event_mask = CGEventMaskBit(kCGEventKeyDown) |
CGEventMaskBit(kCGEventKeyUp) | CGEventMaskBit(kCGEventKeyUp) |
CGEventMaskBit(kCGEventFlagsChanged) | CGEventMaskBit(kCGEventFlagsChanged) |
CGEventMaskBit(kCGEventLeftMouseDown) | CGEventMaskBit(kCGEventLeftMouseDown) |
CGEventMaskBit(kCGEventLeftMouseUp) | CGEventMaskBit(kCGEventLeftMouseUp) |
CGEventMaskBit(kCGEventLeftMouseDragged) | CGEventMaskBit(kCGEventLeftMouseDragged) |
CGEventMaskBit(kCGEventRightMouseDown) | CGEventMaskBit(kCGEventRightMouseDown) |
CGEventMaskBit(kCGEventRightMouseUp) | CGEventMaskBit(kCGEventRightMouseUp) |
CGEventMaskBit(kCGEventRightMouseDragged) | CGEventMaskBit(kCGEventRightMouseDragged) |
CGEventMaskBit(kCGEventOtherMouseDown) | CGEventMaskBit(kCGEventOtherMouseDown) |
CGEventMaskBit(kCGEventOtherMouseUp) | CGEventMaskBit(kCGEventOtherMouseUp) |
CGEventMaskBit(kCGEventOtherMouseDragged) | CGEventMaskBit(kCGEventOtherMouseDragged) |
CGEventMaskBit(kCGEventMouseMoved) | CGEventMaskBit(kCGEventMouseMoved) |
CGEventMaskBit(kCGEventScrollWheel) | CGEventMaskBit(kCGEventScrollWheel) |
// NOTE This event is undocumented and used // NOTE This event is undocumented and used
// for caps-lock release and multi-media keys. // for caps-lock release and multi-media keys.
CGEventMaskBit(NX_SYSDEFINED); CGEventMaskBit(NX_SYSDEFINED);
#endif #endif
// Create the event tap. // Create the event tap.
hook->port = CGEventTapCreate( hook->port = CGEventTapCreate(
kCGSessionEventTap, // kCGHIDEventTap kCGSessionEventTap, // kCGHIDEventTap
kCGHeadInsertEventTap, // kCGTailAppendEventTap kCGHeadInsertEventTap, // kCGTailAppendEventTap
kCGEventTapOptionDefault, // kCGEventTapOptionListenOnly See Bug #22 kCGEventTapOptionDefault, // kCGEventTapOptionListenOnly See Bug #22
event_mask, event_mask,
hook_event_proc, hook_event_proc,
NULL); NULL);
if (hook->port != NULL) { if (hook->port != NULL) {
logger(LOG_LEVEL_DEBUG, "%s [%u]: CGEventTapCreate Successful.\n", logger(LOG_LEVEL_DEBUG, "%s [%u]: CGEventTapCreate Successful.\n",
__FUNCTION__, __LINE__);
// Create the runloop event source from the event tap.
hook->source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, hook->port, 0);
if (hook->source != NULL) {
logger(LOG_LEVEL_DEBUG, "%s [%u]: CFMachPortCreateRunLoopSource successful.\n",
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
event_loop = CFRunLoopGetCurrent(); // Create the runloop event source from the event tap.
if (event_loop != NULL) { hook->source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, hook->port, 0);
logger(LOG_LEVEL_DEBUG, "%s [%u]: CFRunLoopGetCurrent successful.\n", if (hook->source != NULL) {
logger(LOG_LEVEL_DEBUG, "%s [%u]: CFMachPortCreateRunLoopSource successful.\n",
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
// Create run loop observers. event_loop = CFRunLoopGetCurrent();
hook->observer = CFRunLoopObserverCreate( if (event_loop != NULL) {
kCFAllocatorDefault, logger(LOG_LEVEL_DEBUG, "%s [%u]: CFRunLoopGetCurrent successful.\n",
kCFRunLoopEntry | kCFRunLoopExit, //kCFRunLoopAllActivities,
true,
0,
hook_status_proc,
NULL);
if (hook->observer != NULL) {
logger(LOG_LEVEL_DEBUG, "%s [%u]: CFRunLoopObserverCreate successful.\n",
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
tis_message = (TISMessage *) calloc(1, sizeof(TISMessage)); // Create run loop observers.
if (tis_message != NULL) { hook->observer = CFRunLoopObserverCreate(
if (! CFEqual(event_loop, CFRunLoopGetMain())) { kCFAllocatorDefault,
#ifdef USE_WEAK_IMPORT kCFRunLoopEntry | kCFRunLoopExit, //kCFRunLoopAllActivities,
if (dispatch_sync_f == NULL || dispatch_get_main_queue == NULL) { true,
#else 0,
*(void **) (&dispatch_sync_f_f) = dlsym(RTLD_DEFAULT, "dispatch_sync_f"); hook_status_proc,
const char *dlError = dlerror(); NULL);
if (dlError != NULL) {
logger(LOG_LEVEL_DEBUG, "%s [%u]: %s.\n",
__FUNCTION__, __LINE__, dlError);
}
*(void **) (&dispatch_get_main_queue_f) = dlsym(RTLD_DEFAULT, "dispatch_get_main_queue"); if (hook->observer != NULL) {
dlError = dlerror(); logger(LOG_LEVEL_DEBUG, "%s [%u]: CFRunLoopObserverCreate successful.\n",
if (dlError != NULL) { __FUNCTION__, __LINE__);
logger(LOG_LEVEL_DEBUG, "%s [%u]: %s.\n",
__FUNCTION__, __LINE__, dlError);
}
if (dispatch_sync_f_f == NULL || dispatch_get_main_queue_f == NULL) { tis_message = (TISMessage *) calloc(1, sizeof(TISMessage));
#endif if (tis_message != NULL) {
logger(LOG_LEVEL_DEBUG, "%s [%u]: Failed to locate dispatch_sync_f() or dispatch_get_main_queue()!\n", if (! CFEqual(event_loop, CFRunLoopGetMain())) {
__FUNCTION__, __LINE__); #ifdef USE_WEAK_IMPORT
if (dispatch_sync_f == NULL || dispatch_get_main_queue == NULL) {
#if ! defined(USE_CARBON_LEGACY) && defined(USE_COREFOUNDATION) #else
logger(LOG_LEVEL_DEBUG, "%s [%u]: Falling back to runloop signaling.\n", *(void **) (&dispatch_sync_f_f) = dlsym(RTLD_DEFAULT, "dispatch_sync_f");
__FUNCTION__, __LINE__); const char *dlError = dlerror();
if (dlError != NULL) {
int runloop_status = start_message_port_runloop(); logger(LOG_LEVEL_DEBUG, "%s [%u]: %s.\n",
if (runloop_status != IOHOOK_SUCCESS) { __FUNCTION__, __LINE__, dlError);
return runloop_status;
} }
*(void **) (&dispatch_get_main_queue_f) = dlsym(RTLD_DEFAULT, "dispatch_get_main_queue");
dlError = dlerror();
if (dlError != NULL) {
logger(LOG_LEVEL_DEBUG, "%s [%u]: %s.\n",
__FUNCTION__, __LINE__, dlError);
}
if (dispatch_sync_f_f == NULL || dispatch_get_main_queue_f == NULL) {
#endif #endif
logger(LOG_LEVEL_DEBUG, "%s [%u]: Failed to locate dispatch_sync_f() or dispatch_get_main_queue()!\n",
__FUNCTION__, __LINE__);
#if ! defined(USE_CARBON_LEGACY) && defined(USE_COREFOUNDATION)
logger(LOG_LEVEL_DEBUG, "%s [%u]: Falling back to runloop signaling.\n",
__FUNCTION__, __LINE__);
int runloop_status = start_message_port_runloop();
if (runloop_status != IOHOOK_SUCCESS) {
return runloop_status;
}
#endif
}
} }
}
// Add the event source and observer to the runloop mode. // Add the event source and observer to the runloop mode.
CFRunLoopAddSource(event_loop, hook->source, kCFRunLoopDefaultMode); CFRunLoopAddSource(event_loop, hook->source, kCFRunLoopDefaultMode);
CFRunLoopAddObserver(event_loop, hook->observer, kCFRunLoopDefaultMode); CFRunLoopAddObserver(event_loop, hook->observer, kCFRunLoopDefaultMode);
#ifdef USE_OBJC #ifdef USE_OBJC
// Create a garbage collector to handle Cocoa events correctly. // Create a garbage collector to handle Cocoa events correctly.
Class NSAutoreleasePool_class = (Class) objc_getClass("NSAutoreleasePool"); Class NSAutoreleasePool_class = (Class) objc_getClass("NSAutoreleasePool");
id pool = class_createInstance(NSAutoreleasePool_class, 0); id pool = class_createInstance(NSAutoreleasePool_class, 0);
auto_release_pool = objc_msgSend(pool, sel_registerName("init")); auto_release_pool = objc_msgSend(pool, sel_registerName("init"));
#endif
// Start the hook thread runloop.
CFRunLoopRun();
#ifdef USE_OBJC
//objc_msgSend(auto_release_pool, sel_registerName("drain"));
objc_msgSend(auto_release_pool, sel_registerName("release"));
#endif
// Lock back up until we are done processing the exit.
if (CFRunLoopContainsObserver(event_loop, hook->observer, kCFRunLoopDefaultMode)) {
CFRunLoopRemoveObserver(event_loop, hook->observer, kCFRunLoopDefaultMode);
}
if (CFRunLoopContainsSource(event_loop, hook->source, kCFRunLoopDefaultMode)) {
CFRunLoopRemoveSource(event_loop, hook->source, kCFRunLoopDefaultMode);
}
#if ! defined(USE_CARBON_LEGACY) && defined(USE_COREFOUNDATION)
if (! CFEqual(event_loop, CFRunLoopGetMain())) {
#ifdef USE_WEAK_IMPORT
if (dispatch_sync_f == NULL || dispatch_get_main_queue == NULL) {
#else
if (dispatch_sync_f_f == NULL || dispatch_get_main_queue_f == NULL) {
#endif #endif
stop_message_port_runloop();
}
}
#endif
// Free the TIS Message. // Start the hook thread runloop.
free(tis_message); CFRunLoopRun();
#ifdef USE_OBJC
//objc_msgSend(auto_release_pool, sel_registerName("drain"));
objc_msgSend(auto_release_pool, sel_registerName("release"));
#endif
// Lock back up until we are done processing the exit.
if (CFRunLoopContainsObserver(event_loop, hook->observer, kCFRunLoopDefaultMode)) {
CFRunLoopRemoveObserver(event_loop, hook->observer, kCFRunLoopDefaultMode);
}
if (CFRunLoopContainsSource(event_loop, hook->source, kCFRunLoopDefaultMode)) {
CFRunLoopRemoveSource(event_loop, hook->source, kCFRunLoopDefaultMode);
}
#if ! defined(USE_CARBON_LEGACY) && defined(USE_COREFOUNDATION)
if (! CFEqual(event_loop, CFRunLoopGetMain())) {
#ifdef USE_WEAK_IMPORT
if (dispatch_sync_f == NULL || dispatch_get_main_queue == NULL) {
#else
if (dispatch_sync_f_f == NULL || dispatch_get_main_queue_f == NULL) {
#endif
stop_message_port_runloop();
}
}
#endif
// Free the TIS Message.
free(tis_message);
}
else {
logger(LOG_LEVEL_ERROR, "%s [%u]: Failed to allocate memory for TIS message structure!\n",
__FUNCTION__, __LINE__);
// Set the exit status.
status = IOHOOK_ERROR_OUT_OF_MEMORY;
}
// Invalidate and free hook observer.
CFRunLoopObserverInvalidate(hook->observer);
CFRelease(hook->observer);
} }
else { else {
logger(LOG_LEVEL_ERROR, "%s [%u]: Failed to allocate memory for TIS message structure!\n", // 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__); __FUNCTION__, __LINE__);
// Set the exit status. // Set the exit status.
status = IOHOOK_ERROR_OUT_OF_MEMORY; status = IOHOOK_ERROR_CREATE_OBSERVER;
} }
// Invalidate and free hook observer.
CFRunLoopObserverInvalidate(hook->observer);
CFRelease(hook->observer);
} }
else { else {
// We cant do a whole lot of anything if we cant logger(LOG_LEVEL_ERROR, "%s [%u]: CFRunLoopGetCurrent failure!\n",
// create run loop observer.
logger(LOG_LEVEL_ERROR, "%s [%u]: CFRunLoopObserverCreate failure!\n",
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
// Set the exit status. // Set the exit status.
status = IOHOOK_ERROR_CREATE_OBSERVER; status = IOHOOK_ERROR_GET_RUNLOOP;
} }
// Clean up the event source.
CFRelease(hook->source);
} }
else { else {
logger(LOG_LEVEL_ERROR, "%s [%u]: CFRunLoopGetCurrent failure!\n", logger(LOG_LEVEL_ERROR, "%s [%u]: CFMachPortCreateRunLoopSource failure!\n",
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
// Set the exit status. // Set the exit status.
status = IOHOOK_ERROR_GET_RUNLOOP; status = IOHOOK_ERROR_CREATE_RUN_LOOP_SOURCE;
} }
// Clean up the event source. // Stop the CFMachPort from receiving any more messages.
CFRelease(hook->source); CFMachPortInvalidate(hook->port);
CFRelease(hook->port);
} }
else { else {
logger(LOG_LEVEL_ERROR, "%s [%u]: CFMachPortCreateRunLoopSource failure!\n", logger(LOG_LEVEL_ERROR, "%s [%u]: Failed to create event port!\n",
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
// Set the exit status. // Set the exit status.
status = IOHOOK_ERROR_CREATE_RUN_LOOP_SOURCE; status = IOHOOK_ERROR_CREATE_EVENT_PORT;
} }
// Stop the CFMachPort from receiving any more messages. // Free the hook structure.
CFMachPortInvalidate(hook->port); free(hook);
CFRelease(hook->port);
} }
else { else {
logger(LOG_LEVEL_ERROR, "%s [%u]: Failed to create event port!\n", status = IOHOOK_ERROR_OUT_OF_MEMORY;
__FUNCTION__, __LINE__);
// Set the exit status.
status = IOHOOK_ERROR_CREATE_EVENT_PORT;
} }
} while (restart_tap);
} else {
logger(LOG_LEVEL_ERROR, "%s [%u]: Accessibility API is disabled!\n",
__FUNCTION__, __LINE__);
// Free the hook structure. // Set the exit status.
free(hook); status = IOHOOK_ERROR_AXAPI_DISABLED;
} }
else {
status = IOHOOK_ERROR_OUT_OF_MEMORY;
}
}
else {
logger(LOG_LEVEL_ERROR, "%s [%u]: Accessibility API is disabled!\n",
__FUNCTION__, __LINE__);
// Set the exit status.
status = IOHOOK_ERROR_AXAPI_DISABLED;
}
} while (restart_tap);
logger(LOG_LEVEL_DEBUG, "%s [%u]: Something, something, something, complete.\n", logger(LOG_LEVEL_DEBUG, "%s [%u]: Something, something, something, complete.\n",
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);