diff options
author | Richard Moe Gustavsen <richard.gustavsen@nokia.com> | 2009-06-22 11:20:03 (GMT) |
---|---|---|
committer | Richard Moe Gustavsen <richard.gustavsen@nokia.com> | 2009-06-22 11:29:05 (GMT) |
commit | 627a3b8928157bb7f25af406f61a2f9c5cb41e06 (patch) | |
tree | 6a352342fc1f8a9fe68329a87175cdc4f1ccede8 | |
parent | cb9852297373b8bdf462ea097e639b7dee11b972 (diff) | |
download | Qt-627a3b8928157bb7f25af406f61a2f9c5cb41e06.zip Qt-627a3b8928157bb7f25af406f61a2f9c5cb41e06.tar.gz Qt-627a3b8928157bb7f25af406f61a2f9c5cb41e06.tar.bz2 |
Multitouch, Cocoa: Mask mouse hover from the touch set
After a lot of thinking, the conclusion is that we really need to
to this. Lets see if we can add a flag to control it next.
-rw-r--r-- | src/gui/kernel/qcocoaview_mac.mm | 18 | ||||
-rw-r--r-- | src/gui/kernel/qmultitouch_mac.mm | 140 | ||||
-rw-r--r-- | src/gui/kernel/qmultitouch_mac_p.h | 10 |
3 files changed, 88 insertions, 80 deletions
diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index 9aa4dd2..e8e52f9 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -704,11 +704,6 @@ extern "C" { - (void)mouseUp:(NSEvent *)theEvent { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) - QCocoaTouch::setMouseInDraggingState(false); -#endif - bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonRelease, Qt::LeftButton); if (!mouseOK) @@ -752,11 +747,6 @@ extern "C" { - (void)mouseDragged:(NSEvent *)theEvent { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) - QCocoaTouch::setMouseInDraggingState(true); -#endif - qMacDnDParams()->view = self; qMacDnDParams()->theEvent = theEvent; bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::LeftButton); @@ -883,22 +873,22 @@ extern "C" { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 - (void)touchesBeganWithEvent:(NSEvent *)event; { - qt_translateRawTouchEvent(QCocoaTouch::getCurrentTouchPointList(event), qwidget); + qt_translateRawTouchEvent(QCocoaTouch::getCurrentTouchPointList(event, true), qwidget); } - (void)touchesMovedWithEvent:(NSEvent *)event; { - qt_translateRawTouchEvent(QCocoaTouch::getCurrentTouchPointList(event), qwidget); + qt_translateRawTouchEvent(QCocoaTouch::getCurrentTouchPointList(event, true), qwidget); } - (void)touchesEndedWithEvent:(NSEvent *)event; { - qt_translateRawTouchEvent(QCocoaTouch::getCurrentTouchPointList(event), qwidget); + qt_translateRawTouchEvent(QCocoaTouch::getCurrentTouchPointList(event, true), qwidget); } - (void)touchesCancelledWithEvent:(NSEvent *)event; { - qt_translateRawTouchEvent(QCocoaTouch::getCurrentTouchPointList(event), qwidget); + qt_translateRawTouchEvent(QCocoaTouch::getCurrentTouchPointList(event, true), qwidget); } - (void)magnifyWithEvent:(NSEvent *)event; diff --git a/src/gui/kernel/qmultitouch_mac.mm b/src/gui/kernel/qmultitouch_mac.mm index 89cfc24..0f43299 100644 --- a/src/gui/kernel/qmultitouch_mac.mm +++ b/src/gui/kernel/qmultitouch_mac.mm @@ -39,11 +39,11 @@ ** ****************************************************************************/ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 - #include <private/qmultitouch_mac_p.h> #include <qcursor.h> +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + QT_BEGIN_NAMESPACE #ifdef QT_MAC_USE_COCOA @@ -51,33 +51,28 @@ QT_BEGIN_NAMESPACE QHash<int, QCocoaTouch*> QCocoaTouch::_currentTouches; QPointF QCocoaTouch::_screenReferencePos; QPointF QCocoaTouch::_trackpadReferencePos; -bool QCocoaTouch::_inMouseDraggingState = false; int QCocoaTouch::_idAssignmentCount = 0; +int QCocoaTouch::_touchCount = 0; +bool QCocoaTouch::_maskMouseHover = true; QCocoaTouch::QCocoaTouch(NSTouch *nstouch) { + // Keep the identity that Cocoa assigns the + // touches, and use it as key in the touch hash: _identity = int([nstouch identity]); if (_currentTouches.size() == 0){ - // A new touch sequence is about to begin: - _touchPoint.setState(Qt::TouchPointPressed | Qt::TouchPointPrimary); - NSPoint npos = [nstouch normalizedPosition]; - _trackpadPos = QPointF(npos.x, npos.y); - // This touch will act as reference for all subsequent - // touches, so they appear next to each other on screen: - _trackpadReferencePos = _trackpadPos; - _screenReferencePos = QCursor::pos(); - _touchPoint.setScreenPos(_screenReferencePos); - // The first touch should always have 0 as id: + // The first touch should always have + // 0 as id that we use in Qt: _touchPoint.setId(0); _idAssignmentCount = 0; - _currentTouches.insert(_identity, this); } else { - // We are already tracking at least one touch point. _touchPoint.setId(++_idAssignmentCount); - _currentTouches.insert(_identity, this); - updateTouchData(nstouch, NSTouchPhaseBegan); } + + _touchPoint.setPressure(1.0); + _currentTouches.insert(_identity, this); + updateTouchData(nstouch, NSTouchPhaseBegan); } QCocoaTouch::~QCocoaTouch() @@ -87,10 +82,7 @@ QCocoaTouch::~QCocoaTouch() void QCocoaTouch::updateTouchData(NSTouch *nstouch, NSTouchPhase phase) { - NSPoint npos = [nstouch normalizedPosition]; - _trackpadPos = QPointF(npos.x, npos.y); - - if (_inMouseDraggingState || _currentTouches.size() == 1) + if (_touchCount == 1) _touchPoint.setState(toTouchPointState(phase) | Qt::TouchPointPrimary); else _touchPoint.setState(toTouchPointState(phase)); @@ -98,6 +90,14 @@ void QCocoaTouch::updateTouchData(NSTouch *nstouch, NSTouchPhase phase) // From the normalized position on the trackpad, calculate // where on screen the touchpoint should be according to the // reference position: + NSPoint npos = [nstouch normalizedPosition]; + _trackpadPos = QPointF(npos.x, npos.y); + + if (_touchPoint.id() == 0 && phase == NSTouchPhaseBegan) { + _trackpadReferencePos = _trackpadPos; + _screenReferencePos = QCursor::pos(); + } + NSSize dsize = [nstouch deviceSize]; float ppiX = (_trackpadPos.x() - _trackpadReferencePos.x()) * dsize.width; float ppiY = (_trackpadPos.y() - _trackpadReferencePos.y()) * dsize.height; @@ -136,65 +136,83 @@ Qt::TouchPointState QCocoaTouch::toTouchPointState(NSTouchPhase nsState) return qtState; } -void QCocoaTouch::setMouseInDraggingState(bool inDraggingState) -{ - // In mouse dragging state, _all_ fingers control the mouse. - // As such, all fingers should have the primary flag. - _inMouseDraggingState = inDraggingState; -} - -void QCocoaTouch::validateCurrentTouchList(NSEvent *event) -{ - // If the application shows the task switcher during a touch sequence - // we get into an inconsistant state. We try to detect that here: - NSTouchPhase p = NSTouchPhaseAny & ~NSTouchPhaseBegan; - NSSet *s = [event touchesMatchingPhase:p inView:nil]; - if ([s count] == 0 && !_currentTouches.isEmpty()) { - // Remove all instances, and basically start from scratch: - QList<QCocoaTouch *> list = _currentTouches.values(); - foreach (QCocoaTouch *t, _currentTouches.values()) - delete t; - _currentTouches.clear(); - } -} - -QList<QTouchEvent::TouchPoint> QCocoaTouch::getCurrentTouchPointList(NSEvent *event) +QList<QTouchEvent::TouchPoint> QCocoaTouch::getCurrentTouchPointList(NSEvent *event, bool maskMouseHover) { - validateCurrentTouchList(event); - // Go through all the touchpoints in cocoa, find, or create, a QCocoaTouch for - // them, update them, and return the result: QList<QTouchEvent::TouchPoint> touchPoints; - NSSet *ended = [event touchesMatchingPhase:NSTouchPhaseEnded | NSTouchPhaseCancelled inView:nil]; + NSSet *active = [event + touchesMatchingPhase:NSTouchPhaseBegan | NSTouchPhaseMoved | NSTouchPhaseStationary + inView:nil]; + _touchCount = [active count]; + + // First: remove touches that were ended by the user. If we are + // currently masking the mouse hover touch, a corresponding 'begin' + // has never been posted to the app. So we should not send + // the following remove either. + for (int i=0; i<int([ended count]); ++i) { NSTouch *touch = [[ended allObjects] objectAtIndex:i]; QCocoaTouch *qcocoaTouch = findQCocoaTouch(touch); if (qcocoaTouch) { qcocoaTouch->updateTouchData(touch, [touch phase]); - touchPoints.append(qcocoaTouch->_touchPoint); + if (!_maskMouseHover) + touchPoints.append(qcocoaTouch->_touchPoint); delete qcocoaTouch; } } - NSSet *began = [event touchesMatchingPhase:NSTouchPhaseBegan inView:nil]; - for (int i=0; i<int([began count]); ++i) { - NSTouch *touch = [[began allObjects] objectAtIndex:i]; + bool wasMaskingMouseHover = _maskMouseHover; + _maskMouseHover = maskMouseHover && _touchCount < 2; + + // Next: update, or create, existing touches. + // We always keep track of all touch points, even + // when masking the mouse hover touch: + + for (int i=0; i<int([active count]); ++i) { + NSTouch *touch = [[active allObjects] objectAtIndex:i]; QCocoaTouch *qcocoaTouch = findQCocoaTouch(touch); if (!qcocoaTouch) qcocoaTouch = new QCocoaTouch(touch); else - qcocoaTouch->updateTouchData(touch, [touch phase]); - touchPoints.append(qcocoaTouch->_touchPoint); + qcocoaTouch->updateTouchData(touch, wasMaskingMouseHover ? NSTouchPhaseBegan : [touch phase]); + if (!_maskMouseHover) + touchPoints.append(qcocoaTouch->_touchPoint); } - NSSet *active = [event touchesMatchingPhase:NSTouchPhaseMoved | NSTouchPhaseStationary inView:nil]; - for (int i=0; i<int([active count]); ++i) { - NSTouch *touch = [[active allObjects] objectAtIndex:i]; - QCocoaTouch *qcocoaTouch = findQCocoaTouch(touch); - if (qcocoaTouch) { - qcocoaTouch->updateTouchData(touch, [touch phase]); - touchPoints.append(qcocoaTouch->_touchPoint); + // Next: sadly, we need to check that our touch hash is in + // sync with cocoa. This is typically not the case after a system + // gesture happend (like a four-finger-swipe to show expose). + + if (_touchCount != _currentTouches.size()) { + // Remove all instances, and basically start from scratch: + touchPoints.clear(); + QList<QCocoaTouch *> list = _currentTouches.values(); + foreach (QCocoaTouch *qcocoaTouch, _currentTouches.values()) { + if (!_maskMouseHover) { + qcocoaTouch->_touchPoint.setState(Qt::TouchPointReleased); + touchPoints.append(qcocoaTouch->_touchPoint); + } + delete qcocoaTouch; } + _currentTouches.clear(); + _maskMouseHover = maskMouseHover; + return touchPoints; + } + + // Finally: If we in this call _started_ to mask the mouse + // hover touch, we need to fake a relase for it now (and refake + // a begin for it later, if needed). + + if (_maskMouseHover && !wasMaskingMouseHover && !_currentTouches.isEmpty()) { + // If one touch is still active, fake a release event for it. + QCocoaTouch *qcocoaTouch = _currentTouches.values().first(); + qcocoaTouch->_touchPoint.setState(Qt::TouchPointReleased); + touchPoints.append(qcocoaTouch->_touchPoint); + // Since this last touch also will end up beeing the first + // touch (if the user adds a second finger without lifting + // the first), we promote it to be the primary touch: + qcocoaTouch->_touchPoint.setId(0); + _idAssignmentCount = 0; } return touchPoints; diff --git a/src/gui/kernel/qmultitouch_mac_p.h b/src/gui/kernel/qmultitouch_mac_p.h index 92ed11a..9ec256a 100644 --- a/src/gui/kernel/qmultitouch_mac_p.h +++ b/src/gui/kernel/qmultitouch_mac_p.h @@ -53,8 +53,6 @@ #ifndef QMULTITOUCH_MAC_P_H #define QMULTITOUCH_MAC_P_H -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 - #ifdef QT_MAC_USE_COCOA #import <Cocoa/Cocoa.h> #endif @@ -63,6 +61,8 @@ #include <qhash.h> #include <QtCore> +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + QT_BEGIN_NAMESPACE #ifdef QT_MAC_USE_COCOA @@ -70,15 +70,16 @@ QT_BEGIN_NAMESPACE class QCocoaTouch { public: - static QList<QTouchEvent::TouchPoint> getCurrentTouchPointList(NSEvent *event); + static QList<QTouchEvent::TouchPoint> getCurrentTouchPointList(NSEvent *event, bool maskMouseHover); static void setMouseInDraggingState(bool inDraggingState); private: static QHash<int, QCocoaTouch*> _currentTouches; static QPointF _screenReferencePos; static QPointF _trackpadReferencePos; - static bool _inMouseDraggingState; static int _idAssignmentCount; + static int _touchCount; + static bool _maskMouseHover; QTouchEvent::TouchPoint _touchPoint; QPointF _trackpadPos; @@ -90,7 +91,6 @@ class QCocoaTouch void updateTouchData(NSTouch *nstouch, NSTouchPhase phase); static QCocoaTouch *findQCocoaTouch(NSTouch *nstouch); static Qt::TouchPointState toTouchPointState(NSTouchPhase nsState); - static void validateCurrentTouchList(NSEvent *event); }; #endif // QT_MAC_USE_COCOA |