diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2019-10-26 22:31:45 +0200 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2019-11-26 14:47:44 +0000 |
commit | 5dad0afa9e0905bd384878327f19cc7faf3d8d9f (patch) | |
tree | 25224bc806bc3de7987e383041a54fd7396ccf60 /tests | |
parent | 1b5bb04b0e092a214328b90dae5eb15f128fb677 (diff) |
MultiPointTouchArea: stop ignoring Qt-synthesized mouse events
We ignored them because we assume that if a touch event is sent first,
the MultiPointTouchArea will handle it; and then if a synth-mouse event
is sent afterwards for some reason, it's irrelevant to MPTA. However:
1) A synth-mouse event should not actually be sent, because MPTA accepts
the touch event. 2) If Flickable is used with pressDelay set, Flickable
will send the delayed press in the form of a mouse event (it does not
know how to replay a touch event at all). So if MPTA is used in a
ListView delegate for example, it's necessary for MPTA to react to a
synth-mouse event during replay. In both the press delay replay
and QTabletEvent scenarios, the mouse event has source() set to
MouseEventSynthesizedByQt, so MPTA needs to handle those events.
After a synth-mouse event during replay, MPTA can still receive an
actual touch release, which thoroughly confuses its pre-existing logic.
In that case it helps to check whether the touchpoint ID is the same as
QQuickWindowPrivate::touchMouseId, handle the release of that point, and
also release the internal synthetic _mouseQpaTouchPoint which was
remembered from the mouse press.
Fixes: QTBUG-75750
Fixes: QTBUG-78818
Change-Id: I8149f8b05f00677eb07a2f09b725b1db5f95b122
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
(cherry picked from commit 0012f8bd152a36a67abc696465f27d612625b5d9)
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp index 9c19e8e522..7f5adff062 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp +++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp @@ -31,12 +31,15 @@ #include <private/qquickmultipointtoucharea_p.h> #include <private/qquickflickable_p.h> #include <private/qquickmousearea_p.h> +#include <private/qquickwindow_p.h> #include <qpa/qwindowsysteminterface.h> #include <QtQuick/qquickview.h> #include <QtGui/QScreen> #include "../../shared/util.h" #include "../shared/viewtestutil.h" +Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests") + class tst_QQuickMultiPointTouchArea : public QQmlDataTest { Q_OBJECT @@ -62,6 +65,7 @@ private slots: void nested(); void inFlickable(); void inFlickable2(); + void inFlickableWithPressDelay(); void inMouseArea(); void mouseAsTouchpoint(); void invisible(); @@ -812,6 +816,68 @@ void tst_QQuickMultiPointTouchArea::inFlickable2() QTRY_VERIFY(!flickable->isMoving()); } +void tst_QQuickMultiPointTouchArea::inFlickableWithPressDelay() // QTBUG-78818 +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> window(createAndShowView("inFlickable.qml")); + QVERIFY(window->rootObject() != nullptr); + QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window.data()); + + QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(window->rootObject()); + QVERIFY(flickable != nullptr); + flickable->setPressDelay(50); + + QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild<QQuickMultiPointTouchArea*>(); + QVERIFY(mpta != nullptr); + mpta->setMinimumTouchPoints(1); + QQuickTouchPoint *point11 = window->rootObject()->findChild<QQuickTouchPoint*>("point1"); + QPoint p1(20,100); + + // press: Flickable prevents delivery of TouchBegin, but sends mouse press instead, after the delay. + // MPTA handles the mouse press, and its first declared touchpoint is pressed. + QTest::touchEvent(window.data(), device).press(0, p1); + QQuickTouchUtils::flush(window.data()); + QTRY_COMPARE(point11->pressed(), true); + auto pointerEvent = windowPriv->pointerEventInstance(QQuickPointerDevice::touchDevices().at(0)); + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), mpta); + + // release: MPTA receives TouchEnd (which is asymmetric with mouse press); does NOT emit canceled. + QTest::touchEvent(window.data(), device).release(0, p1); + QQuickTouchUtils::flush(window.data()); + QCOMPARE(flickable->property("cancelCount").toInt(), 0); + + // press again + QTest::touchEvent(window.data(), device).press(0, p1); + QQuickTouchUtils::flush(window.data()); + QTRY_COMPARE(point11->pressed(), true); // wait until pressDelay exceeded + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), mpta); + + // drag past the threshold: Flickable takes over the grab, MPTA gets touchUngrab and is no longer pressed + int i = 0; + for (; i < 10 && window->mouseGrabberItem() != flickable; ++i) { + p1 += QPoint(0,dragThreshold); + QTest::touchEvent(window.data(), device).move(0, p1); + QQuickTouchUtils::flush(window.data()); + } + QCOMPARE(window->mouseGrabberItem(), flickable); + qCDebug(lcTests, "Flickable stole grab from MPTA after %d moves", i); + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), flickable); + QCOMPARE(point11->pressed(), false); + QVERIFY(flickable->property("cancelCount").toInt() > 0); // actually 2 because 2 touchPoints are declared... but only one was really cancelled + + // drag a little more and the Flickable moves + p1 += QPoint(0,1); + QTest::touchEvent(window.data(), device).move(0, p1); + QQuickTouchUtils::flush(window.data()); + QVERIFY(flickable->contentY() < 0); + QVERIFY(flickable->isMoving()); + + QTest::touchEvent(window.data(), device).release(0, p1); + QQuickTouchUtils::flush(window.data()); + + QTRY_VERIFY(!flickable->isMoving()); +} + // QTBUG-31047 void tst_QQuickMultiPointTouchArea::inMouseArea() { |