Fix MouseButtonDblClick synthesis from touch double-tap
When QGuiApplicationPrivate::processTouchEvent() sees that the touch event was not handled, and calls processMouseEvent(), the latter uses the QEventPoint with pointId 0 regardless of the original touchpoint ID. Now it updates the persistent QEventPoint from the original touchpoint so that a double-click event will not be ruled out because of the timestamp delta or position delta (movement since press) being too large. Fixes: QTBUG-125993 Pick-to: 6.7 6.5 Change-Id: I8e9b007818107ac2329454e0ccfb2ac9e506b617 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit 2a0b907f11b9c0ad46322ba06482861423246d93) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
c410163173
commit
b1481a1663
@ -2271,7 +2271,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
|
||||
QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp,
|
||||
e->localPos, e->globalPos, e->buttons ^ button, e->modifiers, Qt::NoButton,
|
||||
e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove,
|
||||
e->source, e->nonClientArea);
|
||||
e->source, e->nonClientArea, device, e->eventPointId);
|
||||
if (e->synthetic())
|
||||
moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
|
||||
processMouseEvent(&moveEvent); // mouse move excluding state change
|
||||
@ -2291,6 +2291,9 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
|
||||
bool doubleClick = false;
|
||||
auto persistentEPD = devPriv->pointById(0);
|
||||
|
||||
if (e->synthetic(); auto *originalDeviceEPD = devPriv->queryPointById(e->eventPointId))
|
||||
QMutableEventPoint::update(originalDeviceEPD->eventPoint, persistentEPD->eventPoint);
|
||||
|
||||
if (mouseMove) {
|
||||
QGuiApplicationPrivate::lastCursorPosition = globalPoint;
|
||||
const auto doubleClickDistance = (e->device && e->device->type() == QInputDevice::DeviceType::Mouse ?
|
||||
@ -3207,7 +3210,8 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
|
||||
}
|
||||
// All touch events that are not accepted by the application will be translated to
|
||||
// left mouse button events instead (see AA_SynthesizeMouseForUnhandledTouchEvents docs).
|
||||
// TODO why go through QPA? Why not just send a QMouseEvent right from here?
|
||||
// Sending a QPA event (rather than simply sending a QMouseEvent) takes care of
|
||||
// side-effects such as double-click synthesis.
|
||||
QWindowSystemInterfacePrivate::MouseEvent fake(window, e->timestamp,
|
||||
window->mapFromGlobal(touchPoint->globalPosition().toPoint()),
|
||||
touchPoint->globalPosition(),
|
||||
@ -3217,7 +3221,8 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
|
||||
mouseEventType,
|
||||
Qt::MouseEventSynthesizedByQt,
|
||||
false,
|
||||
device);
|
||||
device,
|
||||
touchPoint->id());
|
||||
fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
|
||||
processMouseEvent(&fake);
|
||||
}
|
||||
|
@ -224,9 +224,11 @@ public:
|
||||
Qt::MouseButtons state, Qt::KeyboardModifiers mods,
|
||||
Qt::MouseButton b, QEvent::Type type,
|
||||
Qt::MouseEventSource src = Qt::MouseEventNotSynthesized, bool frame = false,
|
||||
const QPointingDevice *device = QPointingDevice::primaryPointingDevice())
|
||||
const QPointingDevice *device = QPointingDevice::primaryPointingDevice(),
|
||||
int evPtId = -1)
|
||||
: PointerEvent(w, time, Mouse, mods, device), localPos(local), globalPos(global),
|
||||
buttons(state), source(src), nonClientArea(frame), button(b), buttonType(type) { }
|
||||
buttons(state), source(src), nonClientArea(frame), button(b), buttonType(type),
|
||||
eventPointId(evPtId) { }
|
||||
|
||||
QPointF localPos;
|
||||
QPointF globalPos;
|
||||
@ -235,6 +237,7 @@ public:
|
||||
bool nonClientArea;
|
||||
Qt::MouseButton button;
|
||||
QEvent::Type buttonType;
|
||||
int eventPointId; // from the original device if synth-mouse, otherwise -1
|
||||
};
|
||||
|
||||
class WheelEvent : public PointerEvent {
|
||||
|
@ -3872,6 +3872,7 @@ void tst_QGraphicsProxyWidget::touchEventPropagation()
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonDblClick:
|
||||
mousePressReceiver = qobject_cast<QWidget*>(receiver);
|
||||
break;
|
||||
default:
|
||||
|
@ -432,6 +432,7 @@ private slots:
|
||||
void touchUpdateOnNewTouch();
|
||||
void touchCancel();
|
||||
void touchEventsForGesturePendingWidgets();
|
||||
void synthMouseDoubleClick();
|
||||
|
||||
void styleSheetPropagation();
|
||||
|
||||
@ -12257,7 +12258,24 @@ protected:
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::MouseButtonRelease:
|
||||
++m_mouseEventCount;
|
||||
m_lastMouseEventPos = static_cast<QMouseEvent *>(e)->position();
|
||||
{
|
||||
QMouseEvent *me = static_cast<QMouseEvent *>(e);
|
||||
m_lastMouseEventPos = me->position();
|
||||
m_lastMouseTimestamp = me->timestamp();
|
||||
}
|
||||
if (m_acceptMouse)
|
||||
e->accept();
|
||||
else
|
||||
e->ignore();
|
||||
return true;
|
||||
|
||||
case QEvent::MouseButtonDblClick:
|
||||
++m_mouseEventCount;
|
||||
{
|
||||
QMouseEvent *me = static_cast<QMouseEvent *>(e);
|
||||
m_lastMouseEventPos = me->position();
|
||||
m_doubleClickTimestamp = me->timestamp();
|
||||
}
|
||||
if (m_acceptMouse)
|
||||
e->accept();
|
||||
else
|
||||
@ -12283,6 +12301,8 @@ public:
|
||||
int m_mouseEventCount = 0;
|
||||
bool m_acceptMouse = true;
|
||||
QPointF m_lastMouseEventPos;
|
||||
quint64 m_lastMouseTimestamp = 0;
|
||||
quint64 m_doubleClickTimestamp = 0;
|
||||
};
|
||||
|
||||
void tst_QWidget::touchEventSynthesizedMouseEvent()
|
||||
@ -12524,6 +12544,50 @@ void tst_QWidget::touchEventsForGesturePendingWidgets()
|
||||
QVERIFY(parent.m_gestureEventCount > 0);
|
||||
}
|
||||
|
||||
void tst_QWidget::synthMouseDoubleClick()
|
||||
{
|
||||
TouchMouseWidget widget;
|
||||
widget.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
|
||||
widget.show();
|
||||
QWindow* window = widget.windowHandle();
|
||||
QVERIFY(QTest::qWaitForWindowExposed(window));
|
||||
|
||||
// tap once; move slightly from press to release
|
||||
QPoint p(20, 20);
|
||||
int expectedMouseEventCount = 0;
|
||||
QTest::touchEvent(window, m_touchScreen).press(1, p, window);
|
||||
QCOMPARE(widget.m_touchBeginCount, 0);
|
||||
QCOMPARE(widget.m_mouseEventCount, ++expectedMouseEventCount);
|
||||
QCOMPARE(widget.m_lastMouseEventPos.toPoint(), p);
|
||||
quint64 mouseTimestamp = widget.m_lastMouseTimestamp;
|
||||
p += {1, 0};
|
||||
QTest::touchEvent(window, m_touchScreen).move(1, p, window);
|
||||
QCOMPARE(widget.m_mouseEventCount, ++expectedMouseEventCount);
|
||||
QCOMPARE(widget.m_lastMouseEventPos.toPoint(), p);
|
||||
QCOMPARE_GT(widget.m_lastMouseTimestamp, mouseTimestamp);
|
||||
mouseTimestamp = widget.m_lastMouseTimestamp;
|
||||
QTest::touchEvent(window, m_touchScreen).release(1, p, window);
|
||||
QCOMPARE(widget.m_mouseEventCount, ++expectedMouseEventCount);
|
||||
QCOMPARE(widget.m_lastMouseEventPos.toPoint(), p);
|
||||
QCOMPARE_GT(widget.m_lastMouseTimestamp, mouseTimestamp);
|
||||
mouseTimestamp = widget.m_lastMouseTimestamp;
|
||||
|
||||
// tap again nearby: a double-click event should be synthesized
|
||||
p += {0, 1};
|
||||
QTest::touchEvent(window, m_touchScreen).press(2, p, window);
|
||||
QCOMPARE(widget.m_touchBeginCount, 0);
|
||||
QCOMPARE(widget.m_mouseEventCount, ++expectedMouseEventCount);
|
||||
QCOMPARE(widget.m_lastMouseEventPos.toPoint(), p);
|
||||
QCOMPARE_GT(widget.m_doubleClickTimestamp, mouseTimestamp);
|
||||
mouseTimestamp = widget.m_doubleClickTimestamp;
|
||||
|
||||
QTest::touchEvent(window, m_touchScreen).release(2, p, window);
|
||||
QCOMPARE(widget.m_mouseEventCount, ++expectedMouseEventCount);
|
||||
QCOMPARE(widget.m_lastMouseEventPos.toPoint(), p);
|
||||
QCOMPARE_GT(widget.m_lastMouseTimestamp, mouseTimestamp);
|
||||
mouseTimestamp = widget.m_lastMouseTimestamp;
|
||||
}
|
||||
|
||||
void tst_QWidget::styleSheetPropagation()
|
||||
{
|
||||
QTableView tw;
|
||||
|
Loading…
x
Reference in New Issue
Block a user