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:
parent
f974d8d680
commit
f7a5da4146
|
@ -176,7 +176,7 @@ IF(UNIX)
|
||||||
ADD_DEFINITIONS(-DSYSAPI_UNIX=1 -DHAVE_CONFIG_H)
|
ADD_DEFINITIONS(-DSYSAPI_UNIX=1 -DHAVE_CONFIG_H)
|
||||||
|
|
||||||
IF(APPLE)
|
IF(APPLE)
|
||||||
ADD_DEFINITIONS(-DWINAPI_CARBON=1 -D_THREAD_SAFE)
|
ADD_DEFINITIONS(-DWINAPI_CARBON=1 -D_THREAD_SAFE -DMACOSX_DEPLOYMENT_TARGET=10.4)
|
||||||
ELSE(APPLE)
|
ELSE(APPLE)
|
||||||
ADD_DEFINITIONS(-DWINAPI_XWINDOWS=1)
|
ADD_DEFINITIONS(-DWINAPI_XWINDOWS=1)
|
||||||
ENDIF(APPLE)
|
ENDIF(APPLE)
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#if !defined(MAC_OS_X_VERSION_10_3) || \
|
#if !defined(MAC_OS_X_VERSION_10_3) || \
|
||||||
(MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_3)
|
(MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_3)
|
||||||
enum {
|
enum {
|
||||||
kEventClassSystem = 'macs',
|
kEventClassSystem = 'macs',
|
||||||
kEventSystemUserSessionActivated = 10,
|
kEventSystemUserSessionActivated = 10,
|
||||||
kEventSystemUserSessionDeactivated = 11
|
kEventSystemUserSessionDeactivated = 11
|
||||||
};
|
};
|
||||||
|
@ -54,11 +54,14 @@ enum {
|
||||||
// COSXScreen
|
// 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;
|
CEvent::Type COSXScreen::s_confirmSleepEvent = CEvent::kUnknown;
|
||||||
|
|
||||||
COSXScreen::COSXScreen(bool isPrimary) :
|
COSXScreen::COSXScreen(bool isPrimary) :
|
||||||
|
MouseButtonEventMap(NumButtonIDs),
|
||||||
m_isPrimary(isPrimary),
|
m_isPrimary(isPrimary),
|
||||||
m_isOnScreen(m_isPrimary),
|
m_isOnScreen(m_isPrimary),
|
||||||
m_cursorPosValid(false),
|
m_cursorPosValid(false),
|
||||||
|
@ -107,6 +110,8 @@ COSXScreen::COSXScreen(bool isPrimary) :
|
||||||
this, &m_switchEventHandlerRef);
|
this, &m_switchEventHandlerRef);
|
||||||
DisposeEventHandlerUPP(switchEventHandler);
|
DisposeEventHandlerUPP(switchEventHandler);
|
||||||
|
|
||||||
|
constructMouseButtonEventMap();
|
||||||
|
|
||||||
// watch for requests to sleep
|
// watch for requests to sleep
|
||||||
EVENTQUEUE->adoptHandler(COSXScreen::getConfirmSleepEvent(),
|
EVENTQUEUE->adoptHandler(COSXScreen::getConfirmSleepEvent(),
|
||||||
getEventTarget(),
|
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
|
void
|
||||||
COSXScreen::postMouseEvent(CGPoint& pos) const
|
COSXScreen::postMouseEvent(CGPoint& pos) const
|
||||||
{
|
{
|
||||||
|
@ -393,40 +418,29 @@ COSXScreen::postMouseEvent(CGPoint& pos) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// synthesize event. CGPostMouseEvent is a particularly good
|
CGEventType type = kCGEventMouseMoved;
|
||||||
// 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]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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
|
void
|
||||||
COSXScreen::fakeMouseButton(ButtonID id, bool press) const
|
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;
|
UInt32 index = id - kButtonLeft;
|
||||||
if (index >= sizeof(m_buttons) / sizeof(m_buttons[0])) {
|
if (index >= NumButtonIDs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update state
|
|
||||||
m_buttons[index] = press;
|
|
||||||
|
|
||||||
CGPoint pos;
|
CGPoint pos;
|
||||||
if (!m_cursorPosValid) {
|
if (!m_cursorPosValid) {
|
||||||
SInt32 x, y;
|
SInt32 x, y;
|
||||||
|
@ -434,7 +448,36 @@ COSXScreen::fakeMouseButton(ButtonID id, bool press) const
|
||||||
}
|
}
|
||||||
pos.x = m_xCursor;
|
pos.x = m_xCursor;
|
||||||
pos.y = m_yCursor;
|
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
|
void
|
||||||
|
@ -480,8 +523,17 @@ void
|
||||||
COSXScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const
|
COSXScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const
|
||||||
{
|
{
|
||||||
if (xDelta != 0 || yDelta != 0) {
|
if (xDelta != 0 || yDelta != 0) {
|
||||||
CGPostScrollWheelEvent(2, mapScrollWheelFromSynergy(yDelta),
|
// create a scroll event, post it and release it. not sure if kCGScrollEventUnitLine
|
||||||
-mapScrollWheelFromSynergy(xDelta));
|
// 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
|
// reset buttons
|
||||||
for (UInt32 i = 0; i < sizeof(m_buttons) / sizeof(m_buttons[0]); ++i) {
|
m_buttonState.reset();
|
||||||
m_buttons[i] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// avoid suppression of local hardware events
|
// avoid suppression of local hardware events
|
||||||
// stkamp@users.sourceforge.net
|
// stkamp@users.sourceforge.net
|
||||||
|
@ -642,22 +692,22 @@ COSXScreen::leave()
|
||||||
bool
|
bool
|
||||||
COSXScreen::setClipboard(ClipboardID, const IClipboard* src)
|
COSXScreen::setClipboard(ClipboardID, const IClipboard* src)
|
||||||
{
|
{
|
||||||
if(src != NULL) {
|
if(src != NULL) {
|
||||||
LOG((CLOG_DEBUG "setting clipboard"));
|
LOG((CLOG_DEBUG "setting clipboard"));
|
||||||
CClipboard::copy(&m_pasteboard, src);
|
CClipboard::copy(&m_pasteboard, src);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
COSXScreen::checkClipboards()
|
COSXScreen::checkClipboards()
|
||||||
{
|
{
|
||||||
LOG((CLOG_DEBUG1 "checking clipboard"));
|
LOG((CLOG_DEBUG1 "checking clipboard"));
|
||||||
if (m_pasteboard.synchronize()) {
|
if (m_pasteboard.synchronize()) {
|
||||||
LOG((CLOG_DEBUG "clipboard changed"));
|
LOG((CLOG_DEBUG "clipboard changed"));
|
||||||
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardClipboard);
|
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardClipboard);
|
||||||
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardSelection);
|
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardSelection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1158,7 +1208,7 @@ COSXScreen::enableDragTimer(bool enable)
|
||||||
EVENTQUEUE->adoptHandler(CEvent::kTimer, m_dragTimer,
|
EVENTQUEUE->adoptHandler(CEvent::kTimer, m_dragTimer,
|
||||||
new TMethodEventJob<COSXScreen>(this,
|
new TMethodEventJob<COSXScreen>(this,
|
||||||
&COSXScreen::handleDrag));
|
&COSXScreen::handleDrag));
|
||||||
TrackMouseLocationWithOptions(NULL, 0, 0, &m_dragLastPoint, &modifiers, &res);
|
TrackMouseLocationWithOptions(NULL, 0, 0, &m_dragLastPoint, &modifiers, &res);
|
||||||
}
|
}
|
||||||
else if (!enable && m_dragTimer != NULL) {
|
else if (!enable && m_dragTimer != NULL) {
|
||||||
EVENTQUEUE->removeHandler(CEvent::kTimer, m_dragTimer);
|
EVENTQUEUE->removeHandler(CEvent::kTimer, m_dragTimer);
|
||||||
|
@ -1186,9 +1236,8 @@ void
|
||||||
COSXScreen::updateButtons()
|
COSXScreen::updateButtons()
|
||||||
{
|
{
|
||||||
UInt32 buttons = GetCurrentButtonState();
|
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*
|
IKeyState*
|
||||||
|
@ -1243,9 +1292,9 @@ COSXScreen::updateScreenShape(const CGDirectDisplayID, const CGDisplayChangeSumm
|
||||||
m_yCenter = (rect.origin.y + rect.size.height) / 2;
|
m_yCenter = (rect.origin.y + rect.size.height) / 2;
|
||||||
|
|
||||||
delete[] displays;
|
delete[] displays;
|
||||||
if (m_isPrimary && !m_isOnScreen) {
|
if (m_isPrimary && !m_isOnScreen) {
|
||||||
sendEvent(getShapeChangedEvent());
|
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"));
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -15,11 +15,14 @@
|
||||||
#ifndef COSXSCREEN_H
|
#ifndef COSXSCREEN_H
|
||||||
#define COSXSCREEN_H
|
#define COSXSCREEN_H
|
||||||
|
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
|
#include "stdmap.h"
|
||||||
|
#include "stdvector.h"
|
||||||
|
|
||||||
#include <Carbon/Carbon.h>
|
#include <Carbon/Carbon.h>
|
||||||
#include "COSXClipboard.h"
|
#include "COSXClipboard.h"
|
||||||
#include "CPlatformScreen.h"
|
#include "CPlatformScreen.h"
|
||||||
#include "stdmap.h"
|
|
||||||
#include "stdvector.h"
|
|
||||||
|
|
||||||
#include <mach/mach_port.h>
|
#include <mach/mach_port.h>
|
||||||
#include <mach/mach_interface.h>
|
#include <mach/mach_interface.h>
|
||||||
|
@ -102,6 +105,8 @@ private:
|
||||||
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;
|
||||||
|
|
||||||
|
void constructMouseButtonEventMap();
|
||||||
|
|
||||||
bool onKey(CGEventRef event);
|
bool onKey(CGEventRef event);
|
||||||
bool onHotKey(EventRef event) const;
|
bool onHotKey(EventRef event) const;
|
||||||
|
|
||||||
|
@ -174,6 +179,28 @@ private:
|
||||||
UInt32 m_keycode;
|
UInt32 m_keycode;
|
||||||
UInt32 m_mask;
|
UInt32 m_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum MouseButtonState {
|
||||||
|
kMouseButtonUp = 0,
|
||||||
|
kMouseButtonDragged,
|
||||||
|
kMouseButtonDown,
|
||||||
|
kMouseButtonStateMax
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CMouseButtonState {
|
||||||
|
public:
|
||||||
|
void set(UInt32 button, MouseButtonState state);
|
||||||
|
bool any();
|
||||||
|
void reset();
|
||||||
|
void overwrite(UInt32 buttons);
|
||||||
|
|
||||||
|
bool test(UInt32 button) const;
|
||||||
|
SInt8 getFirstButtonDown() const;
|
||||||
|
private:
|
||||||
|
std::bitset<NumButtonIDs> m_buttons;
|
||||||
|
};
|
||||||
|
|
||||||
typedef std::map<UInt32, CHotKeyItem> HotKeyMap;
|
typedef std::map<UInt32, CHotKeyItem> HotKeyMap;
|
||||||
typedef std::vector<UInt32> HotKeyIDList;
|
typedef std::vector<UInt32> HotKeyIDList;
|
||||||
typedef std::map<KeyModifierMask, UInt32> ModifierHotKeyMap;
|
typedef std::map<KeyModifierMask, UInt32> ModifierHotKeyMap;
|
||||||
|
@ -196,7 +223,17 @@ private:
|
||||||
// mouse state
|
// mouse state
|
||||||
mutable SInt32 m_xCursor, m_yCursor;
|
mutable SInt32 m_xCursor, m_yCursor;
|
||||||
mutable bool m_cursorPosValid;
|
mutable bool m_cursorPosValid;
|
||||||
mutable boolean_t m_buttons[5];
|
|
||||||
|
/* FIXME: this data structure is explicitly marked mutable due
|
||||||
|
to a need to track the state of buttons since the remote
|
||||||
|
side only lets us know of change events, and because the
|
||||||
|
fakeMouseButton button method is marked 'const'. This is
|
||||||
|
Evil, and this should be moved to a place where it need not
|
||||||
|
be mutable as soon as possible. */
|
||||||
|
mutable CMouseButtonState m_buttonState;
|
||||||
|
typedef std::map<UInt16, CGEventType> MouseButtonEventMapType;
|
||||||
|
std::vector<MouseButtonEventMapType> MouseButtonEventMap;
|
||||||
|
|
||||||
bool m_cursorHidden;
|
bool m_cursorHidden;
|
||||||
SInt32 m_dragNumButtonsDown;
|
SInt32 m_dragNumButtonsDown;
|
||||||
Point m_dragLastPoint;
|
Point m_dragLastPoint;
|
||||||
|
|
|
@ -32,4 +32,6 @@ static const ButtonID kButtonRight = 3;
|
||||||
static const ButtonID kButtonExtra0 = 4;
|
static const ButtonID kButtonExtra0 = 4;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
static const UInt8 NumButtonIDs = 5;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue