MacOSX Double / Triple Click Fix

This patch corrects issues with double click and adds triple click to
MacOSX. Double click was functioning but double clicking and then
dragging would not work.
This commit is contained in:
James McMullan 2014-12-04 15:15:38 -05:00 committed by Nick Bolton
parent ecd51d231b
commit 1bbd086a17
2 changed files with 49 additions and 73 deletions

View File

@ -105,8 +105,8 @@ OSXScreen::OSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCurso
m_activeModifierHotKeyMask(0), m_activeModifierHotKeyMask(0),
m_eventTapPort(nullptr), m_eventTapPort(nullptr),
m_eventTapRLSR(nullptr), m_eventTapRLSR(nullptr),
m_lastSingleClick(0), m_lastClickTime(0),
m_lastDoubleClick(0), m_clickState(1),
m_lastSingleClickXCursor(0), m_lastSingleClickXCursor(0),
m_lastSingleClickYCursor(0), m_lastSingleClickYCursor(0),
m_autoShowHideCursor(autoShowHideCursor), m_autoShowHideCursor(autoShowHideCursor),
@ -524,6 +524,10 @@ OSXScreen::postMouseEvent(CGPoint& pos) const
} }
CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, button); CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, button);
// Dragging events also need the click state
CGEventSetIntegerValueField(event, kCGMouseEventClickState, m_clickState);
CGEventPost(kCGHIDEventTap, event); CGEventPost(kCGHIDEventTap, event);
CFRelease(event); CFRelease(event);
@ -532,20 +536,6 @@ OSXScreen::postMouseEvent(CGPoint& pos) const
void void
OSXScreen::fakeMouseButton(ButtonID id, bool press) OSXScreen::fakeMouseButton(ButtonID id, bool press)
{ {
NXEventHandle handle = NXOpenEventStatus();
double clickTime = NXClickTime(handle);
if ((ARCH->time() - m_lastDoubleClick) <= clickTime) {
// drop all down and up fakes immedately after a double click.
// TODO: perhaps there is a better way to do this, usually in
// finder, if you tripple click a folder, it will open it and
// then select a folder under the cursor -- and perhaps other
// strange behaviour might happen?
LOG((CLOG_DEBUG1 "dropping mouse button %s",
press ? "press" : "release"));
return;
}
// Buttons are indexed from one, but the button down array is indexed from zero // Buttons are indexed from one, but the button down array is indexed from zero
UInt32 index = id - kButtonLeft; UInt32 index = id - kButtonLeft;
if (index >= NumButtonIDs) { if (index >= NumButtonIDs) {
@ -570,60 +560,46 @@ OSXScreen::fakeMouseButton(ButtonID id, bool press)
// we define our own defaults. // we define our own defaults.
const double maxDiff = sqrt(2) + 0.0001; const double maxDiff = sqrt(2) + 0.0001;
if (press && (id == kButtonLeft) &&
((ARCH->time() - m_lastSingleClick) <= clickTime) &&
diff <= maxDiff) {
LOG((CLOG_DEBUG1 "faking mouse left double click")); NXEventHandle handle = NXOpenEventStatus();
double clickTime = NXClickTime(handle);
// finder does not seem to detect double clicks from two separate // As long as the click is within the time window and distance window
// CGEventCreateMouseEvent calls. so, if we detect a double click we // increase clickState (double click, triple click, etc)
// use CGEventSetIntegerValueField to tell the OS. // This will allow for higher than triple click but the quartz documenation
// // does not specify that this should be limited to triple click
// the caveat here is that findor will see this as a single click if(press) {
// followed by a double click (even though there should be only a if((ARCH->time() - m_lastClickTime) <= clickTime && diff <= maxDiff){
// double click). this may cause weird behaviour in other apps. m_clickState++;
// }
// for some reason using the old CGPostMouseEvent function, doesn't else {
// cause double clicks (though i'm sure it did work at some point). m_clickState = 1;
}
CGEventRef event = CGEventCreateMouseEvent( m_lastClickTime = ARCH->time();
NULL, kCGEventLeftMouseDown, pos, kCGMouseButtonLeft); }
CGEventSetIntegerValueField(event, kCGMouseEventClickState, 2); if(m_clickState == 1){
m_buttonState.set(index, kMouseButtonDown); m_lastSingleClickXCursor = m_xCursor;
CGEventPost(kCGHIDEventTap, event); m_lastSingleClickYCursor = m_yCursor;
}
CGEventSetType(event, kCGEventLeftMouseUp); EMouseButtonState state = press ? kMouseButtonDown : kMouseButtonUp;
m_buttonState.set(index, kMouseButtonUp);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event); LOG((CLOG_DEBUG1 "faking mouse button id: %d press: %s", id, press ? "pressed" : "released"));
m_lastDoubleClick = ARCH->time(); MouseButtonEventMapType thisButtonMap = MouseButtonEventMap[index];
} CGEventType type = thisButtonMap[state];
else {
// ... otherwise, perform a single press or release as normal. CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, index);
EMouseButtonState state = press ? kMouseButtonDown : kMouseButtonUp; CGEventSetIntegerValueField(event, kCGMouseEventClickState, m_clickState);
LOG((CLOG_DEBUG1 "faking mouse button id: %d press: %s", id, press ? "pressed" : "released")); m_buttonState.set(index, state);
CGEventPost(kCGHIDEventTap, event);
MouseButtonEventMapType thisButtonMap = MouseButtonEventMap[index]; CFRelease(event);
CGEventType type = thisButtonMap[state];
CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, index);
m_buttonState.set(index, state);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
m_lastSingleClick = ARCH->time();
m_lastSingleClickXCursor = m_xCursor;
m_lastSingleClickYCursor = m_yCursor;
}
if (!press && (id == kButtonLeft)) { if (!press && (id == kButtonLeft)) {
if (m_fakeDraggingStarted) { if (m_fakeDraggingStarted) {
m_getDropTargetThread = new Thread(new TMethodJob<OSXScreen>( m_getDropTargetThread = new Thread(new TMethodJob<OSXScreen>(

View File

@ -335,8 +335,8 @@ private:
CFRunLoopSourceRef m_eventTapRLSR; CFRunLoopSourceRef m_eventTapRLSR;
// for double click coalescing. // for double click coalescing.
double m_lastSingleClick; double m_lastClickTime;
double m_lastDoubleClick; int m_clickState;
SInt32 m_lastSingleClickXCursor; SInt32 m_lastSingleClickXCursor;
SInt32 m_lastSingleClickYCursor; SInt32 m_lastSingleClickYCursor;