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::MouseButtonPress:
|
||||||
case QEvent::MouseButtonRelease:
|
case QEvent::MouseButtonRelease:
|
||||||
case QEvent::MouseMove: {
|
case QEvent::MouseMove: {
|
||||||
QMouseEvent *me = static_cast<QMouseEvent *>(e);
|
return static_cast<QMouseEvent *>(e->clone());
|
||||||
QMouseEvent *cme = new QMouseEvent(me->type(), QPoint(0, 0), me->scenePosition(), me->globalPosition(),
|
|
||||||
me->button(), me->buttons(), me->modifiers(), me->source());
|
|
||||||
return cme;
|
|
||||||
}
|
}
|
||||||
#if QT_CONFIG(graphicsview)
|
#if QT_CONFIG(graphicsview)
|
||||||
case QEvent::GraphicsSceneMousePress:
|
case QEvent::GraphicsSceneMousePress:
|
||||||
case QEvent::GraphicsSceneMouseRelease:
|
case QEvent::GraphicsSceneMouseRelease:
|
||||||
case QEvent::GraphicsSceneMouseMove: {
|
case QEvent::GraphicsSceneMouseMove: {
|
||||||
QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(e);
|
QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(e);
|
||||||
#if 1
|
|
||||||
QEvent::Type met = me->type() == QEvent::GraphicsSceneMousePress ? QEvent::MouseButtonPress :
|
QEvent::Type met = me->type() == QEvent::GraphicsSceneMousePress ? QEvent::MouseButtonPress :
|
||||||
(me->type() == QEvent::GraphicsSceneMouseRelease ? QEvent::MouseButtonRelease : QEvent::MouseMove);
|
(me->type() == QEvent::GraphicsSceneMouseRelease ? QEvent::MouseButtonRelease : QEvent::MouseMove);
|
||||||
QMouseEvent *cme = new QMouseEvent(met, QPoint(0, 0), QPoint(0, 0), me->screenPos(),
|
QMouseEvent *cme = new QMouseEvent(met, QPoint(0, 0), QPoint(0, 0), me->screenPos(),
|
||||||
me->button(), me->buttons(), me->modifiers(), me->source());
|
me->button(), me->buttons(), me->modifiers(), me->source());
|
||||||
|
cme->setTimestamp(me->timestamp());
|
||||||
return cme;
|
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)
|
#endif // QT_CONFIG(graphicsview)
|
||||||
default:
|
default:
|
||||||
@ -190,22 +166,6 @@ public:
|
|||||||
mouseTarget = nullptr;
|
mouseTarget = nullptr;
|
||||||
} else if (mouseTarget) {
|
} else if (mouseTarget) {
|
||||||
// we did send a press, so we need to fake a release now
|
// 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);
|
QPoint farFarAway(-QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX);
|
||||||
|
|
||||||
qFGDebug() << "QFG: sending a fake mouse release at far-far-away to " << mouseTarget;
|
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(),
|
mouseTarget->topLevelWidget()->mapFromGlobal(me->globalPosition()), me->globalPosition(),
|
||||||
me->button(), me->buttons(), me->modifiers(),
|
me->button(), me->buttons(), me->modifiers(),
|
||||||
me->source(), me->pointingDevice());
|
me->source(), me->pointingDevice());
|
||||||
|
copy.setTimestamp(me->timestamp());
|
||||||
qt_sendSpontaneousEvent(mouseTarget, ©);
|
qt_sendSpontaneousEvent(mouseTarget, ©);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +103,7 @@ private slots:
|
|||||||
void scroll();
|
void scroll();
|
||||||
void overshoot();
|
void overshoot();
|
||||||
void multipleWindows();
|
void multipleWindows();
|
||||||
|
void mouseEventTimestamp();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPointingDevice *m_touchScreen = QTest::createTouchDevice();
|
QPointingDevice *m_touchScreen = QTest::createTouchDevice();
|
||||||
@ -516,6 +517,67 @@ void tst_QScroller::multipleWindows()
|
|||||||
#endif
|
#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)
|
QTEST_MAIN(tst_QScroller)
|
||||||
|
|
||||||
#include "tst_qscroller.moc"
|
#include "tst_qscroller.moc"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user