Fix for Issue 378, updating deprecated calls for creating mouse events under MacOS 10.6.

Thanks to snes350 for the initial patch to help fix this problem.
This commit is contained in:
Edward Carrel
2010-06-01 10:49:22 +00:00
parent f974d8d680
commit f7a5da4146
4 changed files with 192 additions and 60 deletions

View File

@@ -37,7 +37,7 @@
#if !defined(MAC_OS_X_VERSION_10_3) || \
(MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_3)
enum {
kEventClassSystem = 'macs',
kEventClassSystem = 'macs',
kEventSystemUserSessionActivated = 10,
kEventSystemUserSessionDeactivated = 11
};
@@ -54,11 +54,14 @@ enum {
// COSXScreen
//
bool COSXScreen::s_testedForGHOM = false;
bool COSXScreen::s_hasGHOM = false;
bool COSXScreen::s_testedForGHOM = false;
bool COSXScreen::s_hasGHOM = false;
CEvent::Type COSXScreen::s_confirmSleepEvent = CEvent::kUnknown;
COSXScreen::COSXScreen(bool isPrimary) :
MouseButtonEventMap(NumButtonIDs),
m_isPrimary(isPrimary),
m_isOnScreen(m_isPrimary),
m_cursorPosValid(false),
@@ -107,6 +110,8 @@ COSXScreen::COSXScreen(bool isPrimary) :
this, &m_switchEventHandlerRef);
DisposeEventHandlerUPP(switchEventHandler);
constructMouseButtonEventMap();
// watch for requests to sleep
EVENTQUEUE->adoptHandler(COSXScreen::getConfirmSleepEvent(),
getEventTarget(),
@@ -360,6 +365,26 @@ COSXScreen::unregisterHotKey(UInt32 id)
}
}
void
COSXScreen::constructMouseButtonEventMap()
{
const CGEventType source[NumButtonIDs][3] = {
kCGEventLeftMouseUp,kCGEventLeftMouseDragged,kCGEventLeftMouseDown,
kCGEventOtherMouseUp,kCGEventOtherMouseDragged,kCGEventOtherMouseDown,
kCGEventRightMouseUp,kCGEventRightMouseDragged,kCGEventRightMouseDown,
kCGEventOtherMouseUp,kCGEventOtherMouseDragged,kCGEventOtherMouseDown,
kCGEventOtherMouseUp,kCGEventOtherMouseDragged,kCGEventOtherMouseDown};
for (UInt16 button = 0; button < NumButtonIDs; button++) {
MouseButtonEventMapType new_map;
for (UInt16 state = (UInt32) kMouseButtonUp; state < kMouseButtonStateMax; state++) {
CGEventType curEvent = source[button][state];
new_map[state] = curEvent;
}
MouseButtonEventMap[button] = new_map;
}
}
void
COSXScreen::postMouseEvent(CGPoint& pos) const
{
@@ -392,41 +417,30 @@ COSXScreen::postMouseEvent(CGPoint& pos) const
}
}
}
// synthesize event. CGPostMouseEvent is a particularly good
// example of a bad API. we have to shadow the mouse state to
// use this API and if we want to support more buttons we have
// to recompile.
//
// the order of buttons on the mac is:
// 1 - Left
// 2 - Right
// 3 - Middle
// Whatever the USB device defined.
//
// It is a bit weird that the behaviour of buttons over 3 are dependent
// on currently plugged in USB devices.
CGPostMouseEvent(pos, true, sizeof(m_buttons) / sizeof(m_buttons[0]),
m_buttons[0],
m_buttons[2],
m_buttons[1],
m_buttons[3],
m_buttons[4]);
}
CGEventType type = kCGEventMouseMoved;
SInt8 button = m_buttonState.getFirstButtonDown();
if (button != -1) {
MouseButtonEventMapType thisButtonType = MouseButtonEventMap[button];
type = thisButtonType[kMouseButtonDragged];
}
CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, button);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
}
void
COSXScreen::fakeMouseButton(ButtonID id, bool press) const
{
// get button index
// Buttons are indexed from one, but the button down array is indexed from zero
UInt32 index = id - kButtonLeft;
if (index >= sizeof(m_buttons) / sizeof(m_buttons[0])) {
if (index >= NumButtonIDs) {
return;
}
// update state
m_buttons[index] = press;
CGPoint pos;
if (!m_cursorPosValid) {
SInt32 x, y;
@@ -434,7 +448,36 @@ COSXScreen::fakeMouseButton(ButtonID id, bool press) const
}
pos.x = m_xCursor;
pos.y = m_yCursor;
postMouseEvent(pos);
// synthesize event. CGEventCreateMouseEvent creates a retained mouse
// event, which must also be posted and released. Note this is
// similar to the use of CGEventRef in postMouseEvent above.
// One of the arguments changes based on whether a button is being
// pressed or released, pressed corresponding to when "press" is true.
CGEventRef event;
// the switch statement handles which button was pressed. the left
// and right mouse buttons must be handled separately from any
// other buttons
CGEventType type;
MouseButtonState state;
if (press) {
state = kMouseButtonDown;
} else {
state = kMouseButtonUp;
}
MouseButtonEventMapType thisButtonMap = MouseButtonEventMap[index];
type = thisButtonMap[state];
event = CGEventCreateMouseEvent(NULL, type, pos, index);
m_buttonState.set(index, state);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
}
void
@@ -480,8 +523,17 @@ void
COSXScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const
{
if (xDelta != 0 || yDelta != 0) {
CGPostScrollWheelEvent(2, mapScrollWheelFromSynergy(yDelta),
-mapScrollWheelFromSynergy(xDelta));
// create a scroll event, post it and release it. not sure if kCGScrollEventUnitLine
// is the right choice here over kCGScrollEventUnitPixel
CGEventRef scrollEvent = CGEventCreateScrollWheelEvent(NULL,
kCGScrollEventUnitLine,
2,
mapScrollWheelFromSynergy(yDelta),
-mapScrollWheelFromSynergy(xDelta));
CGEventPost(kCGHIDEventTap, scrollEvent);
CFRelease(scrollEvent);
}
}
@@ -583,9 +635,7 @@ COSXScreen::enter()
}
// reset buttons
for (UInt32 i = 0; i < sizeof(m_buttons) / sizeof(m_buttons[0]); ++i) {
m_buttons[i] = false;
}
m_buttonState.reset();
// avoid suppression of local hardware events
// stkamp@users.sourceforge.net
@@ -642,22 +692,22 @@ COSXScreen::leave()
bool
COSXScreen::setClipboard(ClipboardID, const IClipboard* src)
{
if(src != NULL) {
LOG((CLOG_DEBUG "setting clipboard"));
CClipboard::copy(&m_pasteboard, src);
}
return true;
if(src != NULL) {
LOG((CLOG_DEBUG "setting clipboard"));
CClipboard::copy(&m_pasteboard, src);
}
return true;
}
void
COSXScreen::checkClipboards()
{
LOG((CLOG_DEBUG1 "checking clipboard"));
if (m_pasteboard.synchronize()) {
LOG((CLOG_DEBUG "clipboard changed"));
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardClipboard);
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardSelection);
}
LOG((CLOG_DEBUG1 "checking clipboard"));
if (m_pasteboard.synchronize()) {
LOG((CLOG_DEBUG "clipboard changed"));
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardClipboard);
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardSelection);
}
}
void
@@ -926,7 +976,7 @@ COSXScreen::displayReconfigurationCallback(CGDirectDisplayID displayID, CGDispla
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);
}
@@ -1158,7 +1208,7 @@ COSXScreen::enableDragTimer(bool enable)
EVENTQUEUE->adoptHandler(CEvent::kTimer, m_dragTimer,
new TMethodEventJob<COSXScreen>(this,
&COSXScreen::handleDrag));
TrackMouseLocationWithOptions(NULL, 0, 0, &m_dragLastPoint, &modifiers, &res);
TrackMouseLocationWithOptions(NULL, 0, 0, &m_dragLastPoint, &modifiers, &res);
}
else if (!enable && m_dragTimer != NULL) {
EVENTQUEUE->removeHandler(CEvent::kTimer, m_dragTimer);
@@ -1186,9 +1236,8 @@ void
COSXScreen::updateButtons()
{
UInt32 buttons = GetCurrentButtonState();
for (size_t i = 0; i < sizeof(m_buttons) / sizeof(m_buttons[0]); ++i) {
m_buttons[i] = ((buttons & (1u << i)) != 0);
}
m_buttonState.overwrite(buttons);
}
IKeyState*
@@ -1200,7 +1249,7 @@ COSXScreen::getKeyState() const
void
COSXScreen::updateScreenShape(const CGDirectDisplayID, const CGDisplayChangeSummaryFlags flags)
{
// get info for each display
CGDisplayCount displayCount = 0;
@@ -1243,9 +1292,9 @@ COSXScreen::updateScreenShape(const CGDirectDisplayID, const CGDisplayChangeSumm
m_yCenter = (rect.origin.y + rect.size.height) / 2;
delete[] displays;
if (m_isPrimary && !m_isOnScreen) {
sendEvent(getShapeChangedEvent());
}
if (m_isPrimary && !m_isOnScreen) {
sendEvent(getShapeChangedEvent());
}
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"));
}
@@ -1610,3 +1659,47 @@ COSXScreen::handleCGInputEvent(CGEventTapProxy proxy,
return NULL;
}
}
void
COSXScreen::CMouseButtonState::set(UInt32 button, MouseButtonState state)
{
bool newState = (state == kMouseButtonDown);
m_buttons.set(button, newState);
}
bool
COSXScreen::CMouseButtonState::any()
{
return m_buttons.any();
}
void
COSXScreen::CMouseButtonState::reset()
{
m_buttons.reset();
}
void
COSXScreen::CMouseButtonState::overwrite(UInt32 buttons)
{
m_buttons = std::bitset<NumButtonIDs>(buttons);
}
bool
COSXScreen::CMouseButtonState::test(UInt32 button) const
{
return m_buttons.test(button);
}
SInt8
COSXScreen::CMouseButtonState::getFirstButtonDown() const
{
if (m_buttons.any()) {
for (unsigned short button = 0; button < m_buttons.size(); button++) {
if (m_buttons.test(button)) {
return button;
}
}
}
return -1;
}