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))