Boolean AXEnabled(void) { if (AXAPIEnabled() != 0) { return TRUE; } else { return FALSE; } }
COSXScreen::COSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCursor) : CPlatformScreen(events), m_events(events), MouseButtonEventMap(NumButtonIDs), m_isPrimary(isPrimary), m_isOnScreen(m_isPrimary), m_cursorPosValid(false), m_cursorHidden(false), m_dragNumButtonsDown(0), m_dragTimer(NULL), m_keyState(NULL), m_sequenceNumber(0), m_screensaver(NULL), m_screensaverNotify(false), m_ownClipboard(false), m_clipboardTimer(NULL), m_hiddenWindow(NULL), m_userInputWindow(NULL), m_switchEventHandlerRef(0), m_pmMutex(new CMutex), m_pmWatchThread(NULL), m_pmThreadReady(new CCondVar<bool>(m_pmMutex, false)), m_activeModifierHotKey(0), m_activeModifierHotKeyMask(0), m_lastSingleClick(0), m_lastDoubleClick(0), m_lastSingleClickXCursor(0), m_lastSingleClickYCursor(0), m_autoShowHideCursor(autoShowHideCursor), m_eventTapRLSR(nullptr), m_eventTapPort(nullptr), m_pmRootPort(0) { try { m_displayID = CGMainDisplayID(); updateScreenShape(m_displayID, 0); m_screensaver = new COSXScreenSaver(m_events, getEventTarget()); m_keyState = new COSXKeyState(m_events); // TODO: http://stackoverflow.com/questions/2950124/enable-access-for-assistive-device-programmatically if (m_isPrimary && !AXAPIEnabled()) throw XArch("system setting not enabled: \"Enable access for assistive devices\""); // install display manager notification handler #if defined(MAC_OS_X_VERSION_10_5) CGDisplayRegisterReconfigurationCallback(displayReconfigurationCallback, this); #else m_displayManagerNotificationUPP = NewDMExtendedNotificationUPP(displayManagerCallback); OSStatus err = GetCurrentProcess(&m_PSN); err = DMRegisterExtendedNotifyProc(m_displayManagerNotificationUPP, this, 0, &m_PSN); #endif // install fast user switching event handler EventTypeSpec switchEventTypes[2]; switchEventTypes[0].eventClass = kEventClassSystem; switchEventTypes[0].eventKind = kEventSystemUserSessionDeactivated; switchEventTypes[1].eventClass = kEventClassSystem; switchEventTypes[1].eventKind = kEventSystemUserSessionActivated; EventHandlerUPP switchEventHandler = NewEventHandlerUPP(userSwitchCallback); InstallApplicationEventHandler(switchEventHandler, 2, switchEventTypes, this, &m_switchEventHandlerRef); DisposeEventHandlerUPP(switchEventHandler); constructMouseButtonEventMap(); // watch for requests to sleep m_events->adoptHandler(m_events->forCOSXScreen().confirmSleep(), getEventTarget(), new TMethodEventJob<COSXScreen>(this, &COSXScreen::handleConfirmSleep)); // create thread for monitoring system power state. *m_pmThreadReady = false; LOG((CLOG_DEBUG "starting watchSystemPowerThread")); m_pmWatchThread = new CThread(new TMethodJob<COSXScreen> (this, &COSXScreen::watchSystemPowerThread)); } catch (...) { m_events->removeHandler(m_events->forCOSXScreen().confirmSleep(), getEventTarget()); if (m_switchEventHandlerRef != 0) { RemoveEventHandler(m_switchEventHandlerRef); } #if defined(MAC_OS_X_VERSION_10_5) CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this); #else if (m_displayManagerNotificationUPP != NULL) { DMRemoveExtendedNotifyProc(m_displayManagerNotificationUPP, NULL, &m_PSN, 0); } if (m_hiddenWindow) { ReleaseWindow(m_hiddenWindow); m_hiddenWindow = NULL; } if (m_userInputWindow) { ReleaseWindow(m_userInputWindow); m_userInputWindow = NULL; } #endif delete m_keyState; delete m_screensaver; throw; } // install event handlers m_events->adoptHandler(CEvent::kSystem, m_events->getSystemTarget(), new TMethodEventJob<COSXScreen>(this, &COSXScreen::handleSystemEvent)); // install the platform event queue m_events->adoptBuffer(new COSXEventQueueBuffer(m_events)); }
COSXScreen::COSXScreen(bool isPrimary) : m_isPrimary(isPrimary), m_isOnScreen(m_isPrimary), m_cursorPosValid(false), m_cursorHidden(false), m_dragNumButtonsDown(0), m_dragTimer(NULL), m_keyState(NULL), m_sequenceNumber(0), m_screensaver(NULL), m_screensaverNotify(false), m_ownClipboard(false), m_clipboardTimer(NULL), m_hiddenWindow(NULL), m_userInputWindow(NULL), m_switchEventHandlerRef(0), m_pmMutex(new CMutex), m_pmWatchThread(NULL), m_pmThreadReady(new CCondVar<bool>(m_pmMutex, false)), m_activeModifierHotKey(0), m_activeModifierHotKeyMask(0) { try { m_displayID = CGMainDisplayID(); updateScreenShape(m_displayID, 0); m_screensaver = new COSXScreenSaver(getEventTarget()); m_keyState = new COSXKeyState(); if (m_isPrimary) { if (!AXAPIEnabled()) { LOG((CLOG_ERR "Synergy server requires accessibility API enabled. Please check the option for \"Enable access for assistive devices\" in the Universal Access System Preferences panel. Unintentional key-replication will occur until this is fixed.")); } } // install display manager notification handler #if defined(MAC_OS_X_VERSION_10_5) CGDisplayRegisterReconfigurationCallback(displayReconfigurationCallback, this); #else m_displayManagerNotificationUPP = NewDMExtendedNotificationUPP(displayManagerCallback); OSStatus err = GetCurrentProcess(&m_PSN); err = DMRegisterExtendedNotifyProc(m_displayManagerNotificationUPP, this, 0, &m_PSN); #endif // install fast user switching event handler EventTypeSpec switchEventTypes[2]; switchEventTypes[0].eventClass = kEventClassSystem; switchEventTypes[0].eventKind = kEventSystemUserSessionDeactivated; switchEventTypes[1].eventClass = kEventClassSystem; switchEventTypes[1].eventKind = kEventSystemUserSessionActivated; EventHandlerUPP switchEventHandler = NewEventHandlerUPP(userSwitchCallback); InstallApplicationEventHandler(switchEventHandler, 2, switchEventTypes, this, &m_switchEventHandlerRef); DisposeEventHandlerUPP(switchEventHandler); // watch for requests to sleep EVENTQUEUE->adoptHandler(COSXScreen::getConfirmSleepEvent(), getEventTarget(), new TMethodEventJob<COSXScreen>(this, &COSXScreen::handleConfirmSleep)); // create thread for monitoring system power state. LOG((CLOG_DEBUG "starting watchSystemPowerThread")); m_pmWatchThread = new CThread(new TMethodJob<COSXScreen> (this, &COSXScreen::watchSystemPowerThread)); } catch (...) { EVENTQUEUE->removeHandler(COSXScreen::getConfirmSleepEvent(), getEventTarget()); if (m_switchEventHandlerRef != 0) { RemoveEventHandler(m_switchEventHandlerRef); } #if defined(MAC_OS_X_VERSION_10_5) CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this); #else if (m_displayManagerNotificationUPP != NULL) { DMRemoveExtendedNotifyProc(m_displayManagerNotificationUPP, NULL, &m_PSN, 0); } if (m_hiddenWindow) { ReleaseWindow(m_hiddenWindow); m_hiddenWindow = NULL; } if (m_userInputWindow) { ReleaseWindow(m_userInputWindow); m_userInputWindow = NULL; } #endif delete m_keyState; delete m_screensaver; throw; } // install event handlers EVENTQUEUE->adoptHandler(CEvent::kSystem, IEventQueue::getSystemTarget(), new TMethodEventJob<COSXScreen>(this, &COSXScreen::handleSystemEvent)); // install the platform event queue EVENTQUEUE->adoptBuffer(new COSXEventQueueBuffer); }
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); }
static bool amIAuthorized () { if (AXAPIEnabled() != 0) { return true; } if (AXIsProcessTrusted() != 0) { return true; } return false; }
static bool hasAccessibilityAPIAuthorization () { if (AXAPIEnabled() != 0) { return true; } if (AXIsProcessTrusted() != 0) { return true; } return false; }