Update input-event handing to Quartz-taps on OS X

Created by mthiel
Issue #238
This commit is contained in:
syed.amer@gilani.eu 2009-11-01 19:15:10 +00:00
parent 985648a95f
commit 9515338c75
4 changed files with 203 additions and 223 deletions

View File

@ -138,40 +138,57 @@ COSXKeyState::mapModifiersFromOSX(UInt32 mask) const
LOG((CLOG_DEBUG1 "mask: %04x", mask)); LOG((CLOG_DEBUG1 "mask: %04x", mask));
// convert // convert
KeyModifierMask outMask = 0; KeyModifierMask outMask = 0;
if ((mask & shiftKey) != 0) { if ((mask & kCGEventFlagMaskShift) != 0) {
outMask |= KeyModifierShift; outMask |= KeyModifierShift;
} }
if ((mask & rightShiftKey) != 0) { if ((mask & kCGEventFlagMaskControl) != 0) {
outMask |= KeyModifierShift;
}
if ((mask & controlKey) != 0) {
outMask |= KeyModifierControl; outMask |= KeyModifierControl;
} }
if ((mask & rightControlKey) != 0) { if ((mask & kCGEventFlagMaskAlternate) != 0) {
outMask |= KeyModifierControl;
}
if ((mask & cmdKey) != 0) {
outMask |= KeyModifierAlt; outMask |= KeyModifierAlt;
} }
if ((mask & optionKey) != 0) { if ((mask & kCGEventFlagMaskCommand) != 0) {
outMask |= KeyModifierSuper; outMask |= KeyModifierSuper;
} }
if ((mask & rightOptionKey) != 0) { if ((mask & kCGEventFlagMaskAlphaShift) != 0) {
outMask |= KeyModifierSuper;
}
if ((mask & alphaLock) != 0) {
outMask |= KeyModifierCapsLock; outMask |= KeyModifierCapsLock;
} }
if ((mask & s_osxNumLock) != 0) { if ((mask & kCGEventFlagMaskNumericPad) != 0) {
outMask |= KeyModifierNumLock; outMask |= KeyModifierNumLock;
} }
return outMask; return outMask;
} }
KeyModifierMask
COSXKeyState::mapModifiersToCarbon(UInt32 mask) const
{
KeyModifierMask outMask = 0;
if ((mask & kCGEventFlagMaskShift) != 0) {
outMask |= shiftKey;
}
if ((mask & kCGEventFlagMaskControl) != 0) {
outMask |= controlKey;
}
if ((mask & kCGEventFlagMaskCommand) != 0) {
outMask |= cmdKey;
}
if ((mask & kCGEventFlagMaskAlternate) != 0) {
outMask |= optionKey;
}
if ((mask & kCGEventFlagMaskAlphaShift) != 0) {
outMask |= alphaLock;
}
if ((mask & kCGEventFlagMaskNumericPad) != 0) {
outMask |= s_osxNumLock;
}
return outMask;
}
KeyButton KeyButton
COSXKeyState::mapKeyFromEvent(CKeyIDs& ids, COSXKeyState::mapKeyFromEvent(CKeyIDs& ids,
KeyModifierMask* maskOut, EventRef event) const KeyModifierMask* maskOut, CGEventRef event) const
{ {
ids.clear(); ids.clear();
@ -183,13 +200,11 @@ COSXKeyState::mapKeyFromEvent(CKeyIDs& ids,
} }
// get virtual key // get virtual key
UInt32 vkCode; UInt32 vkCode = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
GetEventParameter(event, kEventParamKeyCode, typeUInt32,
NULL, sizeof(vkCode), NULL, &vkCode);
// handle up events // handle up events
UInt32 eventKind = GetEventKind(event); UInt32 eventKind = CGEventGetType(event);
if (eventKind == kEventRawKeyUp) { if (eventKind == kCGEventKeyUp) {
// the id isn't used. we just need the same button we used on // the id isn't used. we just need the same button we used on
// the key press. note that we don't use or reset the dead key // the key press. note that we don't use or reset the dead key
// state; up events should not affect the dead key state. // state; up events should not affect the dead key state.
@ -214,9 +229,9 @@ COSXKeyState::mapKeyFromEvent(CKeyIDs& ids,
// get the event modifiers and remove the command and control // get the event modifiers and remove the command and control
// keys. note if we used them though. // keys. note if we used them though.
// UCKeyTranslate expects old-style Carbon modifiers, so convert.
UInt32 modifiers; UInt32 modifiers;
GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, modifiers = mapModifiersToCarbon(CGEventGetFlags(event));
NULL, sizeof(modifiers), NULL, &modifiers);
static const UInt32 s_commandModifiers = static const UInt32 s_commandModifiers =
cmdKey | controlKey | rightControlKey; cmdKey | controlKey | rightControlKey;
bool isCommand = ((modifiers & s_commandModifiers) != 0); bool isCommand = ((modifiers & s_commandModifiers) != 0);
@ -224,24 +239,22 @@ COSXKeyState::mapKeyFromEvent(CKeyIDs& ids,
// if we've used a command key then we want the glyph produced without // if we've used a command key then we want the glyph produced without
// the option key (i.e. the base glyph). // the option key (i.e. the base glyph).
if (isCommand) { //if (isCommand) {
modifiers &= ~optionKey; modifiers &= ~optionKey;
} //}
// choose action // choose action
UInt16 action; UInt16 action;
switch (eventKind) { if(eventKind==kCGEventKeyDown) {
case kEventRawKeyDown:
action = kUCKeyActionDown; action = kUCKeyActionDown;
break; }
else if(CGEventGetIntegerValueField(event, kCGKeyboardEventAutorepeat)==1) {
case kEventRawKeyRepeat:
action = kUCKeyActionAutoKey; action = kUCKeyActionAutoKey;
break; }
else {
default:
return 0; return 0;
} }
// translate via uchr resource // translate via uchr resource
CFDataRef ref = (CFDataRef) TISGetInputSourceProperty(currentKeyboardLayout, CFDataRef ref = (CFDataRef) TISGetInputSourceProperty(currentKeyboardLayout,
kTISPropertyUnicodeKeyLayoutData); kTISPropertyUnicodeKeyLayoutData);
@ -251,6 +264,7 @@ COSXKeyState::mapKeyFromEvent(CKeyIDs& ids,
// translate key // translate key
UniCharCount count; UniCharCount count;
UniChar chars[2]; UniChar chars[2];
//LOG((CLOG_DEBUG "modifiers: %08x", modifiers & 0xffu));
OSStatus status = UCKeyTranslate(layout, OSStatus status = UCKeyTranslate(layout,
vkCode & 0xffu, action, vkCode & 0xffu, action,
(modifiers >> 8) & 0xffu, (modifiers >> 8) & 0xffu,
@ -353,6 +367,7 @@ COSXKeyState::fakeKey(const Keystroke& keystroke)
switch (keystroke.m_type) { switch (keystroke.m_type) {
case Keystroke::kButton: case Keystroke::kButton:
{
LOG((CLOG_DEBUG1 " %03x (%08x) %s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client, keystroke.m_data.m_button.m_press ? "down" : "up")); LOG((CLOG_DEBUG1 " %03x (%08x) %s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client, keystroke.m_data.m_button.m_press ? "down" : "up"));
// let system figure out character for us // let system figure out character for us
@ -369,6 +384,7 @@ COSXKeyState::fakeKey(const Keystroke& keystroke)
if (keystroke.m_data.m_button.m_client) { if (keystroke.m_data.m_button.m_client) {
ARCH->sleep(0.01); ARCH->sleep(0.01);
} }
}
break; break;
case Keystroke::kGroup: case Keystroke::kGroup:

View File

@ -54,6 +54,12 @@ public:
*/ */
KeyModifierMask mapModifiersFromOSX(UInt32 mask) const; KeyModifierMask mapModifiersFromOSX(UInt32 mask) const;
//! Convert CG flags-style modifier mask to old-style Carbon
/*!
Still required in a few places for translation calls.
*/
KeyModifierMask mapModifiersToCarbon(UInt32 mask) const;
//! Map key event to keys //! Map key event to keys
/*! /*!
Converts a key event into a sequence of KeyIDs and the shadow modifier Converts a key event into a sequence of KeyIDs and the shadow modifier
@ -63,7 +69,7 @@ public:
KeyID. KeyID.
*/ */
KeyButton mapKeyFromEvent(CKeyIDs& ids, KeyButton mapKeyFromEvent(CKeyIDs& ids,
KeyModifierMask* maskOut, EventRef event) const; KeyModifierMask* maskOut, CGEventRef event) const;
//! Map key and mask to native values //! Map key and mask to native values
/*! /*!

View File

@ -87,38 +87,9 @@ COSXScreen::COSXScreen(bool isPrimary) :
m_keyState = new COSXKeyState(); m_keyState = new COSXKeyState();
if (m_isPrimary) { if (m_isPrimary) {
// 1x1 window (to minimze the back buffer allocated for this if (!AXAPIEnabled()) {
// window. 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."));
Rect bounds = { 100, 100, 101, 101 }; }
// m_hiddenWindow is a window meant to let us get mouse moves
// when the focus is on another computer. If you get your event
// from the application event target you'll get every mouse
// moves. On the other hand the Window event target will only
// get events when the mouse moves over the window.
// The ignoreClicks attributes makes it impossible for the
// user to click on our invisible window.
CreateNewWindow(kUtilityWindowClass,
kWindowNoShadowAttribute |
kWindowIgnoreClicksAttribute |
kWindowNoActivatesAttribute,
&bounds, &m_hiddenWindow);
// Make it invisible
SetWindowAlpha(m_hiddenWindow, 0);
ShowWindow(m_hiddenWindow);
// m_userInputWindow is a window meant to let us get mouse moves
// when the focus is on this computer.
Rect inputBounds = { 100, 100, 200, 200 };
CreateNewWindow(kUtilityWindowClass,
kWindowNoShadowAttribute |
kWindowOpaqueForEventsAttribute |
kWindowStandardHandlerAttribute,
&inputBounds, &m_userInputWindow);
SetWindowAlpha(m_userInputWindow, 0);
} }
// install display manager notification handler // install display manager notification handler
@ -155,15 +126,6 @@ COSXScreen::COSXScreen(bool isPrimary) :
} }
CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this); CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this);
if (m_hiddenWindow) {
CFRelease(m_hiddenWindow);
m_hiddenWindow = NULL;
}
if (m_userInputWindow) {
CFRelease(m_userInputWindow);
m_userInputWindow = NULL;
}
delete m_keyState; delete m_keyState;
delete m_screensaver; delete m_screensaver;
throw; throw;
@ -209,15 +171,6 @@ COSXScreen::~COSXScreen()
RemoveEventHandler(m_switchEventHandlerRef); RemoveEventHandler(m_switchEventHandlerRef);
CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this); CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this);
if (m_hiddenWindow) {
CFRelease(m_hiddenWindow);
m_hiddenWindow = NULL;
}
if (m_userInputWindow) {
CFRelease(m_userInputWindow);
m_userInputWindow = NULL;
}
delete m_keyState; delete m_keyState;
delete m_screensaver; delete m_screensaver;
@ -544,6 +497,20 @@ COSXScreen::enable()
if (m_isPrimary) { if (m_isPrimary) {
// FIXME -- start watching jump zones // FIXME -- start watching jump zones
// kCGEventTapOptionDefault = 0x00000000 (Missing in 10.4, so specified literally)
m_eventTapPort=CGEventTapCreate(kCGHIDEventTap, kCGHIDEventTap, 0,
kCGEventMaskForAllEvents,
handleCGInputEvent,
this);
if(!m_eventTapPort) {
LOG((CLOG_ERR "Failed to create quartz event tap."));
}
m_eventTapRLSR=CFMachPortCreateRunLoopSource(kCFAllocatorDefault, m_eventTapPort, 0);
if(!m_eventTapRLSR) {
LOG((CLOG_ERR "Failed to create a CFRunLoopSourceRef for the quartz event tap."));
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), m_eventTapRLSR, kCFRunLoopDefaultMode);
} }
else { else {
// FIXME -- prevent system from entering power save mode // FIXME -- prevent system from entering power save mode
@ -566,6 +533,15 @@ COSXScreen::disable()
{ {
if (m_isPrimary) { if (m_isPrimary) {
// FIXME -- stop watching jump zones, stop capturing input // FIXME -- stop watching jump zones, stop capturing input
if(m_eventTapRLSR) {
CFRelease(m_eventTapRLSR);
m_eventTapRLSR=NULL;
}
if(m_eventTapPort) {
CFRelease(m_eventTapPort);
m_eventTapPort=NULL;
}
} }
else { else {
// show cursor // show cursor
@ -595,12 +571,6 @@ void
COSXScreen::enter() COSXScreen::enter()
{ {
if (m_isPrimary) { if (m_isPrimary) {
// stop capturing input, watch jump zones
HideWindow( m_userInputWindow );
ShowWindow( m_hiddenWindow );
SetMouseCoalescingEnabled(true, NULL);
CGSetLocalEventsSuppressionInterval(0.0); CGSetLocalEventsSuppressionInterval(0.0);
// enable global hotkeys // enable global hotkeys
@ -640,17 +610,9 @@ COSXScreen::leave()
// warp to center // warp to center
warpCursor(m_xCenter, m_yCenter); warpCursor(m_xCenter, m_yCenter);
// capture events // This used to be necessary to get smooth mouse motion on other screens,
HideWindow(m_hiddenWindow); // but now is just to avoid a hesitating cursor when transitioning to
ShowWindow(m_userInputWindow); // the primary (this) screen.
RepositionWindow(m_userInputWindow,
m_userInputWindow, kWindowCenterOnMainScreen);
SetUserFocusWindow(m_userInputWindow);
// The OS will coalesce some events if they are similar enough in a
// short period of time this is bad for us since we need every event
// to send it over to other machines. So disable it.
SetMouseCoalescingEnabled(false, NULL);
CGSetLocalEventsSuppressionInterval(0.0001); CGSetLocalEventsSuppressionInterval(0.0001);
// disable global hotkeys // disable global hotkeys
@ -796,79 +758,6 @@ COSXScreen::handleSystemEvent(const CEvent& event, void*)
switch (eventClass) { switch (eventClass) {
case kEventClassMouse: case kEventClassMouse:
switch (GetEventKind(*carbonEvent)) { switch (GetEventKind(*carbonEvent)) {
case kEventMouseDown:
{
UInt16 myButton;
GetEventParameter(*carbonEvent,
kEventParamMouseButton,
typeMouseButton,
NULL,
sizeof(myButton),
NULL,
&myButton);
onMouseButton(true, myButton);
break;
}
case kEventMouseUp:
{
UInt16 myButton;
GetEventParameter(*carbonEvent,
kEventParamMouseButton,
typeMouseButton,
NULL,
sizeof(myButton),
NULL,
&myButton);
onMouseButton(false, myButton);
break;
}
case kEventMouseDragged:
case kEventMouseMoved:
{
HIPoint point;
GetEventParameter(*carbonEvent,
kEventParamMouseLocation,
typeHIPoint,
NULL,
sizeof(point),
NULL,
&point);
onMouseMove((SInt32)point.x, (SInt32)point.y);
break;
}
case kEventMouseWheelMoved:
{
EventMouseWheelAxis axis;
SInt32 delta;
GetEventParameter(*carbonEvent,
kEventParamMouseWheelAxis,
typeMouseWheelAxis,
NULL,
sizeof(axis),
NULL,
&axis);
if (axis == kEventMouseWheelAxisX ||
axis == kEventMouseWheelAxisY) {
GetEventParameter(*carbonEvent,
kEventParamMouseWheelDelta,
typeLongInteger,
NULL,
sizeof(delta),
NULL,
&delta);
if (axis == kEventMouseWheelAxisX) {
onMouseWheel(-mapScrollWheelToSynergy((SInt32)delta), 0);
}
else {
onMouseWheel(0, mapScrollWheelToSynergy((SInt32)delta));
}
}
break;
}
case kSynergyEventMouseScroll: case kSynergyEventMouseScroll:
{ {
OSStatus r; OSStatus r;
@ -907,13 +796,6 @@ COSXScreen::handleSystemEvent(const CEvent& event, void*)
case kEventClassKeyboard: case kEventClassKeyboard:
switch (GetEventKind(*carbonEvent)) { switch (GetEventKind(*carbonEvent)) {
case kEventRawKeyUp:
case kEventRawKeyDown:
case kEventRawKeyRepeat:
case kEventRawKeyModifiersChanged:
onKey(*carbonEvent);
break;
case kEventHotKeyPressed: case kEventHotKeyPressed:
case kEventHotKeyReleased: case kEventHotKeyReleased:
onHotKey(*carbonEvent); onHotKey(*carbonEvent);
@ -1071,22 +953,17 @@ COSXScreen::displayReconfigurationCallback(CGDirectDisplayID displayID, CGDispla
} }
bool bool
COSXScreen::onKey(EventRef event) COSXScreen::onKey(CGEventRef event)
{ {
UInt32 eventKind = GetEventKind(event); CGEventType eventKind = CGEventGetType(event);
// get the key and active modifiers // get the key and active modifiers
UInt32 virtualKey, macMask; UInt32 virtualKey = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
GetEventParameter(event, kEventParamKeyCode, typeUInt32, CGEventFlags macMask = CGEventGetFlags(event);
NULL, sizeof(virtualKey), NULL, &virtualKey);
GetEventParameter(event, kEventParamKeyModifiers, typeUInt32,
NULL, sizeof(macMask), NULL, &macMask);
LOG((CLOG_DEBUG1 "event: Key event kind: %d, keycode=%d", eventKind, virtualKey)); LOG((CLOG_DEBUG1 "event: Key event kind: %d, keycode=%d", eventKind, virtualKey));
// sadly, OS X doesn't report the virtualKey for modifier keys. // Special handling to track state of modifiers
// virtualKey will be zero for modifier keys. since that's not good if (eventKind == kCGEventFlagsChanged) {
// enough we'll have to figure out what the key was.
if (virtualKey == 0 && eventKind == kEventRawKeyModifiersChanged) {
// get old and new modifier state // get old and new modifier state
KeyModifierMask oldMask = getActiveModifiers(); KeyModifierMask oldMask = getActiveModifiers();
KeyModifierMask newMask = m_keyState->mapModifiersFromOSX(macMask); KeyModifierMask newMask = m_keyState->mapModifiersFromOSX(macMask);
@ -1126,17 +1003,19 @@ COSXScreen::onKey(EventRef event)
// so we check for a key/modifier match in our hot key map. // so we check for a key/modifier match in our hot key map.
if (!m_isOnScreen) { if (!m_isOnScreen) {
HotKeyToIDMap::const_iterator i = HotKeyToIDMap::const_iterator i =
m_hotKeyToIDMap.find(CHotKeyItem(virtualKey, macMask & 0xff00u)); m_hotKeyToIDMap.find(CHotKeyItem(virtualKey,
m_keyState->mapModifiersToCarbon(macMask)
& 0xff00u));
if (i != m_hotKeyToIDMap.end()) { if (i != m_hotKeyToIDMap.end()) {
UInt32 id = i->second; UInt32 id = i->second;
// determine event type // determine event type
CEvent::Type type; CEvent::Type type;
UInt32 eventKind = GetEventKind(event); //UInt32 eventKind = GetEventKind(event);
if (eventKind == kEventRawKeyDown) { if (eventKind == kCGEventKeyDown) {
type = getHotKeyDownEvent(); type = getHotKeyDownEvent();
} }
else if (eventKind == kEventRawKeyUp) { else if (eventKind == kCGEventKeyUp) {
type = getHotKeyUpEvent(); type = getHotKeyUpEvent();
} }
else { else {
@ -1151,9 +1030,9 @@ COSXScreen::onKey(EventRef event)
} }
// decode event type // decode event type
bool down = (eventKind == kEventRawKeyDown); bool down = (eventKind == kCGEventKeyDown);
bool up = (eventKind == kEventRawKeyUp); bool up = (eventKind == kCGEventKeyUp);
bool isRepeat = (eventKind == kEventRawKeyRepeat); bool isRepeat = (CGEventGetIntegerValueField(event, kCGKeyboardEventAutorepeat) == 1);
// map event to keys // map event to keys
KeyModifierMask mask; KeyModifierMask mask;
@ -1681,3 +1560,73 @@ COSXScreen::CHotKeyItem::operator<(const CHotKeyItem& x) const
return (m_keycode < x.m_keycode || return (m_keycode < x.m_keycode ||
(m_keycode == x.m_keycode && m_mask < x.m_mask)); (m_keycode == x.m_keycode && m_mask < x.m_mask));
} }
// Quartz event tap support
CGEventRef
COSXScreen::handleCGInputEvent(CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void* refcon)
{
COSXScreen* screen = (COSXScreen*)refcon;
CGPoint pos;
switch(type) {
case kCGEventLeftMouseDown:
case kCGEventRightMouseDown:
case kCGEventOtherMouseDown:
screen->onMouseButton(true, CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) + 1);
break;
case kCGEventLeftMouseUp:
case kCGEventRightMouseUp:
case kCGEventOtherMouseUp:
screen->onMouseButton(false, CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) + 1);
break;
case kCGEventMouseMoved:
case kCGEventLeftMouseDragged:
case kCGEventRightMouseDragged:
case kCGEventOtherMouseDragged:
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
// on the system. It hasn't been a problem before, though.
return event;
break;
case kCGEventScrollWheel:
screen->onMouseWheel(screen->mapScrollWheelToSynergy(
CGEventGetIntegerValueField(event, kCGScrollWheelEventDeltaAxis2)),
screen->mapScrollWheelToSynergy(
CGEventGetIntegerValueField(event, kCGScrollWheelEventDeltaAxis1)));
break;
case kCGEventKeyDown:
case kCGEventKeyUp:
case kCGEventFlagsChanged:
screen->onKey(event);
break;
case kCGEventTapDisabledByTimeout:
// Re-enable our event-tap
CGEventTapEnable(screen->m_eventTapPort, true);
LOG((CLOG_NOTE "Quartz Event tap was disabled by timeout. Re-enabling."));
break;
case kCGEventTapDisabledByUserInput:
LOG((CLOG_ERR "Quartz Event tap was disabled by user input!"));
break;
case NX_NULLEVENT:
break;
case NX_SYSDEFINED:
// Unknown, forward it
return event;
break;
default:
LOG((CLOG_NOTE "Unknown Quartz Event type: 0x%02x", type));
}
if(screen->m_isOnScreen) {
return event;
} else {
return NULL;
}
}

View File

@ -94,14 +94,14 @@ private:
void sendClipboardEvent(CEvent::Type type, ClipboardID id) const; void sendClipboardEvent(CEvent::Type type, ClipboardID id) const;
// message handlers // message handlers
bool onMouseMove(SInt32 x, SInt32 y); bool onMouseMove(SInt32 mx, SInt32 my);
// mouse button handler. pressed is true if this is a mousedown // mouse button handler. pressed is true if this is a mousedown
// event, false if it is a mouseup event. macButton is the index // event, false if it is a mouseup event. macButton is the index
// of the button pressed using the mac button mapping. // of the button pressed using the mac button mapping.
bool onMouseButton(bool pressed, UInt16 macButton); bool onMouseButton(bool pressed, UInt16 macButton);
bool onMouseWheel(SInt32 xDelta, SInt32 yDelta) const; bool onMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
bool onKey(EventRef event); bool onKey(CGEventRef event);
bool onHotKey(EventRef event) const; bool onHotKey(EventRef event) const;
// map mac mouse button to synergy buttons // map mac mouse button to synergy buttons
@ -153,6 +153,11 @@ private:
static void setGlobalHotKeysEnabled(bool enabled); static void setGlobalHotKeysEnabled(bool enabled);
static bool getGlobalHotKeysEnabled(); static bool getGlobalHotKeysEnabled();
// Quartz event tap support
static CGEventRef handleCGInputEvent(CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void* refcon);
private: private:
struct CHotKeyItem { struct CHotKeyItem {
public: public:
@ -241,6 +246,10 @@ private:
// events // events
static CEvent::Type s_confirmSleepEvent; static CEvent::Type s_confirmSleepEvent;
// Quartz input event support
CFMachPortRef m_eventTapPort;
CFRunLoopSourceRef m_eventTapRLSR;
}; };
#endif #endif