QGesture: make sure we copy timestamp value for event clones
Otherwise, double-click recognition will fail. Use QEvent::clone when possible, or set the timestamp explicitly when not. As a drive-by, remove some long-dead code in affected code lines. Fixes: QTBUG-102010 Change-Id: I882bf6e8090bf6f182b7a0a3c62aa3a4c8db2e14 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> (cherry picked from commit fb09c82a2c7c44d41a0a36d8fe6d6d22e792668a) Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
parent
33eeba416f
commit
3edc2cb543
@ -38,43 +38,19 @@ static QMouseEvent *copyMouseEvent(QEvent *e)
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseMove: {
|
||||
QMouseEvent *me = static_cast<QMouseEvent *>(e);
|
||||
QMouseEvent *cme = new QMouseEvent(me->type(), QPoint(0, 0), me->scenePosition(), me->globalPosition(),
|
||||
me->button(), me->buttons(), me->modifiers(), me->source());
|
||||
return cme;
|
||||
return static_cast<QMouseEvent *>(e->clone());
|
||||
}
|
||||
#if QT_CONFIG(graphicsview)
|
||||
case QEvent::GraphicsSceneMousePress:
|
||||
case QEvent::GraphicsSceneMouseRelease:
|
||||
case QEvent::GraphicsSceneMouseMove: {
|
||||
QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(e);
|
||||
#if 1
|
||||
QEvent::Type met = me->type() == QEvent::GraphicsSceneMousePress ? QEvent::MouseButtonPress :
|
||||
(me->type() == QEvent::GraphicsSceneMouseRelease ? QEvent::MouseButtonRelease : QEvent::MouseMove);
|
||||
QMouseEvent *cme = new QMouseEvent(met, QPoint(0, 0), QPoint(0, 0), me->screenPos(),
|
||||
me->button(), me->buttons(), me->modifiers(), me->source());
|
||||
cme->setTimestamp(me->timestamp());
|
||||
return cme;
|
||||
#else
|
||||
QGraphicsSceneMouseEvent *copy = new QGraphicsSceneMouseEvent(me->type());
|
||||
copy->setPos(me->pos());
|
||||
copy->setScenePos(me->scenePos());
|
||||
copy->setScreenPos(me->screenPos());
|
||||
for (int i = 0x1; i <= 0x10; i <<= 1) {
|
||||
Qt::MouseButton button = Qt::MouseButton(i);
|
||||
copy->setButtonDownPos(button, me->buttonDownPos(button));
|
||||
copy->setButtonDownScenePos(button, me->buttonDownScenePos(button));
|
||||
copy->setButtonDownScreenPos(button, me->buttonDownScreenPos(button));
|
||||
}
|
||||
copy->setLastPos(me->lastPos());
|
||||
copy->setLastScenePos(me->lastScenePos());
|
||||
copy->setLastScreenPos(me->lastScreenPos());
|
||||
copy->setButtons(me->buttons());
|
||||
copy->setButton(me->button());
|
||||
copy->setModifiers(me->modifiers());
|
||||
copy->setSource(me->source());
|
||||
copy->setFlags(me->flags());
|
||||
return copy;
|
||||
#endif
|
||||
}
|
||||
#endif // QT_CONFIG(graphicsview)
|
||||
default:
|
||||
@ -190,22 +166,6 @@ public:
|
||||
mouseTarget = nullptr;
|
||||
} else if (mouseTarget) {
|
||||
// we did send a press, so we need to fake a release now
|
||||
|
||||
// release all pressed mouse buttons
|
||||
/* Qt::MouseButtons mouseButtons = QGuiApplication::mouseButtons();
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
if (mouseButtons & (1 << i)) {
|
||||
Qt::MouseButton b = static_cast<Qt::MouseButton>(1 << i);
|
||||
mouseButtons &= ~b;
|
||||
QPoint farFarAway(-QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX);
|
||||
|
||||
qFGDebug() << "QFG: sending a fake mouse release at far-far-away to " << mouseTarget;
|
||||
QMouseEvent re(QEvent::MouseButtonRelease, QPoint(), farFarAway,
|
||||
b, mouseButtons, QGuiApplication::keyboardModifiers());
|
||||
sendMouseEvent(&re);
|
||||
}
|
||||
}*/
|
||||
|
||||
QPoint farFarAway(-QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX);
|
||||
|
||||
qFGDebug() << "QFG: sending a fake mouse release at far-far-away to " << mouseTarget;
|
||||
@ -265,6 +225,7 @@ protected:
|
||||
mouseTarget->topLevelWidget()->mapFromGlobal(me->globalPosition()), me->globalPosition(),
|
||||
me->button(), me->buttons(), me->modifiers(),
|
||||
me->source(), me->pointingDevice());
|
||||
copy.setTimestamp(me->timestamp());
|
||||
qt_sendSpontaneousEvent(mouseTarget, ©);
|
||||
}
|
||||
|
||||
|
@ -103,6 +103,7 @@ private slots:
|
||||
void scroll();
|
||||
void overshoot();
|
||||
void multipleWindows();
|
||||
void mouseEventTimestamp();
|
||||
|
||||
private:
|
||||
QPointingDevice *m_touchScreen = QTest::createTouchDevice();
|
||||
@ -516,6 +517,67 @@ void tst_QScroller::multipleWindows()
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
This test verifies that mouse events arrive at the target widget
|
||||
with valid timestamp, even if there is a gesture filtering (and then
|
||||
replaying a copy of) the event. QTBUG-102010
|
||||
|
||||
We cannot truly simulate the double click here, as simulated events don't
|
||||
go through the exact same event machinery as real events, so double clicks
|
||||
don't get generated by Qt here. But we can verify that the timestamps of
|
||||
the eventually delivered events are maintained.
|
||||
*/
|
||||
void tst_QScroller::mouseEventTimestamp()
|
||||
{
|
||||
#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
|
||||
QScopedPointer<tst_QScrollerWidget> sw(new tst_QScrollerWidget());
|
||||
sw->scrollArea = QRectF(0, 0, 1000, 1000);
|
||||
QScroller::grabGesture(sw.data(), QScroller::LeftMouseButtonGesture);
|
||||
sw->setGeometry(100, 100, 400, 300);
|
||||
sw->show();
|
||||
QApplication::setActiveWindow(sw.data());
|
||||
if (!QTest::qWaitForWindowExposed(sw.data()) || !QTest::qWaitForWindowActive(sw.data()))
|
||||
QSKIP("Failed to show and activate window");
|
||||
|
||||
QScroller *s1 = QScroller::scroller(sw.data());
|
||||
|
||||
struct EventFilter : QObject
|
||||
{
|
||||
QList<int> timestamps;
|
||||
protected:
|
||||
bool eventFilter(QObject *o, QEvent *e) override
|
||||
{
|
||||
if (e->isInputEvent())
|
||||
timestamps << static_cast<QInputEvent *>(e)->timestamp();
|
||||
return QObject::eventFilter(o, e);
|
||||
}
|
||||
|
||||
} eventFilter;
|
||||
sw->installEventFilter(&eventFilter);
|
||||
|
||||
const int interval = QGuiApplication::styleHints()->mouseDoubleClickInterval() / 10;
|
||||
const QPoint point = sw->geometry().center();
|
||||
// Simulate double by pressing twice within the double click interval.
|
||||
// Presses are filtered and then delayed by the scroller/gesture machinery,
|
||||
// so we first record all events, and then make sure that the relative timestamps
|
||||
// are maintained also for the replayed or synthesized events.
|
||||
QTest::mousePress(sw->windowHandle(), Qt::LeftButton, {}, point);
|
||||
QCOMPARE(s1->state(), QScroller::Pressed);
|
||||
QTest::mouseRelease(sw->windowHandle(), Qt::LeftButton, {}, point, interval);
|
||||
QCOMPARE(s1->state(), QScroller::Inactive);
|
||||
QTest::mousePress(sw->windowHandle(), Qt::LeftButton, {}, point, interval);
|
||||
QCOMPARE(s1->state(), QScroller::Pressed);
|
||||
// also filtered and delayed by the scroller
|
||||
QTest::mouseRelease(sw->windowHandle(), Qt::LeftButton, {}, point, interval);
|
||||
QCOMPARE(s1->state(), QScroller::Inactive);
|
||||
int lastTimestamp = -1;
|
||||
for (int timestamp : std::as_const(eventFilter.timestamps)) {
|
||||
QCOMPARE_GE(timestamp, lastTimestamp);
|
||||
lastTimestamp = timestamp + interval;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QScroller)
|
||||
|
||||
#include "tst_qscroller.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user