From d3ce585a235e6a92b8a662c06f8686da977daa49 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 24 Jun 2009 12:34:31 +0200 Subject: Add QTouchEvent::DeviceType and deviceType() This enum indicates what kind of device generated the touch event (TouchScreen or TouchPad). We use this information to control how touch events are sent, specifically we restrict touch events to a single widget/QGraphicsItem on touch-pads, since there is no direct relationship between the physical touch location on the pad and the on- using the touch-pad). --- src/gui/graphicsview/qgraphicsscene.cpp | 39 ++++++++++++++++-------- src/gui/graphicsview/qgraphicsscene_p.h | 2 +- src/gui/kernel/qapplication.cpp | 48 ++++++++++++++++++++---------- src/gui/kernel/qapplication_p.h | 7 ++++- src/gui/kernel/qapplication_win.cpp | 2 +- src/gui/kernel/qapplication_x11.cpp | 2 +- src/gui/kernel/qcocoaview_mac.mm | 9 +++--- src/gui/kernel/qevent.cpp | 32 +++++++++++++++++--- src/gui/kernel/qevent.h | 11 ++++++- src/testlib/qtesttouch.h | 18 ++++++----- tests/auto/qtouchevent/tst_qtouchevent.cpp | 33 ++++++++++++++++---- 11 files changed, 148 insertions(+), 55 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 6998429..fb3a01c 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -6054,18 +6054,32 @@ void QGraphicsScenePrivate::touchEventHandler(QTouchEvent *sceneTouchEvent) // update state QGraphicsItem *item = 0; if (touchPoint.state() == Qt::TouchPointPressed) { - // determine which item this event will go to - cachedItemsUnderMouse = itemsAtPosition(touchPoint.screenPos().toPoint(), - touchPoint.scenePos(), - sceneTouchEvent->widget()); - item = cachedItemsUnderMouse.isEmpty() ? 0 : cachedItemsUnderMouse.first(); - int closestTouchPointId = findClosestTouchPointId(touchPoint.scenePos()); - QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPointId); - if (!item - || (closestItem - && (item->isAncestorOf(closestItem) - || closestItem->isAncestorOf(item)))) { - item = closestItem; + if (sceneTouchEvent->deviceType() == QTouchEvent::TouchPad) { + // on touch-pad devices, send all touch points to the same item + item = itemForTouchPointId.isEmpty() + ? 0 + : itemForTouchPointId.constBegin().value(); + } + + if (!item) { + // determine which item this touch point will go to + cachedItemsUnderMouse = itemsAtPosition(touchPoint.screenPos().toPoint(), + touchPoint.scenePos(), + sceneTouchEvent->widget()); + item = cachedItemsUnderMouse.isEmpty() ? 0 : cachedItemsUnderMouse.first(); + } + + if (sceneTouchEvent->deviceType() == QTouchEvent::TouchScreen) { + // on touch-screens, combine this touch point with the closest one we find if it + // is a a direct descendent or ancestor ( + int closestTouchPointId = findClosestTouchPointId(touchPoint.scenePos()); + QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPointId); + if (!item + || (closestItem + && (item->isAncestorOf(closestItem) + || closestItem->isAncestorOf(item)))) { + item = closestItem; + } } if (!item) continue; @@ -6124,6 +6138,7 @@ void QGraphicsScenePrivate::touchEventHandler(QTouchEvent *sceneTouchEvent) QTouchEvent touchEvent(eventType); touchEvent.setWidget(sceneTouchEvent->widget()); + touchEvent.setDeviceType(sceneTouchEvent->deviceType()); touchEvent.setModifiers(sceneTouchEvent->modifiers()); touchEvent.setTouchPointStates(it.value().first); touchEvent.setTouchPoints(it.value().second); diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index ebc854f..3c3a811 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -317,7 +317,7 @@ public: void sendGestureEvent(const QSet &gestures, const QSet &cancelled); QMap sceneCurrentTouchPoints; - QHash itemForTouchPointId; + QMap itemForTouchPointId; static void updateTouchPointsForItem(QGraphicsItem *item, QTouchEvent *touchEvent); int findClosestTouchPointId(const QPointF &scenePos); void touchEventHandler(QTouchEvent *touchEvent); diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 9a22fd5..0b01b73 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -5296,6 +5296,7 @@ int QApplicationPrivate::findClosestTouchPointId(const QPointF &screenPos) } void QApplicationPrivate::translateRawTouchEvent(QWidget *window, + QTouchEvent::DeviceType deviceType, const QList &touchPoints) { QApplicationPrivate *d = self; @@ -5312,21 +5313,33 @@ void QApplicationPrivate::translateRawTouchEvent(QWidget *window, switch (touchPoint.state()) { case Qt::TouchPointPressed: { - // determine which widget this event will go to - if (!window) - window = q->topLevelAt(touchPoint.screenPos().toPoint()); - if (!window) - continue; - widget = window->childAt(window->mapFromGlobal(touchPoint.screenPos().toPoint())); - if (!widget) - widget = window; + if (deviceType == QTouchEvent::TouchPad) { + // on touch-pads, send all touch points to the same widget + widget = d->widgetForTouchPointId.isEmpty() + ? 0 + : d->widgetForTouchPointId.constBegin().value(); + } + + if (!widget) { + // determine which widget this event will go to + if (!window) + window = q->topLevelAt(touchPoint.screenPos().toPoint()); + if (!window) + continue; + widget = window->childAt(window->mapFromGlobal(touchPoint.screenPos().toPoint())); + if (!widget) + widget = window; + } - int closestTouchPointId = d->findClosestTouchPointId(touchPoint.screenPos()); - QWidget *closestWidget = d->widgetForTouchPointId.value(closestTouchPointId); - if (closestWidget - && (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) { - widget = closestWidget; + if (deviceType == QTouchEvent::TouchScreen) { + int closestTouchPointId = d->findClosestTouchPointId(touchPoint.screenPos()); + QWidget *closestWidget = d->widgetForTouchPointId.value(closestTouchPointId); + if (closestWidget + && (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) { + widget = closestWidget; + } } + d->widgetForTouchPointId[touchPoint.id()] = widget; touchPoint.setStartScreenPos(touchPoint.screenPos()); touchPoint.setLastScreenPos(touchPoint.screenPos()); @@ -5356,6 +5369,7 @@ void QApplicationPrivate::translateRawTouchEvent(QWidget *window, widget = d->widgetForTouchPointId.value(touchPoint.id()); if (!widget) continue; + Q_ASSERT(d->appCurrentTouchPoints.contains(touchPoint.id())); QTouchEvent::TouchPoint previousTouchPoint = d->appCurrentTouchPoints.value(touchPoint.id()); touchPoint.setStartScreenPos(previousTouchPoint.startScreenPos()); @@ -5408,6 +5422,7 @@ void QApplicationPrivate::translateRawTouchEvent(QWidget *window, } QTouchEvent touchEvent(eventType, + deviceType, q->keyboardModifiers(), it.value().first, it.value().second); @@ -5433,10 +5448,11 @@ void QApplicationPrivate::translateRawTouchEvent(QWidget *window, } } -Q_GUI_EXPORT void qt_translateRawTouchEvent(const QList &touchPoints, - QWidget *window) +Q_GUI_EXPORT void qt_translateRawTouchEvent(QWidget *window, + QTouchEvent::DeviceType deviceType, + const QList &touchPoints) { - QApplicationPrivate::translateRawTouchEvent(window, touchPoints); + QApplicationPrivate::translateRawTouchEvent(window, deviceType, touchPoints); } QT_END_NAMESPACE diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index f2226ce..c5d9235 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -437,7 +437,7 @@ public: // map number of widget subscribed to it> QMap grabbedGestures; - QHash widgetForTouchPointId; + QMap widgetForTouchPointId; QMap appCurrentTouchPoints; static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); void initializeMultitouch(); @@ -448,6 +448,7 @@ public: void appendTouchPoint(const QTouchEvent::TouchPoint &touchPoint); void removeTouchPoint(int touchPointId); static void translateRawTouchEvent(QWidget *widget, + QTouchEvent::DeviceType deviceType, const QList &touchPoints); #if defined(Q_WS_WIN) @@ -491,6 +492,10 @@ private: static bool shouldSetFocus(QWidget *w, Qt::FocusPolicy policy); }; +Q_GUI_EXPORT void qt_translateRawTouchEvent(QWidget *window, + QTouchEvent::DeviceType deviceType, + const QList &touchPoints); + QT_END_NAMESPACE #endif // QAPPLICATION_P_H diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 85b6bf8..0daabde 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -4078,7 +4078,7 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) touchInputIDToTouchPointID.clear(); } - translateRawTouchEvent(widgetForHwnd, touchPoints); + translateRawTouchEvent(widgetForHwnd, QTouchEvent::TouchScreen, touchPoints); return true; } diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 76e76de..9acdf6d 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -6217,7 +6217,7 @@ void QApplicationPrivate::_q_readRX71MultiTouchEvents() for (int i = 0; i < allRX71TouchPoints.count(); ++i) touchPoints.append(allRX71TouchPoints.at(i).touchPoint); - translateRawTouchEvent(0, touchPoints); + translateRawTouchEvent(0, QTouchEvent::TouchScreen, touchPoints); } #else // !QT_RX71_MULTITOUCH diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index 827094d..28179b7 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -69,7 +69,6 @@ Q_GLOBAL_STATIC(DnDParams, qMacDnDParams); extern void qt_mac_update_cursor_at_global_pos(const QPoint &globalPos); // qcursor_mac.mm extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); // qapplication.cpp -extern bool qt_translateRawTouchEvent(const QList &touchPoints, QWidget *window); // qapplication.cpp extern OSViewRef qt_mac_nativeview_for(const QWidget *w); // qwidget_mac.mm extern const QStringList& qEnabledDraggedTypes(); // qmime_mac.cpp extern QPointer qt_mouseover; //qapplication_mac.mm @@ -874,25 +873,25 @@ extern "C" { - (void)touchesBeganWithEvent:(NSEvent *)event; { bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents); - qt_translateRawTouchEvent(QCocoaTouch::getCurrentTouchPointList(event, all), qwidget); + qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all)); } - (void)touchesMovedWithEvent:(NSEvent *)event; { bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents); - qt_translateRawTouchEvent(QCocoaTouch::getCurrentTouchPointList(event, all), qwidget); + qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all)); } - (void)touchesEndedWithEvent:(NSEvent *)event; { bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents); - qt_translateRawTouchEvent(QCocoaTouch::getCurrentTouchPointList(event, all), qwidget); + qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all)); } - (void)touchesCancelledWithEvent:(NSEvent *)event; { bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents); - qt_translateRawTouchEvent(QCocoaTouch::getCurrentTouchPointList(event, all), qwidget); + qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all)); } - (void)magnifyWithEvent:(NSEvent *)event; diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 759aeb9..1d1a73d 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -3734,15 +3734,39 @@ void QGestureEvent::accept(const QString &type) \since 4.6 */ +/*! \enum QTouchEvent::DeviceType + \since 4.6 + + This enum represents the type of device that generated a QTouchEvent. + + \value TouchScreen In this type of device, the touch surface and display are integrated. This + means the surface and display typically have the same size, such that there + is a direct relationship between the touch points' physical positions and the + coordinate reported by QTouchEvent::TouchPoint. As a result, Qt allows the + user to interact directly with multiple QWidgets and QGraphicsItems at the + same time. + + \value TouchPad In this type of device, the touch surface is separate from the display. There + is not a direct relationship between the physical touch location and the + on-screen coordinates. Instead, they are calculated relative to the current + mouse position, and the user must use the touch-pad to move this reference + point. Unlike touch-screens, Qt allows users to only interact with a single + QWidget or QGraphicsItem at a time. +*/ + /*! - Constructs a QTouchEvent with the given \a type and \a touchPoints. The \a touchPointStates and - \a modifiers are the current touch point states and keyboard modifiers at the time of the event. + Constructs a QTouchEvent with the given \a eventType, \a deviceType, and \a touchPoints. + The \a touchPointStates and \a modifiers are the current touch point states and keyboard + modifiers at the time of the event. */ -QTouchEvent::QTouchEvent(QEvent::Type type, +QTouchEvent::QTouchEvent(QEvent::Type eventType, + QTouchEvent::DeviceType deviceType, Qt::KeyboardModifiers modifiers, Qt::TouchPointStates touchPointStates, const QList &touchPoints) - : QInputEvent(type, modifiers), + : QInputEvent(eventType, modifiers), + _widget(0), + _deviceType(deviceType), _touchPointStates(touchPointStates), _touchPoints(touchPoints) { } diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 04303fb..146ceed 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -821,23 +821,32 @@ public: QTouchEventTouchPointPrivate *d; }; - QTouchEvent(QEvent::Type type, + enum DeviceType { + TouchScreen, + TouchPad + }; + + QTouchEvent(QEvent::Type eventType, + QTouchEvent::DeviceType deviceType = TouchScreen, Qt::KeyboardModifiers modifiers = Qt::NoModifier, Qt::TouchPointStates touchPointStates = 0, const QList &touchPoints = QList()); ~QTouchEvent(); inline QWidget *widget() const { return _widget; } + inline QTouchEvent::DeviceType deviceType() const { return _deviceType; } inline Qt::TouchPointStates touchPointStates() const { return _touchPointStates; } inline const QList &touchPoints() const { return _touchPoints; } // internal inline void setWidget(QWidget *widget) { _widget = widget; } + inline void setDeviceType(DeviceType deviceType) { _deviceType = deviceType; } inline void setTouchPointStates(Qt::TouchPointStates touchPointStates) { _touchPointStates = touchPointStates; } inline void setTouchPoints(const QList &touchPoints) { _touchPoints = touchPoints; } protected: QWidget *_widget; + QTouchEvent::DeviceType _deviceType; Qt::TouchPointStates _touchPointStates; QList _touchPoints; diff --git a/src/testlib/qtesttouch.h b/src/testlib/qtesttouch.h index 042dd7d..e35dbe2 100644 --- a/src/testlib/qtesttouch.h +++ b/src/testlib/qtesttouch.h @@ -62,7 +62,9 @@ QT_BEGIN_NAMESPACE QT_MODULE(Test) -extern Q_GUI_EXPORT void qt_translateRawTouchEvent(const QList &touchPoints, QWidget *window); +extern Q_GUI_EXPORT void qt_translateRawTouchEvent(QWidget *window, + QTouchEvent::DeviceType deviceType, + const QList &touchPoints); namespace QTest { @@ -104,8 +106,8 @@ namespace QTest } private: - QTouchEventSequence(QWidget *widget) - : targetWidget(widget) + QTouchEventSequence(QWidget *widget, QTouchEvent::DeviceType deviceType) + : targetWidget(widget), deviceType(deviceType) { } QTouchEventSequence(const QTouchEventSequence &v); @@ -125,18 +127,20 @@ namespace QTest } void commit() { - qt_translateRawTouchEvent(points.values(), targetWidget); + qt_translateRawTouchEvent(targetWidget, deviceType, points.values()); targetWidget = 0; } QMap points; QWidget *targetWidget; - friend QTouchEventSequence touchEvent(QWidget*); + QTouchEvent::DeviceType deviceType; + friend QTouchEventSequence touchEvent(QWidget *, QTouchEvent::DeviceType); }; - QTouchEventSequence touchEvent(QWidget *widget = 0) + QTouchEventSequence touchEvent(QWidget *widget = 0, + QTouchEvent::DeviceType deviceType = QTouchEvent::TouchScreen) { - return QTouchEventSequence(widget); + return QTouchEventSequence(widget, deviceType); } } diff --git a/tests/auto/qtouchevent/tst_qtouchevent.cpp b/tests/auto/qtouchevent/tst_qtouchevent.cpp index b21ba40..dee059b 100644 --- a/tests/auto/qtouchevent/tst_qtouchevent.cpp +++ b/tests/auto/qtouchevent/tst_qtouchevent.cpp @@ -109,6 +109,7 @@ private slots: void touchBeginPropagatesWhenIgnored(); void touchUpdateAndEndNeverPropagate(); void basicRawEventTranslation(); + void multiPointRawEventTranslation(); }; void tst_QTouchEvent::touchDisabledByDefault() @@ -121,6 +122,7 @@ void tst_QTouchEvent::touchDisabledByDefault() QList touchPoints; touchPoints.append(QTouchEvent::TouchPoint(0)); QTouchEvent touchEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, Qt::NoModifier, Qt::TouchPointPressed, touchPoints); @@ -140,6 +142,7 @@ void tst_QTouchEvent::touchEventAcceptedByDefault() QList touchPoints; touchPoints.append(QTouchEvent::TouchPoint(0)); QTouchEvent touchEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, Qt::NoModifier, Qt::TouchPointPressed, touchPoints); @@ -171,6 +174,7 @@ void tst_QTouchEvent::touchBeginPropagatesWhenIgnored() QList touchPoints; touchPoints.append(QTouchEvent::TouchPoint(0)); QTouchEvent touchEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, Qt::NoModifier, Qt::TouchPointPressed, touchPoints); @@ -210,6 +214,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() QList touchPoints; touchPoints.append(QTouchEvent::TouchPoint(0)); QTouchEvent touchBeginEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, Qt::NoModifier, Qt::TouchPointPressed, touchPoints); @@ -221,6 +226,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() // send the touch update to the child, but ignore it, it doesn't propagate QTouchEvent touchUpdateEvent(QEvent::TouchUpdate, + QTouchEvent::TouchScreen, Qt::NoModifier, Qt::TouchPointMoved, touchPoints); @@ -232,9 +238,10 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() // send the touch end, same thing should happen as with touch update QTouchEvent touchEndEvent(QEvent::TouchEnd, - Qt::NoModifier, - Qt::TouchPointReleased, - touchPoints); + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointReleased, + touchPoints); res = QApplication::sendEvent(&child, &touchEndEvent); QVERIFY(res); QVERIFY(!touchEndEvent.isAccepted()); @@ -261,7 +268,9 @@ void tst_QTouchEvent::basicRawEventTranslation() rawTouchPoint.setScreenPos(screenPos); rawTouchPoint.setNormalizedPos(QPointF(rawTouchPoint.pos().x() / screenGeometry.width(), rawTouchPoint.pos().y() / screenGeometry.height())); - qt_translateRawTouchEvent(QList() << rawTouchPoint, &touchWidget); + qt_translateRawTouchEvent(&touchWidget, + QTouchEvent::TouchScreen, + QList() << rawTouchPoint); QVERIFY(touchWidget.seenTouchBegin); QVERIFY(!touchWidget.seenTouchUpdate); QVERIFY(!touchWidget.seenTouchEnd); @@ -291,7 +300,9 @@ void tst_QTouchEvent::basicRawEventTranslation() rawTouchPoint.setScreenPos(screenPos + delta); rawTouchPoint.setNormalizedPos(QPointF(rawTouchPoint.pos().x() / screenGeometry.width(), rawTouchPoint.pos().y() / screenGeometry.height())); - qt_translateRawTouchEvent(QList() << rawTouchPoint, &touchWidget); + qt_translateRawTouchEvent(&touchWidget, + QTouchEvent::TouchScreen, + QList() << rawTouchPoint); QVERIFY(touchWidget.seenTouchBegin); QVERIFY(touchWidget.seenTouchUpdate); QVERIFY(!touchWidget.seenTouchEnd); @@ -321,7 +332,9 @@ void tst_QTouchEvent::basicRawEventTranslation() rawTouchPoint.setScreenPos(screenPos + delta + delta); rawTouchPoint.setNormalizedPos(QPointF(rawTouchPoint.pos().x() / screenGeometry.width(), rawTouchPoint.pos().y() / screenGeometry.height())); - qt_translateRawTouchEvent(QList() << rawTouchPoint, &touchWidget); + qt_translateRawTouchEvent(&touchWidget, + QTouchEvent::TouchScreen, + QList() << rawTouchPoint); QVERIFY(touchWidget.seenTouchBegin); QVERIFY(touchWidget.seenTouchUpdate); QVERIFY(touchWidget.seenTouchEnd); @@ -347,6 +360,14 @@ void tst_QTouchEvent::basicRawEventTranslation() QCOMPARE(touchEndPoint.pressure(), qreal(-1.)); } +void tst_QTouchEvent::multiPointRawEventTranslation() +{ + + + + +} + QTEST_MAIN(tst_QTouchEvent) #include "tst_qtouchevent.moc" -- cgit v0.12