From cd26e66c2e8ddde06b5e22ef28d815ac1082a7c4 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Tue, 23 Aug 2016 10:44:20 +0200 Subject: Combine device and point id into 32 bit point id This allows us to not have conflicts between the point ids between different devices for QtQuick pointer handlers. We do this in QtGui because we can then safely compare point ids from QTouchEvent::TouchPoint and QQuickEventPoint. (Point ids that QtQuick pointer handlers use will be based on the point ids provided by QTouchEvent::TouchPoint::id) Change-Id: I8b9ab0d44224b15175b820d33cbb2d8bd21e99f2 Reviewed-by: Shawn Rutledge --- src/gui/kernel/qguiapplication.cpp | 4 +- src/gui/kernel/qtouchdevice.h | 1 + src/gui/kernel/qtouchdevice_p.h | 7 +- src/gui/kernel/qwindowsysteminterface.cpp | 43 ++++++- src/gui/kernel/qwindowsysteminterface_p.h | 2 +- .../gui/kernel/qtouchevent/tst_qtouchevent.cpp | 143 +++++++++++++++++++-- 6 files changed, 185 insertions(+), 15 deletions(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index d8457bc041..76386a30a0 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -84,6 +84,7 @@ #include "private/qcursor_p.h" #include "private/qopenglcontext_p.h" #include "private/qinputdevicemanager_p.h" +#include "private/qtouchdevice_p.h" #include "private/qdnd_p.h" #include @@ -1944,7 +1945,8 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo points << point; QEvent::Type type; - QList touchPoints = QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, &type); + QList touchPoints = + QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, QTouchDevicePrivate::get(m_fakeTouchDevice)->id, &type); QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers); fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; diff --git a/src/gui/kernel/qtouchdevice.h b/src/gui/kernel/qtouchdevice.h index 0fb24e47bf..c98aa69236 100644 --- a/src/gui/kernel/qtouchdevice.h +++ b/src/gui/kernel/qtouchdevice.h @@ -87,6 +87,7 @@ public: private: QTouchDevicePrivate *d; + friend class QTouchDevicePrivate; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QTouchDevice::Capabilities) diff --git a/src/gui/kernel/qtouchdevice_p.h b/src/gui/kernel/qtouchdevice_p.h index 203d9fca74..18d2af46a7 100644 --- a/src/gui/kernel/qtouchdevice_p.h +++ b/src/gui/kernel/qtouchdevice_p.h @@ -64,16 +64,21 @@ public: : type(QTouchDevice::TouchScreen), caps(QTouchDevice::Position), maxTouchPoints(1) - { } + { + static quint8 nextId = 2; // device 0 is not used, device 1 is for mouse device + id = nextId++; + } QTouchDevice::DeviceType type; QTouchDevice::Capabilities caps; QString name; int maxTouchPoints; + quint8 id; static void registerDevice(const QTouchDevice *dev); static void unregisterDevice(const QTouchDevice *dev); static bool isRegistered(const QTouchDevice *dev); + static QTouchDevicePrivate *get(QTouchDevice *q) { return q->d; } }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index bb778bc5fc..ecc84e73d7 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -460,9 +460,40 @@ void QWindowSystemInterface::handleTouchEvent(QWindow *w, QTouchDevice *device, handleTouchEvent(w, time, device, points, mods); } +static int g_nextPointId = 1; + +// map from device-independent point id (arbitrary) to "Qt point" ids +typedef QMap PointIdMap; +Q_GLOBAL_STATIC(PointIdMap, g_pointIdMap) + +/*! + This function maps potentially arbitrary point ids \a pointId in the 32 bit + value space to start from 1 and increase incrementally for each touch point + held down. If all touch points are released it will reset the id back to 1 + for the following touch point. + + We can then assume that the touch points ids will never become too large, + and it will then put the device identifier \a deviceId in the upper 8 bits. + This leaves us with max 255 devices, and 16.7M taps without full release + before we run out of value space. +*/ +static int acquireCombinedPointId(quint8 deviceId, int pointId) +{ + quint64 combinedId64 = (quint64(deviceId) << 32) + pointId; + auto it = g_pointIdMap->constFind(combinedId64); + int uid; + if (it == g_pointIdMap->constEnd()) { + uid = g_nextPointId++; + g_pointIdMap->insert(combinedId64, uid); + } else { + uid = *it; + } + return (deviceId << 24) + uid; +} + QList QWindowSystemInterfacePrivate::fromNativeTouchPoints(const QList &points, - const QWindow *window, + const QWindow *window, quint8 deviceId, QEvent::Type *type) { QList touchPoints; @@ -473,7 +504,7 @@ QList QList::const_iterator point = points.constBegin(); QList::const_iterator end = points.constEnd(); while (point != end) { - p.setId(point->id); + p.setId(acquireCombinedPointId(deviceId, point->id)); if (point->uniqueId >= 0) p.setUniqueId(point->uniqueId); p.setPressure(point->pressure); @@ -506,6 +537,11 @@ QList *type = QEvent::TouchEnd; } + if (states == Qt::TouchPointReleased) { + g_nextPointId = 1; + g_pointIdMap->clear(); + } + return touchPoints; } @@ -540,7 +576,8 @@ void QWindowSystemInterface::handleTouchEvent(QWindow *tlw, ulong timestamp, QTo return; QEvent::Type type; - QList touchPoints = QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, tlw, &type); + QList touchPoints = + QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, tlw, QTouchDevicePrivate::get(device)->id, &type); QWindowSystemInterfacePrivate::TouchEvent *e = new QWindowSystemInterfacePrivate::TouchEvent(tlw, timestamp, type, device, touchPoints, mods); diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index f471e1f550..e48a77a8ea 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -503,7 +503,7 @@ public: static QList fromNativeTouchPoints(const QList &points, - const QWindow *window, QEvent::Type *type = Q_NULLPTR); + const QWindow *window, quint8 deviceId, QEvent::Type *type = Q_NULLPTR); static QList toNativeTouchPoints(const QList& pointList, const QWindow *window); diff --git a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp index e6fd67e3a8..a3de9ee5b5 100644 --- a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp +++ b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp @@ -36,6 +36,7 @@ #include #include #include +#include class tst_QTouchEventWidget : public QWidget { @@ -199,6 +200,7 @@ private slots: void touchBeginPropagatesWhenIgnored(); void touchUpdateAndEndNeverPropagate(); void basicRawEventTranslation(); + void basicRawEventTranslationOfIds(); void multiPointRawEventTranslationOnTouchScreen(); void multiPointRawEventTranslationOnTouchPad(); void deleteInEventHandler(); @@ -602,7 +604,8 @@ void tst_QTouchEvent::basicRawEventTranslation() QCOMPARE(touchWidget.touchBeginPoints.count(), 1); QCOMPARE(touchWidget.timestamp, timestamp); QTouchEvent::TouchPoint touchBeginPoint = touchWidget.touchBeginPoints.first(); - QCOMPARE(touchBeginPoint.id(), rawTouchPoint.id()); + const int touchPointId = (QTouchDevicePrivate::get(touchScreenDevice)->id << 24) + 1; + QCOMPARE(touchBeginPoint.id(), touchPointId); QCOMPARE(touchBeginPoint.state(), rawTouchPoint.state()); QCOMPARE(touchBeginPoint.pos(), pos); QCOMPARE(touchBeginPoint.startPos(), pos); @@ -637,7 +640,7 @@ void tst_QTouchEvent::basicRawEventTranslation() QVERIFY(!touchWidget.seenTouchEnd); QCOMPARE(touchWidget.touchUpdatePoints.count(), 1); QTouchEvent::TouchPoint touchUpdatePoint = touchWidget.touchUpdatePoints.first(); - QCOMPARE(touchUpdatePoint.id(), rawTouchPoint.id()); + QCOMPARE(touchUpdatePoint.id(), touchPointId); QCOMPARE(touchUpdatePoint.state(), rawTouchPoint.state()); QCOMPARE(touchUpdatePoint.pos(), pos + delta); QCOMPARE(touchUpdatePoint.startPos(), pos); @@ -669,7 +672,7 @@ void tst_QTouchEvent::basicRawEventTranslation() QVERIFY(touchWidget.seenTouchEnd); QCOMPARE(touchWidget.touchEndPoints.count(), 1); QTouchEvent::TouchPoint touchEndPoint = touchWidget.touchEndPoints.first(); - QCOMPARE(touchEndPoint.id(), rawTouchPoint.id()); + QCOMPARE(touchEndPoint.id(), touchPointId); QCOMPARE(touchEndPoint.state(), rawTouchPoint.state()); QCOMPARE(touchEndPoint.pos(), pos + delta + delta); QCOMPARE(touchEndPoint.startPos(), pos); @@ -745,9 +748,11 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen() QVERIFY(!rightWidget.seenTouchEnd); QCOMPARE(leftWidget.touchBeginPoints.count(), 1); QCOMPARE(rightWidget.touchBeginPoints.count(), 1); + const int touchPointId0 = (QTouchDevicePrivate::get(touchScreenDevice)->id << 24) + 1; + const int touchPointId1 = touchPointId0 + 1; { QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchBeginPoints.first(); - QCOMPARE(leftTouchPoint.id(), rawTouchPoints[0].id()); + QCOMPARE(leftTouchPoint.id(), touchPointId0); QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state()); QCOMPARE(leftTouchPoint.pos(), leftPos); QCOMPARE(leftTouchPoint.startPos(), leftPos); @@ -767,7 +772,7 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen() QCOMPARE(leftTouchPoint.pressure(), qreal(1.)); QTouchEvent::TouchPoint rightTouchPoint = rightWidget.touchBeginPoints.first(); - QCOMPARE(rightTouchPoint.id(), rawTouchPoints[1].id()); + QCOMPARE(rightTouchPoint.id(), touchPointId1); QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state()); QCOMPARE(rightTouchPoint.pos(), rightPos); QCOMPARE(rightTouchPoint.startPos(), rightPos); @@ -811,7 +816,7 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen() QCOMPARE(rightWidget.touchUpdatePoints.count(), 1); { QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchUpdatePoints.first(); - QCOMPARE(leftTouchPoint.id(), rawTouchPoints[0].id()); + QCOMPARE(leftTouchPoint.id(), touchPointId0); QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state()); QCOMPARE(leftTouchPoint.pos(), QPointF(leftWidget.mapFromParent(centerPos.toPoint()))); QCOMPARE(leftTouchPoint.startPos(), leftPos); @@ -831,7 +836,7 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen() QCOMPARE(leftTouchPoint.pressure(), qreal(1.)); QTouchEvent::TouchPoint rightTouchPoint = rightWidget.touchUpdatePoints.first(); - QCOMPARE(rightTouchPoint.id(), rawTouchPoints[1].id()); + QCOMPARE(rightTouchPoint.id(), touchPointId1); QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state()); QCOMPARE(rightTouchPoint.pos(), QPointF(rightWidget.mapFromParent(centerPos.toPoint()))); QCOMPARE(rightTouchPoint.startPos(), rightPos); @@ -875,7 +880,7 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen() QCOMPARE(rightWidget.touchEndPoints.count(), 1); { QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchEndPoints.first(); - QCOMPARE(leftTouchPoint.id(), rawTouchPoints[0].id()); + QCOMPARE(leftTouchPoint.id(), touchPointId0); QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state()); QCOMPARE(leftTouchPoint.pos(), QPointF(leftWidget.mapFromParent(centerPos.toPoint()))); QCOMPARE(leftTouchPoint.startPos(), leftPos); @@ -895,7 +900,7 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen() QCOMPARE(leftTouchPoint.pressure(), qreal(0.)); QTouchEvent::TouchPoint rightTouchPoint = rightWidget.touchEndPoints.first(); - QCOMPARE(rightTouchPoint.id(), rawTouchPoints[1].id()); + QCOMPARE(rightTouchPoint.id(), touchPointId1); QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state()); QCOMPARE(rightTouchPoint.pos(), QPointF(rightWidget.mapFromParent(centerPos.toPoint()))); QCOMPARE(rightTouchPoint.startPos(), rightPos); @@ -1145,6 +1150,126 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad() } } +void tst_QTouchEvent::basicRawEventTranslationOfIds() +{ + if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)) + QSKIP("Wayland: This fails. Figure out why."); + + tst_QTouchEventWidget touchWidget; + touchWidget.setWindowTitle(QTest::currentTestFunction()); + touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); + touchWidget.setGeometry(100, 100, 400, 300); + touchWidget.show(); + QVERIFY(QTest::qWaitForWindowActive(&touchWidget)); + + QVarLengthArray pos; + QVarLengthArray screenPos; + for (int i = 0; i < 2; ++i) { + pos << touchWidget.rect().center() + QPointF(20*i, 20*i); + screenPos << touchWidget.mapToGlobal(pos[i].toPoint()); + } + QPointF delta(10, 10); + QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); + + QVector rawPosList; + rawPosList << QPointF(12, 34) << QPointF(56, 78); + + QList rawTouchPoints; + + // Press both points, this should be translated to a TouchBegin + for (int i = 0; i < 2; ++i) { + QTouchEvent::TouchPoint rawTouchPoint; + rawTouchPoint.setId(i); + rawTouchPoint.setState(Qt::TouchPointPressed); + rawTouchPoint.setScreenPos(screenPos[i]); + rawTouchPoint.setNormalizedPos(normalized(rawTouchPoint.pos(), screenGeometry)); + rawTouchPoint.setRawScreenPositions(rawPosList); + rawTouchPoints << rawTouchPoint; + } + QTouchEvent::TouchPoint &p0 = rawTouchPoints[0]; + QTouchEvent::TouchPoint &p1 = rawTouchPoints[1]; + + const ulong timestamp = 1234; + QWindow *window = touchWidget.windowHandle(); + QList nativeTouchPoints = + QWindowSystemInterfacePrivate::toNativeTouchPoints(rawTouchPoints, window); + QWindowSystemInterface::handleTouchEvent(window, timestamp, touchScreenDevice, nativeTouchPoints); + QCoreApplication::processEvents(); + QVERIFY(touchWidget.seenTouchBegin); + QVERIFY(!touchWidget.seenTouchUpdate); + QVERIFY(!touchWidget.seenTouchEnd); + QCOMPARE(touchWidget.touchBeginPoints.count(), 2); + + const int initialTouchPointId = (QTouchDevicePrivate::get(touchScreenDevice)->id << 24) + 1; + + for (int i = 0; i < touchWidget.touchBeginPoints.count(); ++i) { + QTouchEvent::TouchPoint touchBeginPoint = touchWidget.touchBeginPoints.at(i); + QCOMPARE(touchBeginPoint.id(), initialTouchPointId + i); + QCOMPARE(touchBeginPoint.state(), rawTouchPoints[i].state()); + } + + // moving the point should translate to TouchUpdate + for (int i = 0; i < rawTouchPoints.count(); ++i) { + QTouchEvent::TouchPoint &p = rawTouchPoints[i]; + p.setState(Qt::TouchPointMoved); + p.setScreenPos(p.screenPos() + delta); + p.setNormalizedPos(normalized(p.pos(), screenGeometry)); + } + nativeTouchPoints = + QWindowSystemInterfacePrivate::toNativeTouchPoints(rawTouchPoints, window); + QWindowSystemInterface::handleTouchEvent(window, 0, touchScreenDevice, nativeTouchPoints); + QCoreApplication::processEvents(); + QVERIFY(touchWidget.seenTouchBegin); + QVERIFY(touchWidget.seenTouchUpdate); + QVERIFY(!touchWidget.seenTouchEnd); + QCOMPARE(touchWidget.touchUpdatePoints.count(), 2); + QCOMPARE(touchWidget.touchUpdatePoints.at(0).id(), initialTouchPointId); + QCOMPARE(touchWidget.touchUpdatePoints.at(1).id(), initialTouchPointId + 1); + + // release last point + p0.setState(Qt::TouchPointStationary); + p1.setState(Qt::TouchPointReleased); + + nativeTouchPoints = + QWindowSystemInterfacePrivate::toNativeTouchPoints(rawTouchPoints, window); + QWindowSystemInterface::handleTouchEvent(window, 0, touchScreenDevice, nativeTouchPoints); + QCoreApplication::processEvents(); + QVERIFY(touchWidget.seenTouchBegin); + QVERIFY(touchWidget.seenTouchUpdate); + QVERIFY(!touchWidget.seenTouchEnd); + QCOMPARE(touchWidget.touchUpdatePoints.count(), 2); + QCOMPARE(touchWidget.touchUpdatePoints[0].id(), initialTouchPointId); + QCOMPARE(touchWidget.touchUpdatePoints[1].id(), initialTouchPointId + 1); + + // Press last point again, id should increase + p1.setState(Qt::TouchPointPressed); + p1.setId(42); // new id + nativeTouchPoints = + QWindowSystemInterfacePrivate::toNativeTouchPoints(rawTouchPoints, window); + QWindowSystemInterface::handleTouchEvent(window, 0, touchScreenDevice, nativeTouchPoints); + QCoreApplication::processEvents(); + QVERIFY(touchWidget.seenTouchBegin); + QVERIFY(touchWidget.seenTouchUpdate); + QVERIFY(!touchWidget.seenTouchEnd); + QCOMPARE(touchWidget.touchUpdatePoints.count(), 2); + QCOMPARE(touchWidget.touchUpdatePoints[0].id(), initialTouchPointId); + QCOMPARE(touchWidget.touchUpdatePoints[1].id(), initialTouchPointId + 2); + + // release everything + p0.setState(Qt::TouchPointReleased); + p1.setState(Qt::TouchPointReleased); + nativeTouchPoints = + QWindowSystemInterfacePrivate::toNativeTouchPoints(rawTouchPoints, window); + QWindowSystemInterface::handleTouchEvent(window, 0, touchScreenDevice, nativeTouchPoints); + QCoreApplication::processEvents(); + QVERIFY(touchWidget.seenTouchBegin); + QVERIFY(touchWidget.seenTouchUpdate); + QVERIFY(touchWidget.seenTouchEnd); + QCOMPARE(touchWidget.touchUpdatePoints.count(), 2); + QCOMPARE(touchWidget.touchUpdatePoints[0].id(), initialTouchPointId); + QCOMPARE(touchWidget.touchUpdatePoints[1].id(), initialTouchPointId + 2); +} + void tst_QTouchEvent::deleteInEventHandler() { if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)) -- cgit v1.2.3