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,
|
QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp,
|
||||||
e->localPos, e->globalPos, e->buttons ^ button, e->modifiers, Qt::NoButton,
|
e->localPos, e->globalPos, e->buttons ^ button, e->modifiers, Qt::NoButton,
|
||||||
e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove,
|
e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove,
|
||||||
e->source, e->nonClientArea);
|
e->source, e->nonClientArea, device, e->eventPointId);
|
||||||
if (e->synthetic())
|
if (e->synthetic())
|
||||||
moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
|
moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
|
||||||
processMouseEvent(&moveEvent); // mouse move excluding state change
|
processMouseEvent(&moveEvent); // mouse move excluding state change
|
||||||
@ -2291,6 +2291,9 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
|
|||||||
bool doubleClick = false;
|
bool doubleClick = false;
|
||||||
auto persistentEPD = devPriv->pointById(0);
|
auto persistentEPD = devPriv->pointById(0);
|
||||||
|
|
||||||
|
if (e->synthetic(); auto *originalDeviceEPD = devPriv->queryPointById(e->eventPointId))
|
||||||
|
QMutableEventPoint::update(originalDeviceEPD->eventPoint, persistentEPD->eventPoint);
|
||||||
|
|
||||||
if (mouseMove) {
|
if (mouseMove) {
|
||||||
QGuiApplicationPrivate::lastCursorPosition = globalPoint;
|
QGuiApplicationPrivate::lastCursorPosition = globalPoint;
|
||||||
const auto doubleClickDistance = (e->device && e->device->type() == QInputDevice::DeviceType::Mouse ?
|
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
|
// All touch events that are not accepted by the application will be translated to
|
||||||
// left mouse button events instead (see AA_SynthesizeMouseForUnhandledTouchEvents docs).
|
// 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,
|
QWindowSystemInterfacePrivate::MouseEvent fake(window, e->timestamp,
|
||||||
window->mapFromGlobal(touchPoint->globalPosition().toPoint()),
|
window->mapFromGlobal(touchPoint->globalPosition().toPoint()),
|
||||||
touchPoint->globalPosition(),
|
touchPoint->globalPosition(),
|
||||||
@ -3217,7 +3221,8 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
|
|||||||
mouseEventType,
|
mouseEventType,
|
||||||
Qt::MouseEventSynthesizedByQt,
|
Qt::MouseEventSynthesizedByQt,
|
||||||
false,
|
false,
|
||||||
device);
|
device,
|
||||||
|
touchPoint->id());
|
||||||
fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
|
fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
|
||||||
processMouseEvent(&fake);
|
processMouseEvent(&fake);
|
||||||
}
|
}
|
||||||
|
@ -224,9 +224,11 @@ public:
|
|||||||
Qt::MouseButtons state, Qt::KeyboardModifiers mods,
|
Qt::MouseButtons state, Qt::KeyboardModifiers mods,
|
||||||
Qt::MouseButton b, QEvent::Type type,
|
Qt::MouseButton b, QEvent::Type type,
|
||||||
Qt::MouseEventSource src = Qt::MouseEventNotSynthesized, bool frame = false,
|
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),
|
: 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 localPos;
|
||||||
QPointF globalPos;
|
QPointF globalPos;
|
||||||
@ -235,6 +237,7 @@ public:
|
|||||||
bool nonClientArea;
|
bool nonClientArea;
|
||||||
Qt::MouseButton button;
|
Qt::MouseButton button;
|
||||||
QEvent::Type buttonType;
|
QEvent::Type buttonType;
|
||||||
|
int eventPointId; // from the original device if synth-mouse, otherwise -1
|
||||||
};
|
};
|
||||||
|
|
||||||
class WheelEvent : public PointerEvent {
|
class WheelEvent : public PointerEvent {
|
||||||
|
@ -3872,6 +3872,7 @@ void tst_QGraphicsProxyWidget::touchEventPropagation()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case QEvent::MouseButtonPress:
|
case QEvent::MouseButtonPress:
|
||||||
|
case QEvent::MouseButtonDblClick:
|
||||||
mousePressReceiver = qobject_cast<QWidget*>(receiver);
|
mousePressReceiver = qobject_cast<QWidget*>(receiver);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -432,6 +432,7 @@ private slots:
|
|||||||
void touchUpdateOnNewTouch();
|
void touchUpdateOnNewTouch();
|
||||||
void touchCancel();
|
void touchCancel();
|
||||||
void touchEventsForGesturePendingWidgets();
|
void touchEventsForGesturePendingWidgets();
|
||||||
|
void synthMouseDoubleClick();
|
||||||
|
|
||||||
void styleSheetPropagation();
|
void styleSheetPropagation();
|
||||||
|
|
||||||
@ -12257,7 +12258,24 @@ protected:
|
|||||||
case QEvent::MouseMove:
|
case QEvent::MouseMove:
|
||||||
case QEvent::MouseButtonRelease:
|
case QEvent::MouseButtonRelease:
|
||||||
++m_mouseEventCount;
|
++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)
|
if (m_acceptMouse)
|
||||||
e->accept();
|
e->accept();
|
||||||
else
|
else
|
||||||
@ -12283,6 +12301,8 @@ public:
|
|||||||
int m_mouseEventCount = 0;
|
int m_mouseEventCount = 0;
|
||||||
bool m_acceptMouse = true;
|
bool m_acceptMouse = true;
|
||||||
QPointF m_lastMouseEventPos;
|
QPointF m_lastMouseEventPos;
|
||||||
|
quint64 m_lastMouseTimestamp = 0;
|
||||||
|
quint64 m_doubleClickTimestamp = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void tst_QWidget::touchEventSynthesizedMouseEvent()
|
void tst_QWidget::touchEventSynthesizedMouseEvent()
|
||||||
@ -12524,6 +12544,50 @@ void tst_QWidget::touchEventsForGesturePendingWidgets()
|
|||||||
QVERIFY(parent.m_gestureEventCount > 0);
|
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()
|
void tst_QWidget::styleSheetPropagation()
|
||||||
{
|
{
|
||||||
QTableView tw;
|
QTableView tw;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user