00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "COSXScreen.h"
00016 #include "COSXClipboard.h"
00017 #include "COSXEventQueueBuffer.h"
00018 #include "COSXKeyState.h"
00019 #include "COSXScreenSaver.h"
00020 #include "CClipboard.h"
00021 #include "CKeyMap.h"
00022 #include "CCondVar.h"
00023 #include "CLock.h"
00024 #include "CMutex.h"
00025 #include "CThread.h"
00026 #include "CLog.h"
00027 #include "IEventQueue.h"
00028 #include "TMethodEventJob.h"
00029 #include "TMethodJob.h"
00030 #include "XArch.h"
00031
00032 #include <mach-o/dyld.h>
00033 #include <AvailabilityMacros.h>
00034
00035
00036
00037 #if !defined(MAC_OS_X_VERSION_10_3) || \
00038 (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_3)
00039 enum {
00040 kEventClassSystem = 'macs',
00041 kEventSystemUserSessionActivated = 10,
00042 kEventSystemUserSessionDeactivated = 11
00043 };
00044 #endif
00045
00046
00047 enum {
00048 kSynergyEventMouseScroll = 11,
00049 kSynergyMouseScrollAxisX = 'saxx',
00050 kSynergyMouseScrollAxisY = 'saxy'
00051 };
00052
00053
00054
00055
00056
00057 bool COSXScreen::s_testedForGHOM = false;
00058 bool COSXScreen::s_hasGHOM = false;
00059 CEvent::Type COSXScreen::s_confirmSleepEvent = CEvent::kUnknown;
00060
00061 COSXScreen::COSXScreen(bool isPrimary) :
00062 m_isPrimary(isPrimary),
00063 m_isOnScreen(m_isPrimary),
00064 m_cursorPosValid(false),
00065 m_cursorHidden(false),
00066 m_dragNumButtonsDown(0),
00067 m_dragTimer(NULL),
00068 m_keyState(NULL),
00069 m_sequenceNumber(0),
00070 m_screensaver(NULL),
00071 m_screensaverNotify(false),
00072 m_clipboardTimer(NULL),
00073 m_hiddenWindow(NULL),
00074 m_userInputWindow(NULL),
00075 m_switchEventHandlerRef(0),
00076 m_pmMutex(new CMutex),
00077 m_pmWatchThread(NULL),
00078 m_pmThreadReady(new CCondVar<bool>(m_pmMutex, false)),
00079 m_activeModifierHotKey(0),
00080 m_activeModifierHotKeyMask(0)
00081 {
00082 try {
00083 m_displayID = CGMainDisplayID();
00084 updateScreenShape(m_displayID, 0);
00085 m_screensaver = new COSXScreenSaver(getEventTarget());
00086 m_keyState = new COSXKeyState();
00087
00088 if (m_isPrimary) {
00089
00090
00091 Rect bounds = { 100, 100, 101, 101 };
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101 CreateNewWindow(kUtilityWindowClass,
00102 kWindowNoShadowAttribute |
00103 kWindowIgnoreClicksAttribute |
00104 kWindowNoActivatesAttribute,
00105 &bounds, &m_hiddenWindow);
00106
00107
00108 SetWindowAlpha(m_hiddenWindow, 0);
00109 ShowWindow(m_hiddenWindow);
00110
00111
00112
00113 Rect inputBounds = { 100, 100, 200, 200 };
00114 CreateNewWindow(kUtilityWindowClass,
00115 kWindowNoShadowAttribute |
00116 kWindowOpaqueForEventsAttribute |
00117 kWindowStandardHandlerAttribute,
00118 &inputBounds, &m_userInputWindow);
00119
00120 SetWindowAlpha(m_userInputWindow, 0);
00121 }
00122
00123
00124 CGDisplayRegisterReconfigurationCallback(displayReconfigurationCallback, this);
00125
00126
00127 EventTypeSpec switchEventTypes[2];
00128 switchEventTypes[0].eventClass = kEventClassSystem;
00129 switchEventTypes[0].eventKind = kEventSystemUserSessionDeactivated;
00130 switchEventTypes[1].eventClass = kEventClassSystem;
00131 switchEventTypes[1].eventKind = kEventSystemUserSessionActivated;
00132 EventHandlerUPP switchEventHandler =
00133 NewEventHandlerUPP(userSwitchCallback);
00134 InstallApplicationEventHandler(switchEventHandler, 2, switchEventTypes,
00135 this, &m_switchEventHandlerRef);
00136 DisposeEventHandlerUPP(switchEventHandler);
00137
00138
00139 EVENTQUEUE->adoptHandler(COSXScreen::getConfirmSleepEvent(),
00140 getEventTarget(),
00141 new TMethodEventJob<COSXScreen>(this,
00142 &COSXScreen::handleConfirmSleep));
00143
00144
00145 LOG((CLOG_DEBUG "starting watchSystemPowerThread"));
00146 m_pmWatchThread = new CThread(new TMethodJob<COSXScreen>
00147 (this, &COSXScreen::watchSystemPowerThread));
00148 }
00149 catch (...) {
00150 EVENTQUEUE->removeHandler(COSXScreen::getConfirmSleepEvent(),
00151 getEventTarget());
00152 if (m_switchEventHandlerRef != 0) {
00153 RemoveEventHandler(m_switchEventHandlerRef);
00154 }
00155 CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this);
00156
00157 if (m_hiddenWindow) {
00158 CFRelease(m_hiddenWindow);
00159 m_hiddenWindow = NULL;
00160 }
00161
00162 if (m_userInputWindow) {
00163 CFRelease(m_userInputWindow);
00164 m_userInputWindow = NULL;
00165 }
00166 delete m_keyState;
00167 delete m_screensaver;
00168 throw;
00169 }
00170
00171
00172 EVENTQUEUE->adoptHandler(CEvent::kSystem, IEventQueue::getSystemTarget(),
00173 new TMethodEventJob<COSXScreen>(this,
00174 &COSXScreen::handleSystemEvent));
00175
00176
00177 EVENTQUEUE->adoptBuffer(new COSXEventQueueBuffer);
00178 }
00179
00180 COSXScreen::~COSXScreen()
00181 {
00182 disable();
00183 EVENTQUEUE->adoptBuffer(NULL);
00184 EVENTQUEUE->removeHandler(CEvent::kSystem, IEventQueue::getSystemTarget());
00185
00186 if (m_pmWatchThread) {
00187
00188 {
00189 CLock lock(m_pmMutex);
00190 while (!(bool)*m_pmThreadReady) {
00191 m_pmThreadReady->wait();
00192 }
00193 }
00194
00195
00196 LOG((CLOG_DEBUG "stopping watchSystemPowerThread"));
00197 CFRunLoopStop(m_pmRunloop);
00198 m_pmWatchThread->wait();
00199 delete m_pmWatchThread;
00200 m_pmWatchThread = NULL;
00201 }
00202 delete m_pmThreadReady;
00203 delete m_pmMutex;
00204
00205 EVENTQUEUE->removeHandler(COSXScreen::getConfirmSleepEvent(),
00206 getEventTarget());
00207
00208 RemoveEventHandler(m_switchEventHandlerRef);
00209
00210 CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this);
00211 if (m_hiddenWindow) {
00212 CFRelease(m_hiddenWindow);
00213 m_hiddenWindow = NULL;
00214 }
00215
00216 if (m_userInputWindow) {
00217 CFRelease(m_userInputWindow);
00218 m_userInputWindow = NULL;
00219 }
00220
00221 delete m_keyState;
00222 delete m_screensaver;
00223 }
00224
00225 void*
00226 COSXScreen::getEventTarget() const
00227 {
00228 return const_cast<COSXScreen*>(this);
00229 }
00230
00231 bool
00232 COSXScreen::getClipboard(ClipboardID, IClipboard* dst) const
00233 {
00234 CClipboard::copy(dst, &m_pasteboard);
00235 return true;
00236 }
00237
00238 void
00239 COSXScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
00240 {
00241 x = m_x;
00242 y = m_y;
00243 w = m_w;
00244 h = m_h;
00245 }
00246
00247 void
00248 COSXScreen::getCursorPos(SInt32& x, SInt32& y) const
00249 {
00250 Point mouse;
00251 GetGlobalMouse(&mouse);
00252 x = mouse.h;
00253 y = mouse.v;
00254 m_cursorPosValid = true;
00255 m_xCursor = x;
00256 m_yCursor = y;
00257 }
00258
00259 void
00260 COSXScreen::reconfigure(UInt32)
00261 {
00262
00263 }
00264
00265 void
00266 COSXScreen::warpCursor(SInt32 x, SInt32 y)
00267 {
00268
00269 CGPoint pos;
00270 pos.x = x;
00271 pos.y = y;
00272 CGWarpMouseCursorPosition(pos);
00273
00274
00275 m_xCursor = x;
00276 m_yCursor = y;
00277 m_cursorPosValid = true;
00278 }
00279
00280 void
00281 COSXScreen::fakeInputBegin()
00282 {
00283
00284 }
00285
00286 void
00287 COSXScreen::fakeInputEnd()
00288 {
00289
00290 }
00291
00292 SInt32
00293 COSXScreen::getJumpZoneSize() const
00294 {
00295 return 1;
00296 }
00297
00298 bool
00299 COSXScreen::isAnyMouseButtonDown() const
00300 {
00301 return (GetCurrentButtonState() != 0);
00302 }
00303
00304 void
00305 COSXScreen::getCursorCenter(SInt32& x, SInt32& y) const
00306 {
00307 x = m_xCenter;
00308 y = m_yCenter;
00309 }
00310
00311 UInt32
00312 COSXScreen::registerHotKey(KeyID key, KeyModifierMask mask)
00313 {
00314
00315 UInt32 macKey, macMask;
00316 if (!m_keyState->mapSynergyHotKeyToMac(key, mask, macKey, macMask)) {
00317 LOG((CLOG_WARN "could not map hotkey id=%04x mask=%04x", key, mask));
00318 return 0;
00319 }
00320
00321
00322 UInt32 id;
00323 if (!m_oldHotKeyIDs.empty()) {
00324 id = m_oldHotKeyIDs.back();
00325 m_oldHotKeyIDs.pop_back();
00326 }
00327 else {
00328 id = m_hotKeys.size() + 1;
00329 }
00330
00331
00332 EventHotKeyRef ref = NULL;
00333 bool okay;
00334 if (key == kKeyNone) {
00335 if (m_modifierHotKeys.count(mask) > 0) {
00336
00337 okay = false;
00338 }
00339 else {
00340 m_modifierHotKeys[mask] = id;
00341 okay = true;
00342 }
00343 }
00344 else {
00345 EventHotKeyID hkid = { 'SNRG', (UInt32)id };
00346 OSStatus status = RegisterEventHotKey(macKey, macMask, hkid,
00347 GetApplicationEventTarget(), 0,
00348 &ref);
00349 okay = (status == noErr);
00350 m_hotKeyToIDMap[CHotKeyItem(macKey, macMask)] = id;
00351 }
00352
00353 if (!okay) {
00354 m_oldHotKeyIDs.push_back(id);
00355 m_hotKeyToIDMap.erase(CHotKeyItem(macKey, macMask));
00356 LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", CKeyMap::formatKey(key, mask).c_str(), key, mask));
00357 return 0;
00358 }
00359
00360 m_hotKeys.insert(std::make_pair(id, CHotKeyItem(ref, macKey, macMask)));
00361
00362 LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", CKeyMap::formatKey(key, mask).c_str(), key, mask, id));
00363 return id;
00364 }
00365
00366 void
00367 COSXScreen::unregisterHotKey(UInt32 id)
00368 {
00369
00370 HotKeyMap::iterator i = m_hotKeys.find(id);
00371 if (i == m_hotKeys.end()) {
00372 return;
00373 }
00374
00375
00376 bool okay;
00377 if (i->second.getRef() != NULL) {
00378 okay = (UnregisterEventHotKey(i->second.getRef()) == noErr);
00379 }
00380 else {
00381 okay = false;
00382
00383 for (ModifierHotKeyMap::iterator j = m_modifierHotKeys.begin();
00384 j != m_modifierHotKeys.end(); ++j) {
00385 if (j->second == id) {
00386 m_modifierHotKeys.erase(j);
00387 okay = true;
00388 break;
00389 }
00390 }
00391 }
00392 if (!okay) {
00393 LOG((CLOG_WARN "failed to unregister hotkey id=%d", id));
00394 }
00395 else {
00396 LOG((CLOG_DEBUG "unregistered hotkey id=%d", id));
00397 }
00398
00399
00400 m_hotKeyToIDMap.erase(i->second);
00401 m_hotKeys.erase(i);
00402 m_oldHotKeyIDs.push_back(id);
00403 if (m_activeModifierHotKey == id) {
00404 m_activeModifierHotKey = 0;
00405 m_activeModifierHotKeyMask = 0;
00406 }
00407 }
00408
00409 void
00410 COSXScreen::postMouseEvent(CGPoint& pos) const
00411 {
00412
00413
00414 CGDisplayCount displayCount = 0;
00415 CGGetDisplaysWithPoint(pos, 0, NULL, &displayCount);
00416 if (displayCount == 0) {
00417
00418
00419 displayCount = 0;
00420 CGDirectDisplayID displayID;
00421 CGGetDisplaysWithPoint(CGPointMake(m_xCursor, m_yCursor), 1,
00422 &displayID, &displayCount);
00423 if (displayCount != 0) {
00424 CGRect displayRect = CGDisplayBounds(displayID);
00425 if (pos.x < displayRect.origin.x) {
00426 pos.x = displayRect.origin.x;
00427 }
00428 else if (pos.x > displayRect.origin.x +
00429 displayRect.size.width - 1) {
00430 pos.x = displayRect.origin.x + displayRect.size.width - 1;
00431 }
00432 if (pos.y < displayRect.origin.y) {
00433 pos.y = displayRect.origin.y;
00434 }
00435 else if (pos.y > displayRect.origin.y +
00436 displayRect.size.height - 1) {
00437 pos.y = displayRect.origin.y + displayRect.size.height - 1;
00438 }
00439 }
00440 }
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455 CGPostMouseEvent(pos, true, sizeof(m_buttons) / sizeof(m_buttons[0]),
00456 m_buttons[0],
00457 m_buttons[2],
00458 m_buttons[1],
00459 m_buttons[3],
00460 m_buttons[4]);
00461 }
00462
00463
00464 void
00465 COSXScreen::fakeMouseButton(ButtonID id, bool press) const
00466 {
00467
00468 UInt32 index = id - kButtonLeft;
00469 if (index >= sizeof(m_buttons) / sizeof(m_buttons[0])) {
00470 return;
00471 }
00472
00473
00474 m_buttons[index] = press;
00475
00476 CGPoint pos;
00477 if (!m_cursorPosValid) {
00478 SInt32 x, y;
00479 getCursorPos(x, y);
00480 }
00481 pos.x = m_xCursor;
00482 pos.y = m_yCursor;
00483 postMouseEvent(pos);
00484 }
00485
00486 void
00487 COSXScreen::fakeMouseMove(SInt32 x, SInt32 y) const
00488 {
00489
00490 CGPoint pos;
00491 pos.x = x;
00492 pos.y = y;
00493 postMouseEvent(pos);
00494
00495
00496 m_xCursor = static_cast<SInt32>(pos.x);
00497 m_yCursor = static_cast<SInt32>(pos.y);
00498 m_cursorPosValid = true;
00499 }
00500
00501 void
00502 COSXScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const
00503 {
00504
00505
00506
00507
00508
00509
00510 Point oldPos;
00511 GetGlobalMouse(&oldPos);
00512
00513
00514 CGPoint pos;
00515 m_xCursor = static_cast<SInt32>(oldPos.h);
00516 m_yCursor = static_cast<SInt32>(oldPos.v);
00517 pos.x = oldPos.h + dx;
00518 pos.y = oldPos.v + dy;
00519 postMouseEvent(pos);
00520
00521
00522 m_cursorPosValid = false;
00523 }
00524
00525 void
00526 COSXScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const
00527 {
00528 if (xDelta != 0 || yDelta != 0) {
00529 CGPostScrollWheelEvent(2, mapScrollWheelFromSynergy(yDelta),
00530 -mapScrollWheelFromSynergy(xDelta));
00531 }
00532 }
00533
00534 void
00535 COSXScreen::enable()
00536 {
00537
00538 m_clipboardTimer = EVENTQUEUE->newTimer(1.0, NULL);
00539 EVENTQUEUE->adoptHandler(CEvent::kTimer, m_clipboardTimer,
00540 new TMethodEventJob<COSXScreen>(this,
00541 &COSXScreen::handleClipboardCheck));
00542
00543 if (m_isPrimary) {
00544
00545 }
00546 else {
00547
00548
00549
00550 if (!m_cursorHidden) {
00551
00552 m_cursorHidden = true;
00553 }
00554
00555
00556 fakeMouseMove(m_xCenter, m_yCenter);
00557
00558
00559 }
00560 }
00561
00562 void
00563 COSXScreen::disable()
00564 {
00565 if (m_isPrimary) {
00566
00567 }
00568 else {
00569
00570 if (m_cursorHidden) {
00571
00572 m_cursorHidden = false;
00573 }
00574
00575
00576 }
00577
00578
00579 m_dragNumButtonsDown = 0;
00580 enableDragTimer(false);
00581
00582
00583 if (m_clipboardTimer != NULL) {
00584 EVENTQUEUE->removeHandler(CEvent::kTimer, m_clipboardTimer);
00585 EVENTQUEUE->deleteTimer(m_clipboardTimer);
00586 m_clipboardTimer = NULL;
00587 }
00588
00589 m_isOnScreen = m_isPrimary;
00590 }
00591
00592 void
00593 COSXScreen::enter()
00594 {
00595 if (m_isPrimary) {
00596
00597 HideWindow( m_userInputWindow );
00598 ShowWindow( m_hiddenWindow );
00599
00600 SetMouseCoalescingEnabled(true, NULL);
00601
00602 CGSetLocalEventsSuppressionInterval(0.0);
00603
00604
00605
00606 }
00607 else {
00608
00609 if (m_cursorHidden) {
00610
00611 m_cursorHidden = false;
00612 }
00613
00614
00615 for (UInt32 i = 0; i < sizeof(m_buttons) / sizeof(m_buttons[0]); ++i) {
00616 m_buttons[i] = false;
00617 }
00618
00619
00620
00621 CGSetLocalEventsFilterDuringSupressionState(
00622 kCGEventFilterMaskPermitAllEvents,
00623 kCGEventSupressionStateSupressionInterval);
00624 CGSetLocalEventsFilterDuringSupressionState(
00625 (kCGEventFilterMaskPermitLocalKeyboardEvents |
00626 kCGEventFilterMaskPermitSystemDefinedEvents),
00627 kCGEventSupressionStateRemoteMouseDrag);
00628 }
00629
00630
00631 m_isOnScreen = true;
00632 }
00633
00634 bool
00635 COSXScreen::leave()
00636 {
00637 if (m_isPrimary) {
00638
00639 warpCursor(m_xCenter, m_yCenter);
00640
00641
00642 HideWindow(m_hiddenWindow);
00643 ShowWindow(m_userInputWindow);
00644 RepositionWindow(m_userInputWindow,
00645 m_userInputWindow, kWindowCenterOnMainScreen);
00646 SetUserFocusWindow(m_userInputWindow);
00647
00648
00649
00650
00651 SetMouseCoalescingEnabled(false, NULL);
00652 CGSetLocalEventsSuppressionInterval(0.0001);
00653
00654
00655
00656 }
00657 else {
00658
00659 if (!m_cursorHidden) {
00660
00661 m_cursorHidden = true;
00662 }
00663
00664
00665 fakeMouseMove(m_xCenter, m_yCenter);
00666
00667
00668
00669
00670
00671 }
00672
00673
00674 m_isOnScreen = false;
00675
00676 return true;
00677 }
00678
00679
00680 bool
00681 COSXScreen::setClipboard(ClipboardID, const IClipboard* src)
00682 {
00683 if(src != NULL) {
00684 LOG((CLOG_DEBUG "setting clipboard"));
00685 CClipboard::copy(&m_pasteboard, src);
00686 }
00687 return true;
00688 }
00689
00690 void
00691 COSXScreen::checkClipboards()
00692 {
00693
00694 LOG((CLOG_DEBUG "checking clipboard"));
00695 if (m_pasteboard.synchronize()) {
00696 LOG((CLOG_DEBUG "clipboard changed"));
00697 sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardClipboard);
00698 sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardSelection);
00699 }
00700 }
00701
00702 void
00703 COSXScreen::openScreensaver(bool notify)
00704 {
00705 m_screensaverNotify = notify;
00706 if (!m_screensaverNotify) {
00707 m_screensaver->disable();
00708 }
00709 }
00710
00711 void
00712 COSXScreen::closeScreensaver()
00713 {
00714 if (!m_screensaverNotify) {
00715 m_screensaver->enable();
00716 }
00717 }
00718
00719 void
00720 COSXScreen::screensaver(bool activate)
00721 {
00722 if (activate) {
00723 m_screensaver->activate();
00724 }
00725 else {
00726 m_screensaver->deactivate();
00727 }
00728 }
00729
00730 void
00731 COSXScreen::resetOptions()
00732 {
00733
00734 }
00735
00736 void
00737 COSXScreen::setOptions(const COptionsList&)
00738 {
00739
00740 }
00741
00742 void
00743 COSXScreen::setSequenceNumber(UInt32 seqNum)
00744 {
00745 m_sequenceNumber = seqNum;
00746 }
00747
00748 bool
00749 COSXScreen::isPrimary() const
00750 {
00751 return m_isPrimary;
00752 }
00753
00754 void
00755 COSXScreen::sendEvent(CEvent::Type type, void* data) const
00756 {
00757 EVENTQUEUE->addEvent(CEvent(type, getEventTarget(), data));
00758 }
00759
00760 void
00761 COSXScreen::sendClipboardEvent(CEvent::Type type, ClipboardID id) const
00762 {
00763 CClipboardInfo* info = (CClipboardInfo*)malloc(sizeof(CClipboardInfo));
00764 info->m_id = id;
00765 info->m_sequenceNumber = m_sequenceNumber;
00766 sendEvent(type, info);
00767 }
00768
00769 void
00770 COSXScreen::handleSystemEvent(const CEvent& event, void*)
00771 {
00772 EventRef* carbonEvent = reinterpret_cast<EventRef*>(event.getData());
00773 assert(carbonEvent != NULL);
00774
00775 UInt32 eventClass = GetEventClass(*carbonEvent);
00776
00777 switch (eventClass) {
00778 case kEventClassMouse:
00779 switch (GetEventKind(*carbonEvent)) {
00780 case kEventMouseDown:
00781 {
00782 UInt16 myButton;
00783 GetEventParameter(*carbonEvent,
00784 kEventParamMouseButton,
00785 typeMouseButton,
00786 NULL,
00787 sizeof(myButton),
00788 NULL,
00789 &myButton);
00790 onMouseButton(true, myButton);
00791 break;
00792 }
00793
00794 case kEventMouseUp:
00795 {
00796 UInt16 myButton;
00797 GetEventParameter(*carbonEvent,
00798 kEventParamMouseButton,
00799 typeMouseButton,
00800 NULL,
00801 sizeof(myButton),
00802 NULL,
00803 &myButton);
00804 onMouseButton(false, myButton);
00805 break;
00806 }
00807
00808 case kEventMouseDragged:
00809 case kEventMouseMoved:
00810 {
00811 HIPoint point;
00812 GetEventParameter(*carbonEvent,
00813 kEventParamMouseLocation,
00814 typeHIPoint,
00815 NULL,
00816 sizeof(point),
00817 NULL,
00818 &point);
00819 onMouseMove((SInt32)point.x, (SInt32)point.y);
00820 break;
00821 }
00822
00823 case kEventMouseWheelMoved:
00824 {
00825 EventMouseWheelAxis axis;
00826 SInt32 delta;
00827 GetEventParameter(*carbonEvent,
00828 kEventParamMouseWheelAxis,
00829 typeMouseWheelAxis,
00830 NULL,
00831 sizeof(axis),
00832 NULL,
00833 &axis);
00834 if (axis == kEventMouseWheelAxisX ||
00835 axis == kEventMouseWheelAxisY) {
00836 GetEventParameter(*carbonEvent,
00837 kEventParamMouseWheelDelta,
00838 typeLongInteger,
00839 NULL,
00840 sizeof(delta),
00841 NULL,
00842 &delta);
00843 if (axis == kEventMouseWheelAxisX) {
00844 onMouseWheel(-mapScrollWheelToSynergy((SInt32)delta), 0);
00845 }
00846 else {
00847 onMouseWheel(0, mapScrollWheelToSynergy((SInt32)delta));
00848 }
00849 }
00850 break;
00851 }
00852
00853 case kSynergyEventMouseScroll:
00854 {
00855 OSStatus r;
00856 long xScroll;
00857 long yScroll;
00858
00859
00860 r = GetEventParameter(*carbonEvent,
00861 kSynergyMouseScrollAxisX,
00862 typeLongInteger,
00863 NULL,
00864 sizeof(xScroll),
00865 NULL,
00866 &xScroll);
00867 if (r != noErr) {
00868 xScroll = 0;
00869 }
00870 r = GetEventParameter(*carbonEvent,
00871 kSynergyMouseScrollAxisY,
00872 typeLongInteger,
00873 NULL,
00874 sizeof(yScroll),
00875 NULL,
00876 &yScroll);
00877 if (r != noErr) {
00878 yScroll = 0;
00879 }
00880
00881 if (xScroll != 0 || yScroll != 0) {
00882 onMouseWheel(-mapScrollWheelToSynergy(xScroll),
00883 mapScrollWheelToSynergy(yScroll));
00884 }
00885 }
00886 }
00887 break;
00888
00889 case kEventClassKeyboard:
00890 switch (GetEventKind(*carbonEvent)) {
00891 case kEventRawKeyUp:
00892 case kEventRawKeyDown:
00893 case kEventRawKeyRepeat:
00894 case kEventRawKeyModifiersChanged:
00895 onKey(*carbonEvent);
00896 break;
00897
00898 case kEventHotKeyPressed:
00899 case kEventHotKeyReleased:
00900 onHotKey(*carbonEvent);
00901 break;
00902 }
00903
00904 break;
00905
00906 case kEventClassWindow:
00907 SendEventToWindow(*carbonEvent, m_userInputWindow);
00908 switch (GetEventKind(*carbonEvent)) {
00909 case kEventWindowActivated:
00910 LOG((CLOG_DEBUG1 "window activated"));
00911 break;
00912
00913 case kEventWindowDeactivated:
00914 LOG((CLOG_DEBUG1 "window deactivated"));
00915 break;
00916
00917 case kEventWindowFocusAcquired:
00918 LOG((CLOG_DEBUG1 "focus acquired"));
00919 break;
00920
00921 case kEventWindowFocusRelinquish:
00922 LOG((CLOG_DEBUG1 "focus released"));
00923 break;
00924 }
00925 break;
00926
00927 default:
00928 SendEventToEventTarget(*carbonEvent, GetEventDispatcherTarget());
00929 break;
00930 }
00931 }
00932
00933 bool
00934 COSXScreen::onMouseMove(SInt32 mx, SInt32 my)
00935 {
00936 LOG((CLOG_DEBUG2 "mouse move %+d,%+d", mx, my));
00937
00938 SInt32 x = mx - m_xCursor;
00939 SInt32 y = my - m_yCursor;
00940
00941 if ((x == 0 && y == 0) || (mx == m_xCenter && mx == m_yCenter)) {
00942 return true;
00943 }
00944
00945
00946 m_xCursor = mx;
00947 m_yCursor = my;
00948
00949 if (m_isOnScreen) {
00950
00951 sendEvent(getMotionOnPrimaryEvent(),
00952 CMotionInfo::alloc(m_xCursor, m_yCursor));
00953 }
00954 else {
00955
00956
00957 warpCursor(m_xCenter, m_yCenter);
00958
00959
00960
00961
00962
00963
00964 static SInt32 bogusZoneSize = 10;
00965 if (-x + bogusZoneSize > m_xCenter - m_x ||
00966 x + bogusZoneSize > m_x + m_w - m_xCenter ||
00967 -y + bogusZoneSize > m_yCenter - m_y ||
00968 y + bogusZoneSize > m_y + m_h - m_yCenter) {
00969 LOG((CLOG_DEBUG "dropped bogus motion %+d,%+d", x, y));
00970 }
00971 else {
00972
00973 sendEvent(getMotionOnSecondaryEvent(), CMotionInfo::alloc(x, y));
00974 }
00975 }
00976
00977 return true;
00978 }
00979
00980 bool
00981 COSXScreen::onMouseButton(bool pressed, UInt16 macButton)
00982 {
00983
00984 ButtonID button = mapMacButtonToSynergy(macButton);
00985
00986 if (pressed) {
00987 LOG((CLOG_DEBUG1 "event: button press button=%d", button));
00988 if (button != kButtonNone) {
00989 KeyModifierMask mask = m_keyState->getActiveModifiers();
00990 sendEvent(getButtonDownEvent(), CButtonInfo::alloc(button, mask));
00991 }
00992 }
00993 else {
00994 LOG((CLOG_DEBUG1 "event: button release button=%d", button));
00995 if (button != kButtonNone) {
00996 KeyModifierMask mask = m_keyState->getActiveModifiers();
00997 sendEvent(getButtonUpEvent(), CButtonInfo::alloc(button, mask));
00998 }
00999 }
01000
01001
01002 if (macButton > 2) {
01003 if (pressed) {
01004
01005 if (m_dragNumButtonsDown++ == 0) {
01006 enableDragTimer(true);
01007 }
01008 }
01009 else {
01010
01011 if (--m_dragNumButtonsDown == 0) {
01012 enableDragTimer(false);
01013 }
01014 }
01015 }
01016
01017 return true;
01018 }
01019
01020 bool
01021 COSXScreen::onMouseWheel(SInt32 xDelta, SInt32 yDelta) const
01022 {
01023 LOG((CLOG_DEBUG1 "event: button wheel delta=%+d,%+d", xDelta, yDelta));
01024 sendEvent(getWheelEvent(), CWheelInfo::alloc(xDelta, yDelta));
01025 return true;
01026 }
01027
01028 void
01029 COSXScreen::handleClipboardCheck(const CEvent&, void*)
01030 {
01031 checkClipboards();
01032 }
01033
01034 void
01035 COSXScreen::displayReconfigurationCallback(CGDirectDisplayID displayID, CGDisplayChangeSummaryFlags flags, void* inUserData)
01036 {
01037 COSXScreen* screen = (COSXScreen*)inUserData;
01038
01039 CGDisplayChangeSummaryFlags mask = kCGDisplayMovedFlag |
01040 kCGDisplaySetModeFlag | kCGDisplayAddFlag | kCGDisplayRemoveFlag |
01041 kCGDisplayEnabledFlag | kCGDisplayDisabledFlag |
01042 kCGDisplayMirrorFlag | kCGDisplayUnMirrorFlag |
01043 kCGDisplayDesktopShapeChangedFlag;
01044
01045 LOG((CLOG_DEBUG1 "event: display was reconfigured: %x %x %x", flags, mask, flags & mask));
01046
01047 if (flags & mask) {
01048
01049 LOG((CLOG_DEBUG1 "event: screen changed shape; refreshing dimensions"));
01050 screen->updateScreenShape(displayID, flags);
01051 }
01052 }
01053
01054 bool
01055 COSXScreen::onKey(EventRef event)
01056 {
01057 UInt32 eventKind = GetEventKind(event);
01058
01059
01060 UInt32 virtualKey, macMask;
01061 GetEventParameter(event, kEventParamKeyCode, typeUInt32,
01062 NULL, sizeof(virtualKey), NULL, &virtualKey);
01063 GetEventParameter(event, kEventParamKeyModifiers, typeUInt32,
01064 NULL, sizeof(macMask), NULL, &macMask);
01065 LOG((CLOG_DEBUG1 "event: Key event kind: %d, keycode=%d", eventKind, virtualKey));
01066
01067
01068
01069
01070 if (virtualKey == 0 && eventKind == kEventRawKeyModifiersChanged) {
01071
01072 KeyModifierMask oldMask = getActiveModifiers();
01073 KeyModifierMask newMask = m_keyState->mapModifiersFromOSX(macMask);
01074 m_keyState->handleModifierKeys(getEventTarget(), oldMask, newMask);
01075
01076
01077
01078 if (m_activeModifierHotKey == 0) {
01079 if (m_modifierHotKeys.count(newMask) > 0) {
01080 m_activeModifierHotKey = m_modifierHotKeys[newMask];
01081 m_activeModifierHotKeyMask = newMask;
01082 EVENTQUEUE->addEvent(CEvent(getHotKeyDownEvent(),
01083 getEventTarget(),
01084 CHotKeyInfo::alloc(m_activeModifierHotKey)));
01085 }
01086 }
01087
01088
01089
01090 else if (m_activeModifierHotKey != 0) {
01091 KeyModifierMask mask = (newMask & m_activeModifierHotKeyMask);
01092 if (mask != m_activeModifierHotKeyMask) {
01093 EVENTQUEUE->addEvent(CEvent(getHotKeyUpEvent(),
01094 getEventTarget(),
01095 CHotKeyInfo::alloc(m_activeModifierHotKey)));
01096 m_activeModifierHotKey = 0;
01097 m_activeModifierHotKeyMask = 0;
01098 }
01099 }
01100
01101 return true;
01102 }
01103
01104
01105
01106
01107
01108 if (!m_isOnScreen) {
01109 HotKeyToIDMap::const_iterator i =
01110 m_hotKeyToIDMap.find(CHotKeyItem(virtualKey, macMask & 0xff00u));
01111 if (i != m_hotKeyToIDMap.end()) {
01112 UInt32 id = i->second;
01113
01114
01115 CEvent::Type type;
01116 UInt32 eventKind = GetEventKind(event);
01117 if (eventKind == kEventRawKeyDown) {
01118 type = getHotKeyDownEvent();
01119 }
01120 else if (eventKind == kEventRawKeyUp) {
01121 type = getHotKeyUpEvent();
01122 }
01123 else {
01124 return false;
01125 }
01126
01127 EVENTQUEUE->addEvent(CEvent(type, getEventTarget(),
01128 CHotKeyInfo::alloc(id)));
01129
01130 return true;
01131 }
01132 }
01133
01134
01135 bool down = (eventKind == kEventRawKeyDown);
01136 bool up = (eventKind == kEventRawKeyUp);
01137 bool isRepeat = (eventKind == kEventRawKeyRepeat);
01138
01139
01140 KeyModifierMask mask;
01141 COSXKeyState::CKeyIDs keys;
01142 KeyButton button = m_keyState->mapKeyFromEvent(keys, &mask, event);
01143 if (button == 0) {
01144 return false;
01145 }
01146
01147
01148
01149
01150 KeyModifierMask sendMask = (mask & ~KeyModifierAltGr);
01151 if ((mask & KeyModifierAltGr) != 0) {
01152 sendMask &= ~KeyModifierSuper;
01153 }
01154 mask &= ~KeyModifierAltGr;
01155
01156
01157 if (down) {
01158 m_keyState->onKey(button, true, mask);
01159 }
01160 else if (up) {
01161 if (!m_keyState->isKeyDown(button)) {
01162
01163 return false;
01164 }
01165 m_keyState->onKey(button, false, mask);
01166 }
01167
01168
01169 for (COSXKeyState::CKeyIDs::const_iterator i = keys.begin();
01170 i != keys.end(); ++i) {
01171 m_keyState->sendKeyEvent(getEventTarget(), down, isRepeat,
01172 *i, sendMask, 1, button);
01173 }
01174
01175 return true;
01176 }
01177
01178 bool
01179 COSXScreen::onHotKey(EventRef event) const
01180 {
01181
01182 EventHotKeyID hkid;
01183 GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID,
01184 NULL, sizeof(EventHotKeyID), NULL, &hkid);
01185 UInt32 id = hkid.id;
01186
01187
01188 CEvent::Type type;
01189 UInt32 eventKind = GetEventKind(event);
01190 if (eventKind == kEventHotKeyPressed) {
01191 type = getHotKeyDownEvent();
01192 }
01193 else if (eventKind == kEventHotKeyReleased) {
01194 type = getHotKeyUpEvent();
01195 }
01196 else {
01197 return false;
01198 }
01199
01200 EVENTQUEUE->addEvent(CEvent(type, getEventTarget(),
01201 CHotKeyInfo::alloc(id)));
01202
01203 return true;
01204 }
01205
01206 ButtonID
01207 COSXScreen::mapMacButtonToSynergy(UInt16 macButton) const
01208 {
01209 switch (macButton) {
01210 case 1:
01211 return kButtonLeft;
01212
01213 case 2:
01214 return kButtonRight;
01215
01216 case 3:
01217 return kButtonMiddle;
01218 }
01219
01220 return static_cast<ButtonID>(macButton);
01221 }
01222
01223 SInt32
01224 COSXScreen::mapScrollWheelToSynergy(SInt32 x) const
01225 {
01226
01227
01228 double d = (1.0 + getScrollSpeed()) * x / getScrollSpeedFactor();
01229 return static_cast<SInt32>(120.0 * d);
01230 }
01231
01232 SInt32
01233 COSXScreen::mapScrollWheelFromSynergy(SInt32 x) const
01234 {
01235
01236
01237 return static_cast<SInt32>(3.0 * x / 120.0);
01238 }
01239
01240 double
01241 COSXScreen::getScrollSpeed() const
01242 {
01243 double scaling = 0.0;
01244
01245 CFPropertyListRef pref = ::CFPreferencesCopyValue(
01246 CFSTR("com.apple.scrollwheel.scaling") ,
01247 kCFPreferencesAnyApplication,
01248 kCFPreferencesCurrentUser,
01249 kCFPreferencesAnyHost);
01250 if (pref != NULL) {
01251 CFTypeID id = CFGetTypeID(pref);
01252 if (id == CFNumberGetTypeID()) {
01253 CFNumberRef value = static_cast<CFNumberRef>(pref);
01254 if (CFNumberGetValue(value, kCFNumberDoubleType, &scaling)) {
01255 if (scaling < 0.0) {
01256 scaling = 0.0;
01257 }
01258 }
01259 }
01260 CFRelease(pref);
01261 }
01262
01263 return scaling;
01264 }
01265
01266 double
01267 COSXScreen::getScrollSpeedFactor() const
01268 {
01269 return pow(10.0, getScrollSpeed());
01270 }
01271
01272 void
01273 COSXScreen::enableDragTimer(bool enable)
01274 {
01275 UInt32 modifiers;
01276 MouseTrackingResult res;
01277
01278 if (enable && m_dragTimer == NULL) {
01279 m_dragTimer = EVENTQUEUE->newTimer(0.01, NULL);
01280 EVENTQUEUE->adoptHandler(CEvent::kTimer, m_dragTimer,
01281 new TMethodEventJob<COSXScreen>(this,
01282 &COSXScreen::handleDrag));
01283 TrackMouseLocationWithOptions(NULL, 0, 0, &m_dragLastPoint, &modifiers, &res);
01284 }
01285 else if (!enable && m_dragTimer != NULL) {
01286 EVENTQUEUE->removeHandler(CEvent::kTimer, m_dragTimer);
01287 EVENTQUEUE->deleteTimer(m_dragTimer);
01288 m_dragTimer = NULL;
01289 }
01290 }
01291
01292 void
01293 COSXScreen::handleDrag(const CEvent&, void*)
01294 {
01295 Point p;
01296 UInt32 modifiers;
01297 MouseTrackingResult res;
01298
01299 TrackMouseLocationWithOptions(NULL, 0, 0, &p, &modifiers, &res);
01300
01301 if (res != kMouseTrackingTimedOut && (p.h != m_dragLastPoint.h || p.v != m_dragLastPoint.v)) {
01302 m_dragLastPoint = p;
01303 onMouseMove((SInt32)p.h, (SInt32)p.v);
01304 }
01305 }
01306
01307 void
01308 COSXScreen::updateButtons()
01309 {
01310 UInt32 buttons = GetCurrentButtonState();
01311 for (size_t i = 0; i < sizeof(m_buttons) / sizeof(m_buttons[0]); ++i) {
01312 m_buttons[i] = ((buttons & (1u << i)) != 0);
01313 }
01314 }
01315
01316 IKeyState*
01317 COSXScreen::getKeyState() const
01318 {
01319 return m_keyState;
01320 }
01321
01322 void
01323 COSXScreen::updateScreenShape(const CGDirectDisplayID, const CGDisplayChangeSummaryFlags flags)
01324 {
01325
01326
01327 CGDisplayCount displayCount = 0;
01328
01329 if (CGGetActiveDisplayList(0, NULL, &displayCount) != CGDisplayNoErr) {
01330 return;
01331 }
01332
01333 if (displayCount == 0) {
01334 return;
01335 }
01336
01337 CGDirectDisplayID* displays = new CGDirectDisplayID[displayCount];
01338 if (displays == NULL) {
01339 return;
01340 }
01341
01342 if (CGGetActiveDisplayList(displayCount,
01343 displays, &displayCount) != CGDisplayNoErr) {
01344 delete[] displays;
01345 return;
01346 }
01347
01348
01349 CGRect totalBounds = CGRectZero;
01350 for (CGDisplayCount i = 0; i < displayCount; ++i) {
01351 CGRect bounds = CGDisplayBounds(displays[i]);
01352 totalBounds = CGRectUnion(totalBounds, bounds);
01353 }
01354
01355
01356 m_x = (SInt32)totalBounds.origin.x;
01357 m_y = (SInt32)totalBounds.origin.y;
01358 m_w = (SInt32)totalBounds.size.width;
01359 m_h = (SInt32)totalBounds.size.height;
01360
01361
01362 CGDirectDisplayID main = CGMainDisplayID();
01363 const CGRect rect = CGDisplayBounds(main);
01364 m_xCenter = (rect.origin.x + rect.size.width) / 2;
01365 m_yCenter = (rect.origin.y + rect.size.height) / 2;
01366
01367 delete[] displays;
01368 if (m_isPrimary && !m_isOnScreen) {
01369 sendEvent(getShapeChangedEvent());
01370 }
01371
01372 LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d on %u %s", m_x, m_y, m_w, m_h, displayCount, (displayCount == 1) ? "display" : "displays"));
01373 }
01374
01375 #pragma mark -
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385 pascal OSStatus
01386 COSXScreen::userSwitchCallback(EventHandlerCallRef nextHandler,
01387 EventRef theEvent,
01388 void* inUserData)
01389 {
01390 COSXScreen* screen = (COSXScreen*)inUserData;
01391 UInt32 kind = GetEventKind(theEvent);
01392
01393 if (kind == kEventSystemUserSessionDeactivated) {
01394 LOG((CLOG_DEBUG "user session deactivated"));
01395 EVENTQUEUE->addEvent(CEvent(IScreen::getSuspendEvent(),
01396 screen->getEventTarget()));
01397 }
01398 else if (kind == kEventSystemUserSessionActivated) {
01399 LOG((CLOG_DEBUG "user session activated"));
01400 EVENTQUEUE->addEvent(CEvent(IScreen::getResumeEvent(),
01401 screen->getEventTarget()));
01402 }
01403 return (CallNextEventHandler(nextHandler, theEvent));
01404 }
01405
01406 #pragma mark -
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416 void
01417 COSXScreen::watchSystemPowerThread(void*)
01418 {
01419 io_object_t notifier;
01420 IONotificationPortRef notificationPortRef;
01421 CFRunLoopSourceRef runloopSourceRef = 0;
01422
01423 m_pmRunloop = CFRunLoopGetCurrent();
01424
01425 m_pmRootPort = IORegisterForSystemPower(this, ¬ificationPortRef,
01426 powerChangeCallback, ¬ifier);
01427 if (m_pmRootPort == 0) {
01428 LOG((CLOG_WARN "IORegisterForSystemPower failed"));
01429 }
01430 else {
01431 runloopSourceRef =
01432 IONotificationPortGetRunLoopSource(notificationPortRef);
01433 CFRunLoopAddSource(m_pmRunloop, runloopSourceRef,
01434 kCFRunLoopCommonModes);
01435 }
01436
01437
01438 {
01439 CLock lock(m_pmMutex);
01440 *m_pmThreadReady = true;
01441 m_pmThreadReady->signal();
01442 }
01443
01444
01445
01446
01447 if (m_pmRootPort == 0) {
01448 return;
01449 }
01450
01451
01452 LOG((CLOG_DEBUG "started watchSystemPowerThread"));
01453 CFRunLoopRun();
01454
01455
01456 if (notificationPortRef) {
01457 CFRunLoopRemoveSource(m_pmRunloop,
01458 runloopSourceRef, kCFRunLoopDefaultMode);
01459 CFRunLoopSourceInvalidate(runloopSourceRef);
01460 CFRelease(runloopSourceRef);
01461 }
01462
01463 CLock lock(m_pmMutex);
01464 IODeregisterForSystemPower(¬ifier);
01465 m_pmRootPort = 0;
01466 LOG((CLOG_DEBUG "stopped watchSystemPowerThread"));
01467 }
01468
01469 void
01470 COSXScreen::powerChangeCallback(void* refcon, io_service_t service,
01471 natural_t messageType, void* messageArg)
01472 {
01473 ((COSXScreen*)refcon)->handlePowerChangeRequest(messageType, messageArg);
01474 }
01475
01476 void
01477 COSXScreen::handlePowerChangeRequest(natural_t messageType, void* messageArg)
01478 {
01479
01480 switch (messageType) {
01481 case kIOMessageSystemWillSleep:
01482
01483
01484
01485 EVENTQUEUE->addEvent(CEvent(COSXScreen::getConfirmSleepEvent(),
01486 getEventTarget(), messageArg,
01487 CEvent::kDontFreeData));
01488 return;
01489
01490 case kIOMessageSystemHasPoweredOn:
01491 LOG((CLOG_DEBUG "system wakeup"));
01492 EVENTQUEUE->addEvent(CEvent(IScreen::getResumeEvent(),
01493 getEventTarget()));
01494 break;
01495
01496 default:
01497 break;
01498 }
01499
01500 CLock lock(m_pmMutex);
01501 if (m_pmRootPort != 0) {
01502 IOAllowPowerChange(m_pmRootPort, (long)messageArg);
01503 }
01504 }
01505
01506 CEvent::Type
01507 COSXScreen::getConfirmSleepEvent()
01508 {
01509 return CEvent::registerTypeOnce(s_confirmSleepEvent,
01510 "COSXScreen::confirmSleep");
01511 }
01512
01513 void
01514 COSXScreen::handleConfirmSleep(const CEvent& event, void*)
01515 {
01516 long messageArg = (long)event.getData();
01517 if (messageArg != 0) {
01518 CLock lock(m_pmMutex);
01519 if (m_pmRootPort != 0) {
01520
01521 EVENTQUEUE->addEvent(CEvent(IScreen::getSuspendEvent(),
01522 getEventTarget(), NULL,
01523 CEvent::kDeliverImmediately));
01524
01525 LOG((CLOG_DEBUG "system will sleep"));
01526 IOAllowPowerChange(m_pmRootPort, messageArg);
01527 }
01528 }
01529 }
01530
01531 #pragma mark -
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547 #if 0
01548
01549 #ifdef __cplusplus
01550 extern "C" {
01551 #endif
01552
01553 typedef int CGSConnection;
01554 typedef enum {
01555 CGSGlobalHotKeyEnable = 0,
01556 CGSGlobalHotKeyDisable = 1,
01557 } CGSGlobalHotKeyOperatingMode;
01558
01559 extern CGSConnection _CGSDefaultConnection(void) WEAK_IMPORT_ATTRIBUTE;
01560 extern CGError CGSGetGlobalHotKeyOperatingMode(CGSConnection connection, CGSGlobalHotKeyOperatingMode *mode) WEAK_IMPORT_ATTRIBUTE;
01561 extern CGError CGSSetGlobalHotKeyOperatingMode(CGSConnection connection, CGSGlobalHotKeyOperatingMode mode) WEAK_IMPORT_ATTRIBUTE;
01562
01563 typedef CGSConnection (*_CGSDefaultConnection_t)(void);
01564 typedef CGError (*CGSGetGlobalHotKeyOperatingMode_t)(CGSConnection connection, CGSGlobalHotKeyOperatingMode *mode);
01565 typedef CGError (*CGSSetGlobalHotKeyOperatingMode_t)(CGSConnection connection, CGSGlobalHotKeyOperatingMode mode);
01566
01567 static _CGSDefaultConnection_t s__CGSDefaultConnection;
01568 static CGSGetGlobalHotKeyOperatingMode_t s_CGSGetGlobalHotKeyOperatingMode;
01569 static CGSSetGlobalHotKeyOperatingMode_t s_CGSSetGlobalHotKeyOperatingMode;
01570
01571 #ifdef __cplusplus
01572 }
01573 #endif
01574
01575 #define LOOKUP(name_) \
01576 s_ ## name_ = NULL; \
01577 if (NSIsSymbolNameDefinedWithHint("_" #name_, "CoreGraphics")) { \
01578 s_ ## name_ = (name_ ## _t)NSAddressOfSymbol( \
01579 NSLookupAndBindSymbolWithHint( \
01580 "_" #name_, "CoreGraphics")); \
01581 }
01582
01583 bool
01584 COSXScreen::isGlobalHotKeyOperatingModeAvailable()
01585 {
01586 if (!s_testedForGHOM) {
01587 s_testedForGHOM = true;
01588 LOOKUP(_CGSDefaultConnection);
01589 LOOKUP(CGSGetGlobalHotKeyOperatingMode);
01590 LOOKUP(CGSSetGlobalHotKeyOperatingMode);
01591 s_hasGHOM = (s__CGSDefaultConnection != NULL &&
01592 s_CGSGetGlobalHotKeyOperatingMode != NULL &&
01593 s_CGSSetGlobalHotKeyOperatingMode != NULL);
01594 }
01595 return s_hasGHOM;
01596 }
01597
01598 void
01599 COSXScreen::setGlobalHotKeysEnabled(bool enabled)
01600 {
01601 if (isGlobalHotKeyOperatingModeAvailable()) {
01602 CGSConnection conn = s__CGSDefaultConnection();
01603
01604 CGSGlobalHotKeyOperatingMode mode;
01605 s_CGSGetGlobalHotKeyOperatingMode(conn, &mode);
01606
01607 if (enabled && mode == CGSGlobalHotKeyDisable) {
01608 s_CGSSetGlobalHotKeyOperatingMode(conn, CGSGlobalHotKeyEnable);
01609 }
01610 else if (!enabled && mode == CGSGlobalHotKeyEnable) {
01611 s_CGSSetGlobalHotKeyOperatingMode(conn, CGSGlobalHotKeyDisable);
01612 }
01613 }
01614 }
01615
01616 bool
01617 COSXScreen::getGlobalHotKeysEnabled()
01618 {
01619 CGSGlobalHotKeyOperatingMode mode;
01620 if (isGlobalHotKeyOperatingModeAvailable()) {
01621 CGSConnection conn = s__CGSDefaultConnection();
01622 s_CGSGetGlobalHotKeyOperatingMode(conn, &mode);
01623 }
01624 else {
01625 mode = CGSGlobalHotKeyEnable;
01626 }
01627 return (mode == CGSGlobalHotKeyEnable);
01628 }
01629
01630 #endif
01631
01632
01633
01634
01635
01636 COSXScreen::CHotKeyItem::CHotKeyItem(UInt32 keycode, UInt32 mask) :
01637 m_ref(NULL),
01638 m_keycode(keycode),
01639 m_mask(mask)
01640 {
01641
01642 }
01643
01644 COSXScreen::CHotKeyItem::CHotKeyItem(EventHotKeyRef ref,
01645 UInt32 keycode, UInt32 mask) :
01646 m_ref(ref),
01647 m_keycode(keycode),
01648 m_mask(mask)
01649 {
01650
01651 }
01652
01653 EventHotKeyRef
01654 COSXScreen::CHotKeyItem::getRef() const
01655 {
01656 return m_ref;
01657 }
01658
01659 bool
01660 COSXScreen::CHotKeyItem::operator<(const CHotKeyItem& x) const
01661 {
01662 return (m_keycode < x.m_keycode ||
01663 (m_keycode == x.m_keycode && m_mask < x.m_mask));
01664 }