diff options
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 42 | ||||
-rw-r--r-- | src/quick/items/qquickwindow_p.h | 3 | ||||
-rw-r--r-- | tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 56 |
3 files changed, 85 insertions, 16 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index f705f132fc..c55db04566 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -64,6 +64,7 @@ #include <QtGui/qpainter.h> #include <QtGui/qevent.h> #include <QtGui/qmatrix4x4.h> +#include <QtGui/qpa/qplatformtheme.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/qabstractanimation.h> #include <QtCore/QLibraryInfo> @@ -632,25 +633,28 @@ static QMouseEvent *touchToMouseEvent(QEvent::Type type, const QTouchEvent::Touc return me; } -bool QQuickWindowPrivate::checkIfDoubleClicked(ulong newPressEventTimestamp) +bool QQuickWindowPrivate::checkIfDoubleTapped(ulong newPressEventTimestamp, QPoint newPressPos) { - bool doubleClicked; + bool doubleClicked = false; + + if (touchMousePressTimestamp > 0) { + QPoint distanceBetweenPresses = newPressPos - touchMousePressPos; + const int doubleTapDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::TouchDoubleTapDistance).toInt(); + doubleClicked = (qAbs(distanceBetweenPresses.x()) <= doubleTapDistance) && (qAbs(distanceBetweenPresses.y()) <= doubleTapDistance); - if (touchMousePressTimestamp == 0) { - // just initialize the variable - touchMousePressTimestamp = newPressEventTimestamp; - doubleClicked = false; - } else { - ulong timeBetweenPresses = newPressEventTimestamp - touchMousePressTimestamp; - ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()-> - mouseDoubleClickInterval()); - doubleClicked = timeBetweenPresses < doubleClickInterval; if (doubleClicked) { - touchMousePressTimestamp = 0; - } else { - touchMousePressTimestamp = newPressEventTimestamp; + ulong timeBetweenPresses = newPressEventTimestamp - touchMousePressTimestamp; + ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()-> + mouseDoubleClickInterval()); + doubleClicked = timeBetweenPresses < doubleClickInterval; } } + if (doubleClicked) { + touchMousePressTimestamp = 0; + } else { + touchMousePressTimestamp = newPressEventTimestamp; + touchMousePressPos = newPressPos; + } return doubleClicked; } @@ -707,7 +711,9 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve if (auto pointerEventPoint = pointerEvent->pointById(p.id())) pointerEventPoint->setGrabberItem(item); - if (checkIfDoubleClicked(event->timestamp())) { + if (checkIfDoubleTapped(event->timestamp(), p.screenPos().toPoint())) { + // since we synth the mouse event from from touch, we respect the + // QPlatformTheme::TouchDoubleTapDistance instead of QPlatformTheme::MouseDoubleClickDistance QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event.data(), item, false)); QCoreApplication::sendEvent(item, mouseDoubleClick.data()); event->setAccepted(mouseDoubleClick->isAccepted()); @@ -722,6 +728,12 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve // Touch point was there before and moved } else if (touchMouseDevice == device && p.id() == touchMouseId) { if (p.state() & Qt::TouchPointMoved) { + if (touchMousePressTimestamp != 0) { + const int doubleTapDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::TouchDoubleTapDistance).toInt(); + const QPoint moveDelta = p.screenPos().toPoint() - touchMousePressPos; + if (moveDelta.x() >= doubleTapDistance || moveDelta.y() >= doubleTapDistance) + touchMousePressTimestamp = 0; // Got dragged too far, dismiss the double tap + } if (QQuickItem *mouseGrabberItem = q->mouseGrabberItem()) { QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event.data(), mouseGrabberItem, false)); QCoreApplication::sendEvent(item, me.data()); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 5a3807b24f..63760a3b68 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -135,8 +135,9 @@ public: #endif int touchMouseId; QQuickPointerDevice *touchMouseDevice; - bool checkIfDoubleClicked(ulong newPressEventTimestamp); + bool checkIfDoubleTapped(ulong newPressEventTimestamp, QPoint newPressPos); ulong touchMousePressTimestamp; + QPoint touchMousePressPos; // in screen coordiantes void cancelTouchMouseSynthesis(); // Mouse positions are saved in widget coordinates diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 4cf7fa7119..f08b9207d1 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -353,6 +353,11 @@ protected: m_mouseEvents << *event; } + void mouseDoubleClickEvent(QMouseEvent *event) override { + qCDebug(lcTests) << event; + m_mouseEvents << *event; + } + public: QList<QMouseEvent> m_mouseEvents; QList<QTouchEvent> m_touchEvents; @@ -401,6 +406,8 @@ private slots: void mouseFromTouch_basic(); void synthMouseFromTouch_data(); void synthMouseFromTouch(); + void synthMouseDoubleClickFromTouch_data(); + void synthMouseDoubleClickFromTouch(); void clearWindow(); @@ -1241,6 +1248,55 @@ void tst_qquickwindow::synthMouseFromTouch() QCOMPARE(ev.source(), Qt::MouseEventSynthesizedByQt); } +void tst_qquickwindow::synthMouseDoubleClickFromTouch_data() +{ + QTest::addColumn<QPoint>("movement"); + QTest::addColumn<QPoint>("distanceBetweenPresses"); + QTest::addColumn<bool>("expectedSynthesizedDoubleClickEvent"); + + QTest::newRow("normal") << QPoint(0, 0) << QPoint(0, 0) << true; + QTest::newRow("with 1 pixel wiggle") << QPoint(1, 1) << QPoint(1, 1) << true; + QTest::newRow("too much distance to second tap") << QPoint(0, 0) << QPoint(50, 0) << false; + QTest::newRow("too much drag") << QPoint(50, 0) << QPoint(0, 0) << false; + QTest::newRow("too much drag and too much distance to second tap") << QPoint(50, 0) << QPoint(50, 0) << false; +} + +void tst_qquickwindow::synthMouseDoubleClickFromTouch() +{ + QFETCH(QPoint, movement); + QFETCH(QPoint, distanceBetweenPresses); + QFETCH(bool, expectedSynthesizedDoubleClickEvent); + + QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); + QScopedPointer<MouseRecordingWindow> window(new MouseRecordingWindow); + QScopedPointer<MouseRecordingItem> item(new MouseRecordingItem(false, nullptr)); + item->setParentItem(window->contentItem()); + window->resize(250, 250); + window->setPosition(100, 100); + window->setTitle(QTest::currentTestFunction()); + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QTest::qWait(100); + + QPoint p1 = item->mapToScene(item->clipRect().center()).toPoint(); + QTest::touchEvent(window.data(), touchDevice).press(0, p1, window.data()); + QTest::touchEvent(window.data(), touchDevice).move(0, p1 + movement, window.data()); + QTest::touchEvent(window.data(), touchDevice).release(0, p1 + movement, window.data()); + + QPoint p2 = p1 + distanceBetweenPresses; + QTest::touchEvent(window.data(), touchDevice).press(1, p2, window.data()); + QTest::touchEvent(window.data(), touchDevice).move(1, p2 + movement, window.data()); + QTest::touchEvent(window.data(), touchDevice).release(1, p2 + movement, window.data()); + + const int eventCount = item->m_mouseEvents.count(); + QVERIFY(eventCount >= 2); + + const int nDoubleClicks = std::count_if(item->m_mouseEvents.constBegin(), item->m_mouseEvents.constEnd(), [](const QMouseEvent &ev) { return (ev.type() == QEvent::MouseButtonDblClick); } ); + const bool foundDoubleClick = (nDoubleClicks == 1); + QCOMPARE(foundDoubleClick, expectedSynthesizedDoubleClickEvent); + +} + void tst_qquickwindow::clearWindow() { QQuickWindow *window = new QQuickWindow; |