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 /src | |
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 'src')
-rw-r--r-- | src/quick/items/qquickmultipointtoucharea.cpp | 48 | ||||
-rw-r--r-- | src/quick/items/qquickmultipointtoucharea_p.h | 4 |
2 files changed, 31 insertions, 21 deletions
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp index 708cfff76b..d347472741 100644 --- a/src/quick/items/qquickmultipointtoucharea.cpp +++ b/src/quick/items/qquickmultipointtoucharea.cpp @@ -42,6 +42,7 @@ #include <private/qsgadaptationlayer_p.h> #include <private/qevent_p.h> #include <private/qquickitem_p.h> +#include <private/qquickwindow_p.h> #include <private/qguiapplication_p.h> #include <QEvent> #include <QMouseEvent> @@ -448,6 +449,7 @@ QQuickMultiPointTouchArea::QQuickMultiPointTouchArea(QQuickItem *parent) : QQuickItem(parent), _minimumTouchPoints(0), _maximumTouchPoints(INT_MAX), + _touchMouseDevice(nullptr), _stealMouse(false), _mouseEnabled(true) { @@ -586,10 +588,10 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) bool ended = false; bool moved = false; bool started = false; - bool isMouseEvent = false; clearTouchLists(); QList<QTouchEvent::TouchPoint> touchPoints; + QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window()); switch (event->type()) { case QEvent::TouchBegin: @@ -598,6 +600,9 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) touchPoints = static_cast<QTouchEvent*>(event)->touchPoints(); break; case QEvent::MouseButtonPress: + _mouseQpaTouchPoint = QTouchEvent::TouchPoint(windowPriv->touchMouseId); + _touchMouseDevice = windowPriv->touchMouseDevice->qTouchDevice(); + Q_FALLTHROUGH(); case QEvent::MouseMove: case QEvent::MouseButtonRelease: { QMouseEvent *me = static_cast<QMouseEvent*>(event); @@ -617,7 +622,6 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) _mouseQpaTouchPoint.setState(Qt::TouchPointPressed); } touchPoints << _mouseQpaTouchPoint; - isMouseEvent = true; break; } default: @@ -625,11 +629,6 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) break; } - if (!isMouseEvent && _mouseTouchPoint) { - QQuickWindow *c = window(); - if (c && c->mouseGrabberItem() == this) - touchPoints << _mouseQpaTouchPoint; - } int numTouchPoints = touchPoints.count(); //always remove released touches, and make sure we handle all releases before adds. for (const QTouchEvent::TouchPoint &p : qAsConst(touchPoints)) { @@ -756,7 +755,7 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QMouseEvent *e) dtp = new QQuickTouchPoint(false); updateTouchPoint(dtp, e); dtp->setPressed(true); - _touchPoints.insert(-1, dtp); + _touchPoints.insert(_touchMouseDevice && _mouseQpaTouchPoint.id() > 0 ? _mouseQpaTouchPoint.id() : -1, dtp); _pressedTouchPoints.append(dtp); _mouseTouchPoint = dtp; } @@ -839,8 +838,7 @@ void QQuickMultiPointTouchArea::mousePressEvent(QMouseEvent *event) setKeepMouseGrab(false); event->setAccepted(true); _mousePos = event->localPos(); - - if (event->source() != Qt::MouseEventNotSynthesized) + if (event->source() != Qt::MouseEventNotSynthesized && event->source() != Qt::MouseEventSynthesizedByQt) return; if (_touchPoints.count() >= _minimumTouchPoints - 1 && _touchPoints.count() < _maximumTouchPoints) { @@ -855,7 +853,7 @@ void QQuickMultiPointTouchArea::mouseMoveEvent(QMouseEvent *event) return; } - if (event->source() != Qt::MouseEventNotSynthesized) + if (event->source() != Qt::MouseEventNotSynthesized && event->source() != Qt::MouseEventSynthesizedByQt) return; _movedTouchPoints.clear(); @@ -870,7 +868,7 @@ void QQuickMultiPointTouchArea::mouseReleaseEvent(QMouseEvent *event) return; } - if (event->source() != Qt::MouseEventNotSynthesized) + if (event->source() != Qt::MouseEventNotSynthesized && event->source() != Qt::MouseEventSynthesizedByQt) return; if (_mouseTouchPoint) { @@ -880,18 +878,16 @@ void QQuickMultiPointTouchArea::mouseReleaseEvent(QMouseEvent *event) _mouseTouchPoint = nullptr; } - QQuickWindow *c = window(); - if (c && c->mouseGrabberItem() == this) - ungrabMouse(); setKeepMouseGrab(false); } -void QQuickMultiPointTouchArea::ungrab() +void QQuickMultiPointTouchArea::ungrab(bool normalRelease) { _stealMouse = false; setKeepMouseGrab(false); setKeepTouchGrab(false); - ungrabTouchPoints(); + if (!normalRelease) + ungrabTouchPoints(); if (_touchPoints.count()) { for (QObject *obj : qAsConst(_touchPoints)) @@ -969,13 +965,25 @@ bool QQuickMultiPointTouchArea::childMouseEventFilter(QQuickItem *receiver, QEve if (!isEnabled() || !isVisible()) return QQuickItem::childMouseEventFilter(receiver, event); switch (event->type()) { - case QEvent::MouseButtonPress: + case QEvent::MouseButtonPress: { + QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window()); + // If we already got a chance to filter the touchpoint that generated this synth-mouse-press, + // and chose not to filter it, ignore it now, too. + if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventSynthesizedByQt && + _lastFilterableTouchPointIds.contains(windowPriv->touchMouseId)) + return false; + } Q_FALLTHROUGH(); case QEvent::MouseMove: case QEvent::MouseButtonRelease: return sendMouseEvent(static_cast<QMouseEvent *>(event)); - break; case QEvent::TouchBegin: + _lastFilterableTouchPointIds.clear(); + Q_FALLTHROUGH(); case QEvent::TouchUpdate: + for (auto tp : static_cast<QTouchEvent*>(event)->touchPoints()) { + if (tp.state() == Qt::TouchPointPressed) + _lastFilterableTouchPointIds << tp.id(); + } if (!shouldFilter(event)) return false; updateTouchData(event); @@ -984,7 +992,7 @@ bool QQuickMultiPointTouchArea::childMouseEventFilter(QQuickItem *receiver, QEve if (!shouldFilter(event)) return false; updateTouchData(event); - ungrab(); + ungrab(true); } break; default: diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h index 634ea1c2e2..23f4ebff75 100644 --- a/src/quick/items/qquickmultipointtoucharea_p.h +++ b/src/quick/items/qquickmultipointtoucharea_p.h @@ -284,7 +284,7 @@ protected: #endif private: - void ungrab(); + void ungrab(bool normalRelease = false); QMap<int,QQuickTouchPoint*> _touchPrototypes; //TouchPoints defined in QML QMap<int,QObject*> _touchPoints; //All current touch points QList<QObject*> _releasedTouchPoints; @@ -292,8 +292,10 @@ private: QList<QObject*> _movedTouchPoints; int _minimumTouchPoints; int _maximumTouchPoints; + QVector<int> _lastFilterableTouchPointIds; QPointer<QQuickTouchPoint> _mouseTouchPoint; // exists when mouse button is down and _mouseEnabled is true; null otherwise QTouchEvent::TouchPoint _mouseQpaTouchPoint; // synthetic QPA touch point to hold state and position of the mouse + const QTouchDevice *_touchMouseDevice; QPointF _mousePos; bool _stealMouse; bool _mouseEnabled; |