mirror of
https://github.com/robotn/gohook.git
synced 2024-11-23 20:56:52 +08:00
optimize darwin check accessibility not loop
This commit is contained in:
parent
9fa8b6c408
commit
3f023c292f
@ -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__);
|
||||||
|
Loading…
Reference in New Issue
Block a user