diff options
Diffstat (limited to 'src/lib/platform/OSXScreen.mm')
| -rw-r--r-- | src/lib/platform/OSXScreen.mm | 218 |
1 files changed, 106 insertions, 112 deletions
diff --git a/src/lib/platform/OSXScreen.mm b/src/lib/platform/OSXScreen.mm index 2b4594f..d41e321 100644 --- a/src/lib/platform/OSXScreen.mm +++ b/src/lib/platform/OSXScreen.mm @@ -2,11 +2,11 @@ * barrier -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman - * + * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE that should have accompanied this file. - * + * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -38,7 +38,6 @@ #include "base/Log.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" -#include "base/TMethodJob.h" #include <math.h> #include <mach-o/dyld.h> @@ -110,10 +109,10 @@ OSXScreen::OSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCurso updateScreenShape(m_displayID, 0); m_screensaver = new OSXScreenSaver(m_events, getEventTarget()); m_keyState = new OSXKeyState(m_events); - + // only needed when running as a server. if (m_isPrimary) { - + #if defined(MAC_OS_X_VERSION_10_9) // we can't pass options to show the dialog, this must be done by the gui. if (!AXIsProcessTrusted()) { @@ -126,7 +125,7 @@ OSXScreen::OSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCurso } #endif } - + // install display manager notification handler CGDisplayRegisterReconfigurationCallback(displayReconfigurationCallback, this); @@ -157,8 +156,7 @@ OSXScreen::OSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCurso m_carbonLoopReady = new CondVar<bool>(m_carbonLoopMutex, false); #endif LOG((CLOG_DEBUG "starting watchSystemPowerThread")); - m_pmWatchThread = new Thread(new TMethodJob<OSXScreen> - (this, &OSXScreen::watchSystemPowerThread)); + m_pmWatchThread = new Thread([this](){ watchSystemPowerThread(); }); } catch (...) { m_events->removeHandler(m_events->forOSXScreen().confirmSleep(), @@ -166,7 +164,7 @@ OSXScreen::OSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCurso if (m_switchEventHandlerRef != 0) { RemoveEventHandler(m_switchEventHandlerRef); } - + CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this); delete m_keyState; @@ -217,7 +215,7 @@ OSXScreen::~OSXScreen() delete m_keyState; delete m_screensaver; - + #if defined(MAC_OS_X_VERSION_10_7) delete m_carbonLoopMutex; delete m_carbonLoopReady; @@ -273,7 +271,7 @@ OSXScreen::warpCursor(SInt32 x, SInt32 y) pos.x = x; pos.y = y; CGWarpMouseCursorPosition(pos); - + // save new cursor position m_xCursor = x; m_yCursor = y; @@ -325,7 +323,7 @@ OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask) LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); return 0; } - + // choose hotkey id UInt32 id; if (!m_oldHotKeyIDs.empty()) { @@ -351,7 +349,7 @@ OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask) } else { EventHotKeyID hkid = { 'SNRG', (UInt32)id }; - OSStatus status = RegisterEventHotKey(macKey, macMask, hkid, + OSStatus status = RegisterEventHotKey(macKey, macMask, hkid, GetApplicationEventTarget(), 0, &ref); okay = (status == noErr); @@ -366,7 +364,7 @@ OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask) } m_hotKeys.insert(std::make_pair(id, HotKeyItem(ref, macKey, macMask))); - + LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", barrier::KeyMap::formatKey(key, mask).c_str(), key, mask, id)); return id; } @@ -468,7 +466,7 @@ OSXScreen::postMouseEvent(CGPoint& pos) const } } } - + CGEventType type = kCGEventMouseMoved; SInt8 button = m_buttonState.getFirstButtonDown(); @@ -478,10 +476,10 @@ OSXScreen::postMouseEvent(CGPoint& pos) const } CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, static_cast<CGMouseButton>(button)); - + // Dragging events also need the click state CGEventSetIntegerValueField(event, kCGMouseEventClickState, m_clickState); - + // Fix for sticky keys CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags(); CGEventSetFlags(event, modifiers); @@ -503,7 +501,7 @@ OSXScreen::postMouseEvent(CGPoint& pos) const CGEventSetDoubleValueField(event, kCGMouseEventDeltaY, deltaFY); CGEventPost(kCGHIDEventTap, event); - + CFRelease(event); } @@ -515,7 +513,7 @@ OSXScreen::fakeMouseButton(ButtonID id, bool press) if (index >= NumButtonIDs) { return; } - + CGPoint pos; if (!m_cursorPosValid) { SInt32 x, y; @@ -533,79 +531,77 @@ OSXScreen::fakeMouseButton(ButtonID id, bool press) // since we don't have double click distance in NX APIs // we define our own defaults. const double maxDiff = sqrt(2) + 0.0001; - + double clickTime = [NSEvent doubleClickInterval]; - + // As long as the click is within the time window and distance window // increase clickState (double click, triple click, etc) - // This will allow for higher than triple click but the quartz documenation + // This will allow for higher than triple click but the quartz documentation // does not specify that this should be limited to triple click if (press) { - if ((ARCH->time() - m_lastClickTime) <= clickTime && diff <= maxDiff){ + if ((ARCH->time() - m_lastClickTime) <= clickTime && diff <= maxDiff) { m_clickState++; } else { m_clickState = 1; } - + m_lastClickTime = ARCH->time(); } - - if (m_clickState == 1){ + + if (m_clickState == 1) { m_lastSingleClickXCursor = m_xCursor; m_lastSingleClickYCursor = m_yCursor; } - + EMouseButtonState state = press ? kMouseButtonDown : kMouseButtonUp; - + LOG((CLOG_DEBUG1 "faking mouse button id: %d press: %s", index, press ? "pressed" : "released")); - + MouseButtonEventMapType thisButtonMap = MouseButtonEventMap[index]; CGEventType type = thisButtonMap[state]; CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, static_cast<CGMouseButton>(index)); - + CGEventSetIntegerValueField(event, kCGMouseEventClickState, m_clickState); - + // Fix for sticky keys CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags(); CGEventSetFlags(event, modifiers); - + m_buttonState.set(index, state); CGEventPost(kCGHIDEventTap, event); - + CFRelease(event); - + if (!press && (id == kButtonLeft)) { if (m_fakeDraggingStarted) { - m_getDropTargetThread = new Thread(new TMethodJob<OSXScreen>( - this, &OSXScreen::getDropTargetThread)); + m_getDropTargetThread = new Thread([this](){ get_drop_target_thread(); }); } - + m_draggingStarted = false; } } -void -OSXScreen::getDropTargetThread(void*) +void OSXScreen::get_drop_target_thread() { #if defined(MAC_OS_X_VERSION_10_7) char* cstr = NULL; - + // wait for 5 secs for the drop destinaiton string to be filled. UInt32 timeout = ARCH->time() + 5; - + while (ARCH->time() < timeout) { CFStringRef cfstr = getCocoaDropTarget(); cstr = CFStringRefToUTF8String(cfstr); CFRelease(cfstr); - + if (cstr != NULL) { break; } ARCH->sleep(.1f); } - + if (cstr != NULL) { LOG((CLOG_DEBUG "drop target: %s", cstr)); m_dropTarget = cstr; @@ -626,12 +622,12 @@ OSXScreen::fakeMouseMove(SInt32 x, SInt32 y) if (m_fakeDraggingStarted) { m_buttonState.set(0, kMouseButtonDown); } - + // index 0 means left mouse button if (m_buttonState.test(0)) { m_draggingStarted = true; } - + // synthesize event CGPoint pos; pos.x = x; @@ -679,11 +675,11 @@ OSXScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const NULL, kCGScrollEventUnitLine, 2, mapScrollWheelFromBarrier(yDelta), -mapScrollWheelFromBarrier(xDelta)); - + // Fix for sticky keys CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags(); CGEventSetFlags(scrollEvent, modifiers); - + CGEventPost(kCGHIDEventTap, scrollEvent); CFRelease(scrollEvent); } @@ -754,11 +750,11 @@ OSXScreen::enable() if (m_isPrimary) { // FIXME -- start watching jump zones - + // kCGEventTapOptionDefault = 0x00000000 (Missing in 10.4, so specified literally) m_eventTapPort = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, - kCGEventMaskForAllEvents, - handleCGInputEvent, + kCGEventMaskForAllEvents, + handleCGInputEvent, this); } else { @@ -773,10 +769,10 @@ OSXScreen::enable() // there may be a better way to do this, but we register an event handler even if we're // not on the primary display (acting as a client). This way, if a local event comes in - // (either keyboard or mouse), we can make sure to show the cursor if we've hidden it. + // (either keyboard or mouse), we can make sure to show the cursor if we've hidden it. m_eventTapPort = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, - kCGEventMaskForAllEvents, - handleCGInputEventSecondary, + kCGEventMaskForAllEvents, + handleCGInputEventSecondary, this); } @@ -798,9 +794,9 @@ OSXScreen::disable() if (m_autoShowHideCursor) { showCursor(); } - + // FIXME -- stop watching jump zones, stop capturing input - + if (m_eventTapRLSR) { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_eventTapRLSR, kCFRunLoopDefaultMode); CFRelease(m_eventTapRLSR); @@ -846,7 +842,7 @@ OSXScreen::enter() io_registry_entry_t entry = IORegistryEntryFromPath( kIOMasterPortDefault, "IOService:/IOResources/IODisplayWrangler"); - + if (entry != MACH_PORT_NULL) { IORegistryEntrySetCFProperty(entry, CFSTR("IORequestIdle"), kCFBooleanFalse); IOObjectRelease(entry); @@ -863,15 +859,15 @@ bool OSXScreen::leave() { hideCursor(); - + if (isDraggingStarted()) { String& fileList = getDraggingFilename(); - + if (!m_isPrimary) { if (fileList.empty() == false) { ClientApp& app = ClientApp::instance(); Client* client = app.getClientPtr(); - + DragInformation di; di.setFilename(fileList); DragFileList dragFileList; @@ -881,7 +877,7 @@ OSXScreen::leave() dragFileList, info); client->sendDragInfo(fileCount, info, info.size()); LOG((CLOG_DEBUG "send dragging file to server")); - + // TODO: what to do with multiple file or even // a folder client->sendFileToServer(fileList.c_str()); @@ -889,7 +885,7 @@ OSXScreen::leave() } m_draggingStarted = false; } - + if (m_isPrimary) { avoidHesitatingCursor(); @@ -906,8 +902,8 @@ OSXScreen::setClipboard(ClipboardID, const IClipboard* src) { if (src != NULL) { LOG((CLOG_DEBUG "setting clipboard")); - Clipboard::copy(&m_pasteboard, src); - } + Clipboard::copy(&m_pasteboard, src); + } return true; } @@ -1036,16 +1032,16 @@ OSXScreen::handleSystemEvent(const Event& event, void*) } break; - case kEventClassKeyboard: + case kEventClassKeyboard: switch (GetEventKind(*carbonEvent)) { case kEventHotKeyPressed: case kEventHotKeyReleased: onHotKey(*carbonEvent); break; } - + break; - + case kEventClassWindow: // 2nd param was formerly GetWindowEventTarget(m_userInputWindow) which is 32-bit only, // however as m_userInputWindow is never initialized to anything we can take advantage of @@ -1076,7 +1072,7 @@ OSXScreen::handleSystemEvent(const Event& event, void*) } } -bool +bool OSXScreen::onMouseMove(CGFloat mx, CGFloat my) { LOG((CLOG_DEBUG2 "mouse move %+f,%+f", mx, my)); @@ -1140,7 +1136,7 @@ OSXScreen::onMouseMove(CGFloat mx, CGFloat my) return true; } -bool +bool OSXScreen::onMouseButton(bool pressed, UInt16 macButton) { // Buttons 2 and 3 are inverted on the mac @@ -1176,7 +1172,7 @@ OSXScreen::onMouseButton(bool pressed, UInt16 macButton) } } } - + if (macButton == kButtonLeft) { EMouseButtonState state = pressed ? kMouseButtonDown : kMouseButtonUp; m_buttonState.set(kButtonLeft - 1, state); @@ -1186,10 +1182,9 @@ OSXScreen::onMouseButton(bool pressed, UInt16 macButton) } else { if (m_fakeDraggingStarted) { - m_getDropTargetThread = new Thread(new TMethodJob<OSXScreen>( - this, &OSXScreen::getDropTargetThread)); + m_getDropTargetThread = new Thread([this](){ get_drop_target_thread(); }); } - + m_draggingStarted = false; } } @@ -1218,16 +1213,16 @@ OSXScreen::displayReconfigurationCallback(CGDirectDisplayID displayID, CGDisplay // Closing or opening the lid when an external monitor is // connected causes an kCGDisplayBeginConfigurationFlag event - CGDisplayChangeSummaryFlags mask = kCGDisplayBeginConfigurationFlag | kCGDisplayMovedFlag | - kCGDisplaySetModeFlag | kCGDisplayAddFlag | kCGDisplayRemoveFlag | - kCGDisplayEnabledFlag | kCGDisplayDisabledFlag | - kCGDisplayMirrorFlag | kCGDisplayUnMirrorFlag | + CGDisplayChangeSummaryFlags mask = kCGDisplayBeginConfigurationFlag | kCGDisplayMovedFlag | + kCGDisplaySetModeFlag | kCGDisplayAddFlag | kCGDisplayRemoveFlag | + kCGDisplayEnabledFlag | kCGDisplayDisabledFlag | + kCGDisplayMirrorFlag | kCGDisplayUnMirrorFlag | kCGDisplayDesktopShapeChangedFlag; - + LOG((CLOG_DEBUG1 "event: display was reconfigured: %x %x %x", flags, mask, flags & mask)); if (flags & mask) { /* Something actually did change */ - + LOG((CLOG_DEBUG1 "event: screen changed shape; refreshing dimensions")); screen->updateScreenShape(displayID, flags); } @@ -1274,7 +1269,7 @@ OSXScreen::onKey(CGEventRef event) m_activeModifierHotKeyMask = 0; } } - + return true; } @@ -1342,7 +1337,7 @@ OSXScreen::onKey(CGEventRef event) } void -OSXScreen::onMediaKey(CGEventRef event) +OSXScreen::onMediaKey(CGEventRef event) { KeyID keyID; bool down; @@ -1405,7 +1400,7 @@ OSXScreen::mapBarrierButtonToMac(UInt16 button) const return static_cast<ButtonID>(button); } -ButtonID +ButtonID OSXScreen::mapMacButtonToBarrier(UInt16 macButton) const { switch (macButton) { @@ -1418,7 +1413,7 @@ OSXScreen::mapMacButtonToBarrier(UInt16 macButton) const case 3: return kButtonMiddle; } - + return static_cast<ButtonID>(macButton); } @@ -1445,8 +1440,8 @@ OSXScreen::getScrollSpeed() const double scaling = 0.0; CFPropertyListRef pref = ::CFPreferencesCopyValue( - CFSTR("com.apple.scrollwheel.scaling") , - kCFPreferencesAnyApplication, + CFSTR("com.apple.scrollwheel.scaling") , + kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); if (pref != NULL) { @@ -1535,7 +1530,7 @@ OSXScreen::updateScreenShape() if (CGGetActiveDisplayList(0, NULL, &displayCount) != CGDisplayNoErr) { return; } - + if (displayCount == 0) { return; } @@ -1579,13 +1574,13 @@ OSXScreen::updateScreenShape() (displayCount == 1) ? "display" : "displays")); } -#pragma mark - +#pragma mark - // // FAST USER SWITCH NOTIFICATION SUPPORT // // OSXScreen::userSwitchCallback(void*) -// +// // gets called if a fast user switch occurs // @@ -1611,18 +1606,17 @@ OSXScreen::userSwitchCallback(EventHandlerCallRef nextHandler, return (CallNextEventHandler(nextHandler, theEvent)); } -#pragma mark - +#pragma mark - // // SLEEP/WAKEUP NOTIFICATION SUPPORT // // OSXScreen::watchSystemPowerThread(void*) -// -// main of thread monitoring system power (sleep/wakup) using a CFRunLoop +// +// main of thread monitoring system power (sleep/wakeup) using a CFRunLoop // -void -OSXScreen::watchSystemPowerThread(void*) +void OSXScreen::watchSystemPowerThread() { io_object_t notifier; IONotificationPortRef notificationPortRef; @@ -1641,7 +1635,7 @@ OSXScreen::watchSystemPowerThread(void*) CFRunLoopAddSource(m_pmRunloop, runloopSourceRef, kCFRunLoopCommonModes); } - + // thread is ready { Lock lock(m_pmMutex); @@ -1658,15 +1652,15 @@ OSXScreen::watchSystemPowerThread(void*) } LOG((CLOG_DEBUG "started watchSystemPowerThread")); - + LOG((CLOG_DEBUG "waiting for event loop")); m_events->waitForReady(); - + #if defined(MAC_OS_X_VERSION_10_7) { Lock lockCarbon(m_carbonLoopMutex); if (*m_carbonLoopReady == false) { - + // we signalling carbon loop ready before starting // unless we know how to do it within the loop LOG((CLOG_DEBUG "signalling carbon loop ready")); @@ -1676,12 +1670,12 @@ OSXScreen::watchSystemPowerThread(void*) } } #endif - + // start the run loop LOG((CLOG_DEBUG "starting carbon loop")); CFRunLoopRun(); LOG((CLOG_DEBUG "carbon loop has stopped")); - + // cleanup if (notificationPortRef) { CFRunLoopRemoveSource(m_pmRunloop, @@ -1716,7 +1710,7 @@ OSXScreen::handlePowerChangeRequest(natural_t messageType, void* messageArg) getEventTarget(), messageArg, Event::kDontFreeData)); return; - + case kIOMessageSystemHasPoweredOn: LOG((CLOG_DEBUG "system wakeup")); m_events->addEvent(Event(m_events->forIScreen().resume(), @@ -1742,16 +1736,16 @@ OSXScreen::handleConfirmSleep(const Event& event, void*) if (m_pmRootPort != 0) { // deliver suspend event immediately. m_events->addEvent(Event(m_events->forIScreen().suspend(), - getEventTarget(), NULL, + getEventTarget(), NULL, Event::kDeliverImmediately)); - + LOG((CLOG_DEBUG "system will sleep")); IOAllowPowerChange(m_pmRootPort, messageArg); } } } -#pragma mark - +#pragma mark - // // GLOBAL HOTKEY OPERATING MODE SUPPORT (10.3) @@ -1941,7 +1935,7 @@ OSXScreen::handleCGInputEvent(CGEventTapProxy proxy, case kCGEventMouseMoved: pos = CGEventGetLocation(event); screen->onMouseMove(pos.x, pos.y); - + // The system ignores our cursor-centering calls if // we don't return the event. This should be harmless, // but might register as slight movement to other apps @@ -1980,10 +1974,10 @@ OSXScreen::handleCGInputEvent(CGEventTapProxy proxy, } break; } - + LOG((CLOG_DEBUG3 "unknown quartz event type: 0x%02x", type)); } - + if (screen->m_isOnScreen) { return event; } else { @@ -1992,38 +1986,38 @@ OSXScreen::handleCGInputEvent(CGEventTapProxy proxy, } void -OSXScreen::MouseButtonState::set(UInt32 button, EMouseButtonState state) +OSXScreen::MouseButtonState::set(UInt32 button, EMouseButtonState state) { bool newState = (state == kMouseButtonDown); m_buttons.set(button, newState); } bool -OSXScreen::MouseButtonState::any() +OSXScreen::MouseButtonState::any() { return m_buttons.any(); } void -OSXScreen::MouseButtonState::reset() +OSXScreen::MouseButtonState::reset() { m_buttons.reset(); } void -OSXScreen::MouseButtonState::overwrite(UInt32 buttons) +OSXScreen::MouseButtonState::overwrite(UInt32 buttons) { m_buttons = std::bitset<NumButtonIDs>(buttons); } bool -OSXScreen::MouseButtonState::test(UInt32 button) const +OSXScreen::MouseButtonState::test(UInt32 button) const { return m_buttons.test(button); } SInt8 -OSXScreen::MouseButtonState::getFirstButtonDown() const +OSXScreen::MouseButtonState::getFirstButtonDown() const { if (m_buttons.any()) { for (unsigned short button = 0; button < m_buttons.size(); button++) { @@ -2041,7 +2035,7 @@ OSXScreen::CFStringRefToUTF8String(CFStringRef aString) if (aString == NULL) { return NULL; } - + CFIndex length = CFStringGetLength(aString); CFIndex maxSize = CFStringGetMaximumSizeForEncoding( length, |
