2022-05-13 13:12:05 +00:00
|
|
|
// Copyright (C) 2020 The Qt Company Ltd.
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
#include <QtTest/QtTest>
|
2018-10-02 07:34:05 +00:00
|
|
|
#include <QDebug>
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
#include <QtGui/qstylehints.h>
|
2017-05-11 11:47:58 +00:00
|
|
|
#include <private/qdebug_p.h>
|
2020-07-23 11:56:26 +00:00
|
|
|
#include <QtGui/private/qpointingdevice_p.h>
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
#include <QtQuick/qquickview.h>
|
|
|
|
#include <QtQuick/qquickitem.h>
|
2016-07-24 21:15:31 +00:00
|
|
|
#include <QtQuick/private/qquickevents_p_p.h>
|
2012-06-26 16:00:59 +00:00
|
|
|
#include <QtQuick/private/qquickmousearea_p.h>
|
|
|
|
#include <QtQuick/private/qquickmultipointtoucharea_p.h>
|
|
|
|
#include <QtQuick/private/qquickpincharea_p.h>
|
|
|
|
#include <QtQuick/private/qquickflickable_p.h>
|
2016-07-24 21:15:31 +00:00
|
|
|
#include <QtQuick/private/qquickwindow_p.h>
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
#include <QtQml/qqmlengine.h>
|
|
|
|
#include <QtQml/qqmlproperty.h>
|
|
|
|
|
2021-08-06 10:27:35 +00:00
|
|
|
#include <QtQuickTestUtils/private/qmlutils_p.h>
|
|
|
|
#include <QtQuickTestUtils/private/viewtestutils_p.h>
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2018-10-02 07:34:05 +00:00
|
|
|
Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
|
|
|
|
|
2012-06-26 16:00:59 +00:00
|
|
|
struct Event
|
|
|
|
{
|
|
|
|
Event(QEvent::Type t, QPoint mouse, QPoint global)
|
|
|
|
:type(t), mousePos(mouse), mousePosGlobal(global)
|
|
|
|
{}
|
|
|
|
|
2020-07-23 11:56:26 +00:00
|
|
|
Event(QEvent::Type t, const QList<QEventPoint> &touch)
|
|
|
|
:type(t)
|
|
|
|
{
|
|
|
|
for (auto &tp : touch)
|
|
|
|
points << tp;
|
|
|
|
}
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
QEvent::Type type;
|
|
|
|
QPoint mousePos;
|
|
|
|
QPoint mousePosGlobal;
|
2020-07-13 11:40:04 +00:00
|
|
|
QList<QEventPoint> points;
|
2012-06-26 16:00:59 +00:00
|
|
|
};
|
|
|
|
|
2017-05-11 11:47:58 +00:00
|
|
|
#ifndef QT_NO_DEBUG_STREAM
|
|
|
|
QDebug operator<<(QDebug dbg, const struct Event &event) {
|
|
|
|
QDebugStateSaver saver(dbg);
|
|
|
|
dbg.nospace();
|
|
|
|
dbg << "Event(";
|
|
|
|
QtDebugUtils::formatQEnum(dbg, event.type);
|
|
|
|
if (event.points.isEmpty())
|
|
|
|
dbg << " @ " << event.mousePos << " global " << event.mousePosGlobal;
|
|
|
|
else
|
2022-10-05 05:29:16 +00:00
|
|
|
dbg << ", " << event.points.size() << " touchpoints: " << event.points;
|
2017-05-11 11:47:58 +00:00
|
|
|
dbg << ')';
|
|
|
|
return dbg;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-06-26 16:00:59 +00:00
|
|
|
class EventItem : public QQuickItem
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
2016-08-01 12:13:20 +00:00
|
|
|
|
|
|
|
Q_SIGNALS:
|
|
|
|
void onTouchEvent(QQuickItem *receiver);
|
|
|
|
|
2012-06-26 16:00:59 +00:00
|
|
|
public:
|
2018-02-21 09:41:54 +00:00
|
|
|
EventItem(QQuickItem *parent = nullptr)
|
2018-02-21 10:52:59 +00:00
|
|
|
: QQuickItem(parent)
|
2016-07-31 19:27:58 +00:00
|
|
|
{
|
|
|
|
setAcceptedMouseButtons(Qt::LeftButton);
|
|
|
|
}
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
void touchEvent(QTouchEvent *event) override
|
2012-06-26 16:00:59 +00:00
|
|
|
{
|
2020-07-23 11:56:26 +00:00
|
|
|
qCDebug(lcTests) << event << "accepting?" << acceptTouch;
|
|
|
|
eventList.append(Event(event->type(), event->points()));
|
|
|
|
Q_ASSERT(event->pointCount() > 0);
|
|
|
|
point0 = event->point(0).id();
|
2012-06-26 16:00:59 +00:00
|
|
|
event->setAccepted(acceptTouch);
|
2016-08-01 12:13:20 +00:00
|
|
|
emit onTouchEvent(this);
|
2012-06-26 16:00:59 +00:00
|
|
|
}
|
2020-11-17 09:11:08 +00:00
|
|
|
void mousePressEvent(QMouseEvent *event) override
|
2012-06-26 16:00:59 +00:00
|
|
|
{
|
2020-07-23 11:56:26 +00:00
|
|
|
qCDebug(lcTests) << event << "accepting?" << acceptMouse;
|
2020-06-08 07:21:58 +00:00
|
|
|
eventList.append(Event(event->type(), event->position().toPoint(), event->globalPosition().toPoint()));
|
2020-07-23 11:56:26 +00:00
|
|
|
mouseGrabber = event->exclusiveGrabber(event->points().first());
|
2012-06-26 16:00:59 +00:00
|
|
|
event->setAccepted(acceptMouse);
|
|
|
|
}
|
2020-11-17 09:11:08 +00:00
|
|
|
void mouseMoveEvent(QMouseEvent *event) override
|
2012-06-26 16:00:59 +00:00
|
|
|
{
|
2020-07-23 11:56:26 +00:00
|
|
|
qCDebug(lcTests) << event << "accepting?" << acceptMouse;
|
2020-06-08 07:21:58 +00:00
|
|
|
eventList.append(Event(event->type(), event->position().toPoint(), event->globalPosition().toPoint()));
|
2020-07-23 11:56:26 +00:00
|
|
|
mouseGrabber = event->exclusiveGrabber(event->points().first());
|
2012-06-26 16:00:59 +00:00
|
|
|
event->setAccepted(acceptMouse);
|
|
|
|
}
|
2020-11-17 09:11:08 +00:00
|
|
|
void mouseReleaseEvent(QMouseEvent *event) override
|
2012-06-26 16:00:59 +00:00
|
|
|
{
|
2020-07-23 11:56:26 +00:00
|
|
|
qCDebug(lcTests) << event << "accepting?" << acceptMouse;
|
2020-06-08 07:21:58 +00:00
|
|
|
eventList.append(Event(event->type(), event->position().toPoint(), event->globalPosition().toPoint()));
|
2020-07-23 11:56:26 +00:00
|
|
|
mouseGrabber = event->exclusiveGrabber(event->points().first());
|
2012-06-26 16:00:59 +00:00
|
|
|
event->setAccepted(acceptMouse);
|
|
|
|
}
|
2020-11-17 09:11:08 +00:00
|
|
|
void mouseDoubleClickEvent(QMouseEvent *event) override
|
2012-06-26 16:00:59 +00:00
|
|
|
{
|
2020-07-23 11:56:26 +00:00
|
|
|
qCDebug(lcTests) << event << "accepting?" << acceptMouse;
|
2020-06-08 07:21:58 +00:00
|
|
|
eventList.append(Event(event->type(), event->position().toPoint(), event->globalPosition().toPoint()));
|
2020-07-23 11:56:26 +00:00
|
|
|
mouseGrabber = event->exclusiveGrabber(event->points().first());
|
2012-06-26 16:00:59 +00:00
|
|
|
event->setAccepted(acceptMouse);
|
|
|
|
}
|
2014-10-10 19:54:39 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
void mouseUngrabEvent() override
|
2014-10-10 19:54:39 +00:00
|
|
|
{
|
2020-07-23 11:56:26 +00:00
|
|
|
qCDebug(lcTests);
|
2014-10-10 19:54:39 +00:00
|
|
|
eventList.append(Event(QEvent::UngrabMouse, QPoint(0,0), QPoint(0,0)));
|
2020-07-23 11:56:26 +00:00
|
|
|
mouseGrabber = nullptr;
|
2014-10-10 19:54:39 +00:00
|
|
|
}
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
void touchUngrabEvent() override
|
When stealing a touchpoint as synth. mouse, ungrab touch
If you use MultiPointTouchArea to make a button component, or if you
do something similar by subclassing QQuickItem and handling touch events,
and you place such a component inside a Flickable, when the user presses
on the button and then drags far enough that the Flickable steals the grab,
the MPTA or custom item did not receive the touchUngrabEvent() callback.
Now it does, so now the button will go back to released state as a result
of having the grab stolen.
The situation here is special in that it's the only place where a touch
event is transformed to be treated as mouse in the future, usually it's
either treated as touch or mouse from the start.
When this happens, it's not enough to call setMouseGrabber because that
doesn't send touch cancel to the previous grabber. Instead we need to
explicitly call touchUngrabEvent to notify the touch handling item.
The explicit setting of the grabber which was there previously is not
needed, since grabMouse will update the grab based on touchMouseId.
tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the
pressed state of the touchpoint when the grab is stolen, but it was
changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be
restored, and we can also un-blacklist inFlickable, which was deemed
unstable in 6d163779711d4601931ae0f82910794fb2498136
[ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now
properly receive touchUngrabEvent() when the touch grab is stolen by
a filtering parent Item, such as a Flickable.
Task-number: QTBUG-57910
Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2017-01-05 15:16:43 +00:00
|
|
|
{
|
2020-07-23 11:56:26 +00:00
|
|
|
qCDebug(lcTests);
|
When stealing a touchpoint as synth. mouse, ungrab touch
If you use MultiPointTouchArea to make a button component, or if you
do something similar by subclassing QQuickItem and handling touch events,
and you place such a component inside a Flickable, when the user presses
on the button and then drags far enough that the Flickable steals the grab,
the MPTA or custom item did not receive the touchUngrabEvent() callback.
Now it does, so now the button will go back to released state as a result
of having the grab stolen.
The situation here is special in that it's the only place where a touch
event is transformed to be treated as mouse in the future, usually it's
either treated as touch or mouse from the start.
When this happens, it's not enough to call setMouseGrabber because that
doesn't send touch cancel to the previous grabber. Instead we need to
explicitly call touchUngrabEvent to notify the touch handling item.
The explicit setting of the grabber which was there previously is not
needed, since grabMouse will update the grab based on touchMouseId.
tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the
pressed state of the touchpoint when the grab is stolen, but it was
changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be
restored, and we can also un-blacklist inFlickable, which was deemed
unstable in 6d163779711d4601931ae0f82910794fb2498136
[ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now
properly receive touchUngrabEvent() when the touch grab is stolen by
a filtering parent Item, such as a Flickable.
Task-number: QTBUG-57910
Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2017-01-05 15:16:43 +00:00
|
|
|
++touchUngrabCount;
|
|
|
|
}
|
|
|
|
|
2021-10-26 13:43:31 +00:00
|
|
|
void dumpEventList()
|
|
|
|
{
|
|
|
|
for (const auto &event : eventList)
|
|
|
|
qDebug() << event;
|
|
|
|
}
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
bool event(QEvent *event) override {
|
2012-06-26 16:00:59 +00:00
|
|
|
return QQuickItem::event(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<Event> eventList;
|
2020-07-23 11:56:26 +00:00
|
|
|
QObject *mouseGrabber = nullptr;
|
2018-02-21 10:52:59 +00:00
|
|
|
int touchUngrabCount = 0;
|
|
|
|
bool acceptMouse = false;
|
|
|
|
bool acceptTouch = false;
|
|
|
|
bool filterTouch = false; // when used as event filter
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
bool eventFilter(QObject *, QEvent *event) override
|
2012-06-26 16:00:59 +00:00
|
|
|
{
|
|
|
|
if (event->type() == QEvent::TouchBegin ||
|
|
|
|
event->type() == QEvent::TouchUpdate ||
|
|
|
|
event->type() == QEvent::TouchCancel ||
|
|
|
|
event->type() == QEvent::TouchEnd) {
|
2020-07-23 11:56:26 +00:00
|
|
|
qCDebug(lcTests) << event;
|
2012-06-26 16:00:59 +00:00
|
|
|
QTouchEvent *touch = static_cast<QTouchEvent*>(event);
|
2020-07-23 11:56:26 +00:00
|
|
|
eventList.append(Event(event->type(), touch->points()));
|
|
|
|
Q_ASSERT(touch->pointCount() > 0);
|
|
|
|
point0 = touch->point(0).id();
|
2012-06-26 16:00:59 +00:00
|
|
|
if (filterTouch)
|
|
|
|
event->accept();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2018-02-21 10:52:59 +00:00
|
|
|
int point0 = -1;
|
2012-06-26 16:00:59 +00:00
|
|
|
};
|
|
|
|
|
2020-07-23 11:56:26 +00:00
|
|
|
class GrabMonitor : public QObject
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
QObject *exclusiveGrabber = nullptr;
|
2022-10-21 08:36:14 +00:00
|
|
|
int transitionCount = 0;
|
2020-07-23 11:56:26 +00:00
|
|
|
bool fromMouseEvent = false;
|
|
|
|
bool canceled = false;
|
|
|
|
|
2022-11-11 07:56:31 +00:00
|
|
|
void reset()
|
|
|
|
{
|
|
|
|
exclusiveGrabber = nullptr;
|
|
|
|
transitionCount = 0;
|
|
|
|
fromMouseEvent = false;
|
|
|
|
canceled = false;
|
|
|
|
}
|
|
|
|
|
2020-07-23 11:56:26 +00:00
|
|
|
void onGrabChanged(QObject *grabber, QPointingDevice::GrabTransition transition, const QPointerEvent *event, const QEventPoint &point)
|
|
|
|
{
|
|
|
|
qCDebug(lcTests) << grabber << transition << event << point << point.device();
|
2022-10-21 08:36:14 +00:00
|
|
|
++transitionCount;
|
2020-07-23 11:56:26 +00:00
|
|
|
switch (transition) {
|
|
|
|
case QPointingDevice::GrabTransition::GrabExclusive:
|
|
|
|
exclusiveGrabber = grabber;
|
2020-07-14 18:09:57 +00:00
|
|
|
fromMouseEvent = event && QQuickDeliveryAgentPrivate::isMouseEvent(event);
|
2020-07-23 11:56:26 +00:00
|
|
|
canceled = false;
|
|
|
|
break;
|
|
|
|
case QPointingDevice::GrabTransition::UngrabExclusive:
|
|
|
|
exclusiveGrabber = nullptr;
|
|
|
|
canceled = false;
|
|
|
|
break;
|
|
|
|
case QPointingDevice::GrabTransition::CancelGrabExclusive:
|
|
|
|
exclusiveGrabber = nullptr;
|
|
|
|
canceled = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// ignore the passive grabs since this test doesn't involve pointer handlers
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-06-26 16:00:59 +00:00
|
|
|
class tst_TouchMouse : public QQmlDataTest
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
tst_TouchMouse()
|
2021-08-06 10:27:35 +00:00
|
|
|
: QQmlDataTest(QT_QMLTEST_DATADIR)
|
2012-06-26 16:00:59 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
private slots:
|
2020-11-17 09:11:08 +00:00
|
|
|
void initTestCase() override;
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2018-01-31 11:54:40 +00:00
|
|
|
void simpleTouchEvent_data();
|
2012-06-26 16:00:59 +00:00
|
|
|
void simpleTouchEvent();
|
2013-03-07 11:08:48 +00:00
|
|
|
void testEventFilter();
|
2012-06-26 16:00:59 +00:00
|
|
|
void mouse();
|
|
|
|
void touchOverMouse();
|
|
|
|
void mouseOverTouch();
|
|
|
|
|
|
|
|
void buttonOnFlickable();
|
When stealing a touchpoint as synth. mouse, ungrab touch
If you use MultiPointTouchArea to make a button component, or if you
do something similar by subclassing QQuickItem and handling touch events,
and you place such a component inside a Flickable, when the user presses
on the button and then drags far enough that the Flickable steals the grab,
the MPTA or custom item did not receive the touchUngrabEvent() callback.
Now it does, so now the button will go back to released state as a result
of having the grab stolen.
The situation here is special in that it's the only place where a touch
event is transformed to be treated as mouse in the future, usually it's
either treated as touch or mouse from the start.
When this happens, it's not enough to call setMouseGrabber because that
doesn't send touch cancel to the previous grabber. Instead we need to
explicitly call touchUngrabEvent to notify the touch handling item.
The explicit setting of the grabber which was there previously is not
needed, since grabMouse will update the grab based on touchMouseId.
tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the
pressed state of the touchpoint when the grab is stolen, but it was
changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be
restored, and we can also un-blacklist inFlickable, which was deemed
unstable in 6d163779711d4601931ae0f82910794fb2498136
[ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now
properly receive touchUngrabEvent() when the touch grab is stolen by
a filtering parent Item, such as a Flickable.
Task-number: QTBUG-57910
Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2017-01-05 15:16:43 +00:00
|
|
|
void touchButtonOnFlickable();
|
2016-10-03 15:04:00 +00:00
|
|
|
void buttonOnDelayedPressFlickable_data();
|
2013-11-13 11:41:19 +00:00
|
|
|
void buttonOnDelayedPressFlickable();
|
2012-06-26 16:00:59 +00:00
|
|
|
void buttonOnTouch();
|
|
|
|
|
|
|
|
void pinchOnFlickable();
|
|
|
|
void flickableOnPinch();
|
|
|
|
void mouseOnFlickableOnPinch();
|
|
|
|
|
2012-12-19 17:29:49 +00:00
|
|
|
void tapOnDismissiveTopMouseAreaClicksBottomOne();
|
|
|
|
|
2014-10-10 19:54:39 +00:00
|
|
|
void touchGrabCausesMouseUngrab();
|
2016-08-01 12:13:20 +00:00
|
|
|
void touchPointDeliveryOrder();
|
2014-10-10 19:54:39 +00:00
|
|
|
|
2015-11-30 15:39:15 +00:00
|
|
|
void hoverEnabled();
|
2017-01-13 09:02:23 +00:00
|
|
|
void implicitUngrab();
|
2021-10-26 13:43:31 +00:00
|
|
|
void touchCancelWillCancelMousePress();
|
2015-11-30 15:39:15 +00:00
|
|
|
|
2022-04-29 19:49:57 +00:00
|
|
|
void oneTouchInsideAndOneOutside();
|
|
|
|
|
2022-10-21 08:36:14 +00:00
|
|
|
void strayTouchDoesntAutograb();
|
|
|
|
|
2013-11-13 11:41:19 +00:00
|
|
|
protected:
|
2020-11-17 09:11:08 +00:00
|
|
|
bool eventFilter(QObject *, QEvent *event) override
|
2013-11-13 11:41:19 +00:00
|
|
|
{
|
2020-09-30 17:35:26 +00:00
|
|
|
if (event->isPointerEvent()) {
|
|
|
|
qCDebug(lcTests) << "window filtering" << event;
|
|
|
|
QPointerEvent *pe = static_cast<QPointerEvent*>(event);
|
|
|
|
filteredEventList.append(Event(pe->type(),
|
|
|
|
pe->points().first().position().toPoint(),
|
|
|
|
pe->points().first().globalPosition().toPoint()));
|
2013-11-13 11:41:19 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-06-26 16:00:59 +00:00
|
|
|
private:
|
|
|
|
QQuickView *createView();
|
2020-03-26 15:50:40 +00:00
|
|
|
QPointingDevice *device = QTest::createTouchDevice();
|
2013-11-13 11:41:19 +00:00
|
|
|
QList<Event> filteredEventList;
|
2020-07-23 11:56:26 +00:00
|
|
|
GrabMonitor grabMonitor;
|
2012-06-26 16:00:59 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
QQuickView *tst_TouchMouse::createView()
|
|
|
|
{
|
2018-02-21 09:41:54 +00:00
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
2012-07-11 07:32:16 +00:00
|
|
|
return window;
|
2012-06-26 16:00:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_TouchMouse::initTestCase()
|
|
|
|
{
|
|
|
|
QQmlDataTest::initTestCase();
|
|
|
|
qmlRegisterType<EventItem>("Qt.test", 1, 0, "EventItem");
|
2020-07-23 11:56:26 +00:00
|
|
|
connect(device, &QPointingDevice::grabChanged, &grabMonitor, &GrabMonitor::onGrabChanged);
|
2012-06-26 16:00:59 +00:00
|
|
|
}
|
|
|
|
|
2018-01-31 11:54:40 +00:00
|
|
|
void tst_TouchMouse::simpleTouchEvent_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<bool>("synthMouse"); // AA_SynthesizeMouseForUnhandledTouchEvents
|
|
|
|
QTest::newRow("no synth") << false;
|
|
|
|
QTest::newRow("synth") << true;
|
|
|
|
}
|
|
|
|
|
2012-06-26 16:00:59 +00:00
|
|
|
void tst_TouchMouse::simpleTouchEvent()
|
|
|
|
{
|
2018-01-31 11:54:40 +00:00
|
|
|
QFETCH(bool, synthMouse);
|
|
|
|
qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, synthMouse);
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("singleitem.qml")));
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem1 = window.rootObject()->findChild<EventItem*>("eventItem1");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(eventItem1);
|
2020-07-23 11:56:26 +00:00
|
|
|
auto devPriv = QPointingDevicePrivate::get(device);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
// Do not accept touch or mouse
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
eventItem1->setAcceptTouchEvents(false);
|
2012-06-26 16:00:59 +00:00
|
|
|
QPoint p1;
|
|
|
|
p1 = QPoint(20, 20);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
// Get a synth-mouse event if allowed
|
|
|
|
QCOMPARE(eventItem1->eventList.size(), synthMouse ? 1 : 0);
|
|
|
|
if (synthMouse)
|
|
|
|
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
|
2012-06-26 16:00:59 +00:00
|
|
|
p1 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2016-07-31 19:27:58 +00:00
|
|
|
// Not accepted, no updates
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), synthMouse ? 1 : 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), synthMouse ? 1 : 0);
|
2012-06-26 16:00:59 +00:00
|
|
|
eventItem1->eventList.clear();
|
|
|
|
|
|
|
|
// Accept touch
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
eventItem1->setAcceptTouchEvents(true);
|
2012-06-26 16:00:59 +00:00
|
|
|
eventItem1->acceptTouch = true;
|
|
|
|
p1 = QPoint(20, 20);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 1);
|
|
|
|
p1 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 2);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 3);
|
|
|
|
eventItem1->eventList.clear();
|
|
|
|
|
|
|
|
// wait to avoid getting a double click event
|
|
|
|
QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
|
|
|
|
|
|
|
|
// Accept mouse
|
|
|
|
eventItem1->acceptTouch = false;
|
|
|
|
eventItem1->acceptMouse = true;
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
eventItem1->setAcceptTouchEvents(false);
|
2012-06-26 16:00:59 +00:00
|
|
|
eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
|
|
|
|
p1 = QPoint(20, 20);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), synthMouse ? 1 : 0);
|
2018-01-31 11:54:40 +00:00
|
|
|
if (synthMouse)
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
|
2020-07-23 11:56:26 +00:00
|
|
|
QCOMPARE(devPriv->firstPointExclusiveGrabber(), synthMouse ? eventItem1 : nullptr);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
QPoint localPos = eventItem1->mapFromScene(p1).toPoint();
|
2020-11-17 09:11:08 +00:00
|
|
|
QPoint globalPos = window.mapToGlobal(p1);
|
2018-01-31 11:54:40 +00:00
|
|
|
if (synthMouse) {
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.at(0).mousePos, localPos);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(0).mousePosGlobal, globalPos);
|
2018-01-31 11:54:40 +00:00
|
|
|
}
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
p1 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 0);
|
|
|
|
if (synthMouse)
|
|
|
|
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseMove);
|
2018-01-31 11:54:40 +00:00
|
|
|
// else, if there was no synth-mouse and we didn't accept the touch,
|
|
|
|
// TouchUpdate was not sent to eventItem1 either.
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), synthMouse ? 4 : 0);
|
2018-01-31 11:54:40 +00:00
|
|
|
if (synthMouse) {
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonRelease);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(3).type, QEvent::UngrabMouse);
|
2018-01-31 11:54:40 +00:00
|
|
|
}
|
|
|
|
// else, if there was no synth-mouse and we didn't accept the touch,
|
|
|
|
// TouchEnd was not sent to eventItem1 either.
|
2012-06-26 16:00:59 +00:00
|
|
|
eventItem1->eventList.clear();
|
|
|
|
|
|
|
|
// wait to avoid getting a double click event
|
|
|
|
QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
|
|
|
|
|
|
|
|
// Accept mouse buttons but not the event
|
|
|
|
eventItem1->acceptTouch = false;
|
|
|
|
eventItem1->acceptMouse = false;
|
|
|
|
eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
|
|
|
|
p1 = QPoint(20, 20);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), synthMouse ? 1 : 0);
|
2018-01-31 11:54:40 +00:00
|
|
|
if (synthMouse)
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
|
2012-06-26 16:00:59 +00:00
|
|
|
p1 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), synthMouse ? 1 : 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), synthMouse ? 1 : 0);
|
2012-06-26 16:00:59 +00:00
|
|
|
eventItem1->eventList.clear();
|
|
|
|
|
|
|
|
// wait to avoid getting a double click event
|
|
|
|
QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
|
|
|
|
|
|
|
|
// Accept touch and mouse
|
|
|
|
eventItem1->acceptTouch = true;
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
eventItem1->setAcceptTouchEvents(true);
|
2012-06-26 16:00:59 +00:00
|
|
|
eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
|
|
|
|
p1 = QPoint(20, 20);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 1);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
|
|
|
|
p1 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 2);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchUpdate);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 3);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchEnd);
|
|
|
|
eventItem1->eventList.clear();
|
|
|
|
}
|
|
|
|
|
2013-03-07 11:08:48 +00:00
|
|
|
void tst_TouchMouse::testEventFilter()
|
2012-06-26 16:00:59 +00:00
|
|
|
{
|
|
|
|
// // install event filter on item and see that it can grab events
|
2017-01-11 15:40:28 +00:00
|
|
|
// QScopedPointer<QQuickView> window(createView());
|
2020-11-17 09:11:08 +00:00
|
|
|
// window.setSource(testFileUrl("singleitem.qml"));
|
|
|
|
// window.show();
|
2021-08-06 10:27:35 +00:00
|
|
|
// QQuickVisualTestUtils::centerOnScreen(&window);
|
2020-11-17 09:11:08 +00:00
|
|
|
// QVERIFY(QTest::qWaitForWindowActive(&window));
|
2012-07-11 07:32:16 +00:00
|
|
|
// QVERIFY(window->rootObject() != 0);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
// EventItem *eventItem1 = window.rootObject()->findChild<EventItem*>("eventItem1");
|
2012-06-26 16:00:59 +00:00
|
|
|
// QVERIFY(eventItem1);
|
|
|
|
// eventItem1->acceptTouch = true;
|
|
|
|
|
|
|
|
// EventItem *filter = new EventItem;
|
|
|
|
// filter->filterTouch = true;
|
|
|
|
// eventItem1->installEventFilter(filter);
|
|
|
|
|
|
|
|
// QPoint p1 = QPoint(20, 20);
|
2020-11-17 09:11:08 +00:00
|
|
|
// QTest::touchEvent(&window, device).press(0, p1, &window);
|
2012-06-26 16:00:59 +00:00
|
|
|
// // QEXPECT_FAIL("", "We do not implement event filters correctly", Abort);
|
|
|
|
// QCOMPARE(eventItem1->eventList.size(), 0);
|
|
|
|
// QCOMPARE(filter->eventList.size(), 1);
|
2020-11-17 09:11:08 +00:00
|
|
|
// QTest::touchEvent(&window, device).release(0, p1, &window);
|
2012-06-26 16:00:59 +00:00
|
|
|
// QCOMPARE(eventItem1->eventList.size(), 0);
|
|
|
|
// QCOMPARE(filter->eventList.size(), 2);
|
|
|
|
|
|
|
|
// delete filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_TouchMouse::mouse()
|
|
|
|
{
|
|
|
|
// eventItem1
|
|
|
|
// - eventItem2
|
|
|
|
|
|
|
|
QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("twoitems.qml")));
|
|
|
|
|
|
|
|
EventItem *eventItem1 = window.rootObject()->findChild<EventItem*>("eventItem1");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(eventItem1);
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem2 = window.rootObject()->findChild<EventItem*>("eventItem2");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(eventItem2);
|
|
|
|
|
|
|
|
// bottom item likes mouse, top likes touch
|
|
|
|
eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
eventItem1->setAcceptTouchEvents(false);
|
2012-06-26 16:00:59 +00:00
|
|
|
eventItem1->acceptMouse = true;
|
|
|
|
// item 2 doesn't accept anything, thus it sees a touch pass by
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
eventItem2->setAcceptTouchEvents(false);
|
2012-06-26 16:00:59 +00:00
|
|
|
QPoint p1 = QPoint(30, 30);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 1);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
|
2012-06-26 16:00:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_TouchMouse::touchOverMouse()
|
|
|
|
{
|
|
|
|
// eventItem1
|
|
|
|
// - eventItem2
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("twoitems.qml")));
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem1 = window.rootObject()->findChild<EventItem*>("eventItem1");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(eventItem1);
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem2 = window.rootObject()->findChild<EventItem*>("eventItem2");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(eventItem2);
|
|
|
|
|
|
|
|
// bottom item likes mouse, top likes touch
|
|
|
|
eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
eventItem1->acceptMouse = true;
|
|
|
|
eventItem2->acceptTouch = false; // let it fall through
|
|
|
|
eventItem2->setAcceptTouchEvents(true);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
QCOMPARE(eventItem1->eventList.size(), 0);
|
|
|
|
QPoint p1 = QPoint(20, 20);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
qCDebug(lcTests) << "expected delivered events: press(mouse)" << eventItem1->eventList;
|
|
|
|
QCOMPARE(eventItem1->eventList.size(), 1);
|
|
|
|
qCDebug(lcTests) << "expected delivered events: press(touch)" << eventItem2->eventList;
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(eventItem2->eventList.size(), 1);
|
|
|
|
QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin);
|
|
|
|
p1 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
qCDebug(lcTests) << "expected delivered events: press(mouse) move(mouse)" << eventItem1->eventList;
|
|
|
|
QCOMPARE(eventItem1->eventList.size(), 2);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseMove);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
qCDebug(lcTests) << "expected delivered events: press(mouse) move(mouse) release(mouse) ungrab(mouse)" << eventItem1->eventList;
|
|
|
|
QCOMPARE(eventItem1->eventList.size(), 4);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonRelease);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(3).type, QEvent::UngrabMouse);
|
2012-06-26 16:00:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_TouchMouse::mouseOverTouch()
|
|
|
|
{
|
|
|
|
// eventItem1
|
|
|
|
// - eventItem2
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("twoitems.qml")));
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem1 = window.rootObject()->findChild<EventItem*>("eventItem1");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(eventItem1);
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem2 = window.rootObject()->findChild<EventItem*>("eventItem2");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(eventItem2);
|
|
|
|
|
|
|
|
// bottom item likes mouse, top likes touch
|
|
|
|
eventItem1->acceptTouch = true;
|
|
|
|
eventItem2->setAcceptedMouseButtons(Qt::LeftButton);
|
|
|
|
eventItem2->acceptMouse = true;
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
eventItem2->setAcceptTouchEvents(false);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
QPoint p1 = QPoint(20, 20);
|
|
|
|
QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 0);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem2->eventList.size(), 1);
|
|
|
|
QCOMPARE(eventItem2->eventList.at(0).type, QEvent::MouseButtonPress);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
p1 += QPoint(10, 0);
|
|
|
|
QTest::touchEvent(&window, device).move(0, p1, &window);
|
|
|
|
QCOMPARE(eventItem2->eventList.size(), 1);
|
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
|
|
|
qCDebug(lcTests) << "expected delivered events: press(mouse) move(mouse) release(mouse) ungrab(mouse)" << eventItem2->eventList;
|
|
|
|
QCOMPARE(eventItem2->eventList.size(), 4);
|
|
|
|
eventItem2->eventList.clear();
|
2012-06-26 16:00:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_TouchMouse::buttonOnFlickable()
|
|
|
|
{
|
|
|
|
// flickable - height 500 / 1000
|
|
|
|
// - eventItem1 y: 100, height 100
|
|
|
|
// - eventItem2 y: 300, height 100
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("buttononflickable.qml")));
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickFlickable *flickable = window.rootObject()->findChild<QQuickFlickable*>("flickable");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(flickable);
|
|
|
|
|
|
|
|
// should a mouse area button be clickable on top of flickable? yes :)
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem1 = window.rootObject()->findChild<EventItem*>("eventItem1");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(eventItem1);
|
|
|
|
eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
|
|
|
|
eventItem1->acceptMouse = true;
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
eventItem1->setAcceptTouchEvents(false);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
// should a touch button be touchable on top of flickable? yes :)
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem2 = window.rootObject()->findChild<EventItem*>("eventItem2");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(eventItem2);
|
|
|
|
QCOMPARE(eventItem2->eventList.size(), 0);
|
|
|
|
eventItem2->acceptTouch = true;
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
eventItem2->setAcceptTouchEvents(true);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
// wait to avoid getting a double click event
|
|
|
|
QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
|
|
|
|
|
|
|
|
// check that buttons are clickable
|
|
|
|
// mouse button
|
|
|
|
QCOMPARE(eventItem1->eventList.size(), 0);
|
|
|
|
QPoint p1 = QPoint(20, 130);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QTRY_COMPARE(eventItem1->eventList.size(), 1);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 3);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonRelease);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(2).type, QEvent::UngrabMouse);
|
2012-06-26 16:00:59 +00:00
|
|
|
eventItem1->eventList.clear();
|
|
|
|
|
|
|
|
// touch button
|
|
|
|
p1 = QPoint(10, 310);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(eventItem2->eventList.size(), 1);
|
|
|
|
QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(eventItem2->eventList.size(), 2);
|
|
|
|
QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchEnd);
|
|
|
|
QCOMPARE(eventItem1->eventList.size(), 0);
|
|
|
|
eventItem2->eventList.clear();
|
|
|
|
|
|
|
|
// wait to avoid getting a double click event
|
|
|
|
QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
|
|
|
|
|
|
|
|
// click above button, no events please
|
|
|
|
p1 = QPoint(10, 90);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 0);
|
|
|
|
eventItem1->eventList.clear();
|
|
|
|
|
|
|
|
// wait to avoid getting a double click event
|
|
|
|
QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
|
|
|
|
|
|
|
|
// check that flickable moves - mouse button
|
|
|
|
QCOMPARE(eventItem1->eventList.size(), 0);
|
|
|
|
p1 = QPoint(10, 110);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 1);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(&window);
|
2020-07-14 18:09:57 +00:00
|
|
|
QVERIFY(windowPriv->deliveryAgentPrivate()->touchMouseId != -1);
|
2020-07-23 11:56:26 +00:00
|
|
|
auto devPriv = QPointingDevicePrivate::get(device);
|
|
|
|
QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, eventItem1);
|
|
|
|
QCOMPARE(grabMonitor.exclusiveGrabber, eventItem1);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
When stealing a touchpoint as synth. mouse, ungrab touch
If you use MultiPointTouchArea to make a button component, or if you
do something similar by subclassing QQuickItem and handling touch events,
and you place such a component inside a Flickable, when the user presses
on the button and then drags far enough that the Flickable steals the grab,
the MPTA or custom item did not receive the touchUngrabEvent() callback.
Now it does, so now the button will go back to released state as a result
of having the grab stolen.
The situation here is special in that it's the only place where a touch
event is transformed to be treated as mouse in the future, usually it's
either treated as touch or mouse from the start.
When this happens, it's not enough to call setMouseGrabber because that
doesn't send touch cancel to the previous grabber. Instead we need to
explicitly call touchUngrabEvent to notify the touch handling item.
The explicit setting of the grabber which was there previously is not
needed, since grabMouse will update the grab based on touchMouseId.
tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the
pressed state of the touchpoint when the grab is stolen, but it was
changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be
restored, and we can also un-blacklist inFlickable, which was deemed
unstable in 6d163779711d4601931ae0f82910794fb2498136
[ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now
properly receive touchUngrabEvent() when the touch grab is stolen by
a filtering parent Item, such as a Flickable.
Task-number: QTBUG-57910
Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2017-01-05 15:16:43 +00:00
|
|
|
int dragDelta = -qApp->styleHints()->startDragDistance();
|
2012-06-26 16:00:59 +00:00
|
|
|
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
// Start dragging; eventually, Flickable steals the grab
|
|
|
|
int i = 0;
|
|
|
|
for (; i < 10 && !flickable->isMovingVertically(); ++i) {
|
|
|
|
p1 += QPoint(0, dragDelta);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
}
|
|
|
|
QVERIFY(flickable->isMovingVertically());
|
|
|
|
qCDebug(lcTests) << "flickable started moving after" << i << "moves, when we got to" << p1;
|
|
|
|
QCOMPARE(eventItem1->eventList.size(), 4);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseMove);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(3).type, QEvent::UngrabMouse);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-07-23 11:56:26 +00:00
|
|
|
QCOMPARE(grabMonitor.exclusiveGrabber, flickable);
|
2020-07-14 18:09:57 +00:00
|
|
|
QVERIFY(windowPriv->deliveryAgentPrivate()->touchMouseId != -1);
|
2020-07-23 11:56:26 +00:00
|
|
|
QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, flickable);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
When stealing a touchpoint as synth. mouse, ungrab touch
If you use MultiPointTouchArea to make a button component, or if you
do something similar by subclassing QQuickItem and handling touch events,
and you place such a component inside a Flickable, when the user presses
on the button and then drags far enough that the Flickable steals the grab,
the MPTA or custom item did not receive the touchUngrabEvent() callback.
Now it does, so now the button will go back to released state as a result
of having the grab stolen.
The situation here is special in that it's the only place where a touch
event is transformed to be treated as mouse in the future, usually it's
either treated as touch or mouse from the start.
When this happens, it's not enough to call setMouseGrabber because that
doesn't send touch cancel to the previous grabber. Instead we need to
explicitly call touchUngrabEvent to notify the touch handling item.
The explicit setting of the grabber which was there previously is not
needed, since grabMouse will update the grab based on touchMouseId.
tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the
pressed state of the touchpoint when the grab is stolen, but it was
changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be
restored, and we can also un-blacklist inFlickable, which was deemed
unstable in 6d163779711d4601931ae0f82910794fb2498136
[ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now
properly receive touchUngrabEvent() when the touch grab is stolen by
a filtering parent Item, such as a Flickable.
Task-number: QTBUG-57910
Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2017-01-05 15:16:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_TouchMouse::touchButtonOnFlickable()
|
|
|
|
{
|
|
|
|
// flickable - height 500 / 1000
|
|
|
|
// - eventItem1 y: 100, height 100
|
|
|
|
// - eventItem2 y: 300, height 100
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("buttononflickable.qml")));
|
When stealing a touchpoint as synth. mouse, ungrab touch
If you use MultiPointTouchArea to make a button component, or if you
do something similar by subclassing QQuickItem and handling touch events,
and you place such a component inside a Flickable, when the user presses
on the button and then drags far enough that the Flickable steals the grab,
the MPTA or custom item did not receive the touchUngrabEvent() callback.
Now it does, so now the button will go back to released state as a result
of having the grab stolen.
The situation here is special in that it's the only place where a touch
event is transformed to be treated as mouse in the future, usually it's
either treated as touch or mouse from the start.
When this happens, it's not enough to call setMouseGrabber because that
doesn't send touch cancel to the previous grabber. Instead we need to
explicitly call touchUngrabEvent to notify the touch handling item.
The explicit setting of the grabber which was there previously is not
needed, since grabMouse will update the grab based on touchMouseId.
tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the
pressed state of the touchpoint when the grab is stolen, but it was
changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be
restored, and we can also un-blacklist inFlickable, which was deemed
unstable in 6d163779711d4601931ae0f82910794fb2498136
[ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now
properly receive touchUngrabEvent() when the touch grab is stolen by
a filtering parent Item, such as a Flickable.
Task-number: QTBUG-57910
Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2017-01-05 15:16:43 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickFlickable *flickable = window.rootObject()->findChild<QQuickFlickable*>("flickable");
|
When stealing a touchpoint as synth. mouse, ungrab touch
If you use MultiPointTouchArea to make a button component, or if you
do something similar by subclassing QQuickItem and handling touch events,
and you place such a component inside a Flickable, when the user presses
on the button and then drags far enough that the Flickable steals the grab,
the MPTA or custom item did not receive the touchUngrabEvent() callback.
Now it does, so now the button will go back to released state as a result
of having the grab stolen.
The situation here is special in that it's the only place where a touch
event is transformed to be treated as mouse in the future, usually it's
either treated as touch or mouse from the start.
When this happens, it's not enough to call setMouseGrabber because that
doesn't send touch cancel to the previous grabber. Instead we need to
explicitly call touchUngrabEvent to notify the touch handling item.
The explicit setting of the grabber which was there previously is not
needed, since grabMouse will update the grab based on touchMouseId.
tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the
pressed state of the touchpoint when the grab is stolen, but it was
changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be
restored, and we can also un-blacklist inFlickable, which was deemed
unstable in 6d163779711d4601931ae0f82910794fb2498136
[ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now
properly receive touchUngrabEvent() when the touch grab is stolen by
a filtering parent Item, such as a Flickable.
Task-number: QTBUG-57910
Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2017-01-05 15:16:43 +00:00
|
|
|
QVERIFY(flickable);
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem2 = window.rootObject()->findChild<EventItem*>("eventItem2");
|
When stealing a touchpoint as synth. mouse, ungrab touch
If you use MultiPointTouchArea to make a button component, or if you
do something similar by subclassing QQuickItem and handling touch events,
and you place such a component inside a Flickable, when the user presses
on the button and then drags far enough that the Flickable steals the grab,
the MPTA or custom item did not receive the touchUngrabEvent() callback.
Now it does, so now the button will go back to released state as a result
of having the grab stolen.
The situation here is special in that it's the only place where a touch
event is transformed to be treated as mouse in the future, usually it's
either treated as touch or mouse from the start.
When this happens, it's not enough to call setMouseGrabber because that
doesn't send touch cancel to the previous grabber. Instead we need to
explicitly call touchUngrabEvent to notify the touch handling item.
The explicit setting of the grabber which was there previously is not
needed, since grabMouse will update the grab based on touchMouseId.
tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the
pressed state of the touchpoint when the grab is stolen, but it was
changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be
restored, and we can also un-blacklist inFlickable, which was deemed
unstable in 6d163779711d4601931ae0f82910794fb2498136
[ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now
properly receive touchUngrabEvent() when the touch grab is stolen by
a filtering parent Item, such as a Flickable.
Task-number: QTBUG-57910
Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2017-01-05 15:16:43 +00:00
|
|
|
QVERIFY(eventItem2);
|
|
|
|
QCOMPARE(eventItem2->eventList.size(), 0);
|
|
|
|
eventItem2->acceptTouch = true;
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
eventItem2->setAcceptTouchEvents(true);
|
When stealing a touchpoint as synth. mouse, ungrab touch
If you use MultiPointTouchArea to make a button component, or if you
do something similar by subclassing QQuickItem and handling touch events,
and you place such a component inside a Flickable, when the user presses
on the button and then drags far enough that the Flickable steals the grab,
the MPTA or custom item did not receive the touchUngrabEvent() callback.
Now it does, so now the button will go back to released state as a result
of having the grab stolen.
The situation here is special in that it's the only place where a touch
event is transformed to be treated as mouse in the future, usually it's
either treated as touch or mouse from the start.
When this happens, it's not enough to call setMouseGrabber because that
doesn't send touch cancel to the previous grabber. Instead we need to
explicitly call touchUngrabEvent to notify the touch handling item.
The explicit setting of the grabber which was there previously is not
needed, since grabMouse will update the grab based on touchMouseId.
tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the
pressed state of the touchpoint when the grab is stolen, but it was
changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be
restored, and we can also un-blacklist inFlickable, which was deemed
unstable in 6d163779711d4601931ae0f82910794fb2498136
[ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now
properly receive touchUngrabEvent() when the touch grab is stolen by
a filtering parent Item, such as a Flickable.
Task-number: QTBUG-57910
Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2017-01-05 15:16:43 +00:00
|
|
|
|
|
|
|
// press via touch, then drag: check that flickable moves and that the button gets ungrabbed
|
|
|
|
QCOMPARE(eventItem2->eventList.size(), 0);
|
|
|
|
QPoint p1 = QPoint(10, 310);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
When stealing a touchpoint as synth. mouse, ungrab touch
If you use MultiPointTouchArea to make a button component, or if you
do something similar by subclassing QQuickItem and handling touch events,
and you place such a component inside a Flickable, when the user presses
on the button and then drags far enough that the Flickable steals the grab,
the MPTA or custom item did not receive the touchUngrabEvent() callback.
Now it does, so now the button will go back to released state as a result
of having the grab stolen.
The situation here is special in that it's the only place where a touch
event is transformed to be treated as mouse in the future, usually it's
either treated as touch or mouse from the start.
When this happens, it's not enough to call setMouseGrabber because that
doesn't send touch cancel to the previous grabber. Instead we need to
explicitly call touchUngrabEvent to notify the touch handling item.
The explicit setting of the grabber which was there previously is not
needed, since grabMouse will update the grab based on touchMouseId.
tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the
pressed state of the touchpoint when the grab is stolen, but it was
changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be
restored, and we can also un-blacklist inFlickable, which was deemed
unstable in 6d163779711d4601931ae0f82910794fb2498136
[ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now
properly receive touchUngrabEvent() when the touch grab is stolen by
a filtering parent Item, such as a Flickable.
Task-number: QTBUG-57910
Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2017-01-05 15:16:43 +00:00
|
|
|
QCOMPARE(eventItem2->eventList.size(), 1);
|
|
|
|
QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin);
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(&window);
|
2020-07-14 18:09:57 +00:00
|
|
|
QVERIFY(windowPriv->deliveryAgentPrivate()->touchMouseId == -1);
|
2020-07-23 11:56:26 +00:00
|
|
|
auto devPriv = QPointingDevicePrivate::get(device);
|
|
|
|
QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, eventItem2);
|
|
|
|
QCOMPARE(grabMonitor.exclusiveGrabber, eventItem2);
|
When stealing a touchpoint as synth. mouse, ungrab touch
If you use MultiPointTouchArea to make a button component, or if you
do something similar by subclassing QQuickItem and handling touch events,
and you place such a component inside a Flickable, when the user presses
on the button and then drags far enough that the Flickable steals the grab,
the MPTA or custom item did not receive the touchUngrabEvent() callback.
Now it does, so now the button will go back to released state as a result
of having the grab stolen.
The situation here is special in that it's the only place where a touch
event is transformed to be treated as mouse in the future, usually it's
either treated as touch or mouse from the start.
When this happens, it's not enough to call setMouseGrabber because that
doesn't send touch cancel to the previous grabber. Instead we need to
explicitly call touchUngrabEvent to notify the touch handling item.
The explicit setting of the grabber which was there previously is not
needed, since grabMouse will update the grab based on touchMouseId.
tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the
pressed state of the touchpoint when the grab is stolen, but it was
changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be
restored, and we can also un-blacklist inFlickable, which was deemed
unstable in 6d163779711d4601931ae0f82910794fb2498136
[ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now
properly receive touchUngrabEvent() when the touch grab is stolen by
a filtering parent Item, such as a Flickable.
Task-number: QTBUG-57910
Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2017-01-05 15:16:43 +00:00
|
|
|
|
|
|
|
int dragDelta = qApp->styleHints()->startDragDistance() * -0.7;
|
|
|
|
p1 += QPoint(0, dragDelta);
|
|
|
|
QPoint p2 = p1 + QPoint(0, dragDelta);
|
|
|
|
QPoint p3 = p2 + QPoint(0, dragDelta);
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
QTest::touchEvent(&window, device).move(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
QTest::touchEvent(&window, device).move(0, p2, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
QTest::touchEvent(&window, device).move(0, p3, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
When stealing a touchpoint as synth. mouse, ungrab touch
If you use MultiPointTouchArea to make a button component, or if you
do something similar by subclassing QQuickItem and handling touch events,
and you place such a component inside a Flickable, when the user presses
on the button and then drags far enough that the Flickable steals the grab,
the MPTA or custom item did not receive the touchUngrabEvent() callback.
Now it does, so now the button will go back to released state as a result
of having the grab stolen.
The situation here is special in that it's the only place where a touch
event is transformed to be treated as mouse in the future, usually it's
either treated as touch or mouse from the start.
When this happens, it's not enough to call setMouseGrabber because that
doesn't send touch cancel to the previous grabber. Instead we need to
explicitly call touchUngrabEvent to notify the touch handling item.
The explicit setting of the grabber which was there previously is not
needed, since grabMouse will update the grab based on touchMouseId.
tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the
pressed state of the touchpoint when the grab is stolen, but it was
changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be
restored, and we can also un-blacklist inFlickable, which was deemed
unstable in 6d163779711d4601931ae0f82910794fb2498136
[ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now
properly receive touchUngrabEvent() when the touch grab is stolen by
a filtering parent Item, such as a Flickable.
Task-number: QTBUG-57910
Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2017-01-05 15:16:43 +00:00
|
|
|
|
2018-03-02 12:56:03 +00:00
|
|
|
QTRY_COMPARE(eventItem2->touchUngrabCount, 1);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
qCDebug(lcTests) << "expected delivered events: press(touch) move(touch)" << eventItem2->eventList;
|
|
|
|
QCOMPARE(eventItem2->eventList.size(), 2);
|
When stealing a touchpoint as synth. mouse, ungrab touch
If you use MultiPointTouchArea to make a button component, or if you
do something similar by subclassing QQuickItem and handling touch events,
and you place such a component inside a Flickable, when the user presses
on the button and then drags far enough that the Flickable steals the grab,
the MPTA or custom item did not receive the touchUngrabEvent() callback.
Now it does, so now the button will go back to released state as a result
of having the grab stolen.
The situation here is special in that it's the only place where a touch
event is transformed to be treated as mouse in the future, usually it's
either treated as touch or mouse from the start.
When this happens, it's not enough to call setMouseGrabber because that
doesn't send touch cancel to the previous grabber. Instead we need to
explicitly call touchUngrabEvent to notify the touch handling item.
The explicit setting of the grabber which was there previously is not
needed, since grabMouse will update the grab based on touchMouseId.
tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the
pressed state of the touchpoint when the grab is stolen, but it was
changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be
restored, and we can also un-blacklist inFlickable, which was deemed
unstable in 6d163779711d4601931ae0f82910794fb2498136
[ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now
properly receive touchUngrabEvent() when the touch grab is stolen by
a filtering parent Item, such as a Flickable.
Task-number: QTBUG-57910
Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2017-01-05 15:16:43 +00:00
|
|
|
QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchUpdate);
|
2020-07-23 11:56:26 +00:00
|
|
|
QCOMPARE(grabMonitor.exclusiveGrabber, flickable);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
// both EventItem and Flickable handled the actual touch, so synth-mouse doesn't happen
|
2020-07-14 18:09:57 +00:00
|
|
|
QCOMPARE(windowPriv->deliveryAgentPrivate()->touchMouseId, -1);
|
2020-07-23 11:56:26 +00:00
|
|
|
QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, flickable);
|
When stealing a touchpoint as synth. mouse, ungrab touch
If you use MultiPointTouchArea to make a button component, or if you
do something similar by subclassing QQuickItem and handling touch events,
and you place such a component inside a Flickable, when the user presses
on the button and then drags far enough that the Flickable steals the grab,
the MPTA or custom item did not receive the touchUngrabEvent() callback.
Now it does, so now the button will go back to released state as a result
of having the grab stolen.
The situation here is special in that it's the only place where a touch
event is transformed to be treated as mouse in the future, usually it's
either treated as touch or mouse from the start.
When this happens, it's not enough to call setMouseGrabber because that
doesn't send touch cancel to the previous grabber. Instead we need to
explicitly call touchUngrabEvent to notify the touch handling item.
The explicit setting of the grabber which was there previously is not
needed, since grabMouse will update the grab based on touchMouseId.
tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the
pressed state of the touchpoint when the grab is stolen, but it was
changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be
restored, and we can also un-blacklist inFlickable, which was deemed
unstable in 6d163779711d4601931ae0f82910794fb2498136
[ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now
properly receive touchUngrabEvent() when the touch grab is stolen by
a filtering parent Item, such as a Flickable.
Task-number: QTBUG-57910
Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2017-01-05 15:16:43 +00:00
|
|
|
QVERIFY(flickable->isMovingVertically());
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p3, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
}
|
|
|
|
|
2016-10-03 15:04:00 +00:00
|
|
|
void tst_TouchMouse::buttonOnDelayedPressFlickable_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<bool>("scrollBeforeDelayIsOver");
|
2018-10-02 07:34:05 +00:00
|
|
|
QTest::addColumn<bool>("releaseBeforeDelayIsOver");
|
2016-10-03 15:04:00 +00:00
|
|
|
|
|
|
|
// the item should never see the event,
|
|
|
|
// due to the pressDelay which never delivers if we start moving
|
2018-10-02 07:34:05 +00:00
|
|
|
QTest::newRow("scroll before press delay is over") << true << false;
|
|
|
|
|
|
|
|
// after release, the item should see the press and release via event replay (QTBUG-61144)
|
|
|
|
QTest::newRow("release before press delay is over") << false << true;
|
2016-10-03 15:04:00 +00:00
|
|
|
|
|
|
|
// wait until the "button" sees the press but then
|
|
|
|
// start moving: the button gets a press and cancel event
|
2018-10-02 07:34:05 +00:00
|
|
|
QTest::newRow("scroll after press delay is over") << false << false;
|
2016-10-03 15:04:00 +00:00
|
|
|
}
|
|
|
|
|
2013-11-13 11:41:19 +00:00
|
|
|
void tst_TouchMouse::buttonOnDelayedPressFlickable()
|
|
|
|
{
|
|
|
|
// flickable - height 500 / 1000
|
|
|
|
// - eventItem1 y: 100, height 100
|
|
|
|
// - eventItem2 y: 300, height 100
|
2016-10-03 15:04:00 +00:00
|
|
|
QFETCH(bool, scrollBeforeDelayIsOver);
|
2018-10-02 07:34:05 +00:00
|
|
|
QFETCH(bool, releaseBeforeDelayIsOver);
|
2020-09-30 17:35:26 +00:00
|
|
|
const int threshold = qApp->styleHints()->startDragDistance();
|
2020-09-15 10:55:05 +00:00
|
|
|
|
2013-11-13 11:41:19 +00:00
|
|
|
qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true);
|
|
|
|
filteredEventList.clear();
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("buttononflickable.qml")));
|
2013-11-13 11:41:19 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickFlickable *flickable = window.rootObject()->findChild<QQuickFlickable*>("flickable");
|
2013-11-13 11:41:19 +00:00
|
|
|
QVERIFY(flickable);
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
window.installEventFilter(this);
|
2013-11-13 11:41:19 +00:00
|
|
|
|
2016-10-03 15:04:00 +00:00
|
|
|
// wait 600 ms before letting the child see the press event
|
|
|
|
flickable->setPressDelay(600);
|
2013-11-13 11:41:19 +00:00
|
|
|
|
|
|
|
// should a mouse area button be clickable on top of flickable? yes :)
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem1 = window.rootObject()->findChild<EventItem*>("eventItem1");
|
2013-11-13 11:41:19 +00:00
|
|
|
QVERIFY(eventItem1);
|
|
|
|
eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
|
|
|
|
eventItem1->acceptMouse = true;
|
|
|
|
|
|
|
|
// should a touch button be touchable on top of flickable? yes :)
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem2 = window.rootObject()->findChild<EventItem*>("eventItem2");
|
2013-11-13 11:41:19 +00:00
|
|
|
QVERIFY(eventItem2);
|
|
|
|
QCOMPARE(eventItem2->eventList.size(), 0);
|
|
|
|
eventItem2->acceptTouch = true;
|
|
|
|
|
|
|
|
// wait to avoid getting a double click event
|
|
|
|
QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(&window);
|
2020-07-14 18:09:57 +00:00
|
|
|
QCOMPARE(windowPriv->deliveryAgentPrivate()->touchMouseId, -1); // no grabber
|
2013-11-13 11:41:19 +00:00
|
|
|
|
2016-10-03 15:04:00 +00:00
|
|
|
// touch press
|
2013-11-13 11:41:19 +00:00
|
|
|
QPoint p1 = QPoint(10, 110);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2013-11-13 11:41:19 +00:00
|
|
|
|
2018-10-02 07:34:05 +00:00
|
|
|
if (scrollBeforeDelayIsOver || releaseBeforeDelayIsOver) {
|
|
|
|
// no events yet: press is delayed
|
2016-10-03 15:04:00 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 0);
|
|
|
|
} else {
|
|
|
|
// wait until the button sees the press
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
qCDebug(lcTests) << "expected delivered events: press(mouse)" << eventItem1->eventList;
|
|
|
|
qCDebug(lcTests) << "expected filtered events: actual TouchBegin and replayed TouchBegin" << filteredEventList;
|
|
|
|
QTRY_COMPARE(eventItem1->eventList.size(), 1);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(filteredEventList.size(), 2); // actual touch begin and replayed touch begin
|
2016-10-03 15:04:00 +00:00
|
|
|
}
|
2013-11-13 11:41:19 +00:00
|
|
|
|
2018-10-02 07:34:05 +00:00
|
|
|
if (!releaseBeforeDelayIsOver) {
|
|
|
|
// move the touchpoint: try to flick
|
2020-09-30 17:35:26 +00:00
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
|
|
p1 += QPoint(0, -threshold);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2020-09-30 17:35:26 +00:00
|
|
|
}
|
2018-10-02 07:34:05 +00:00
|
|
|
QTRY_VERIFY(flickable->isMovingVertically());
|
|
|
|
|
|
|
|
if (scrollBeforeDelayIsOver) {
|
|
|
|
QCOMPARE(eventItem1->eventList.size(), 0);
|
2020-09-30 17:35:26 +00:00
|
|
|
qCDebug(lcTests) << "expected filtered events: 1 TouchBegin and 3 TouchUpdate" << filteredEventList;
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(filteredEventList.size(), 4);
|
2018-10-02 07:34:05 +00:00
|
|
|
} else {
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
qCDebug(lcTests) << "expected delivered events: press(mouse), move(mouse), move(mouse), ungrab(mouse)" << eventItem1->eventList;
|
|
|
|
QCOMPARE(eventItem1->eventList.size(), 4);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseMove);
|
2018-10-02 07:34:05 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.last().type, QEvent::UngrabMouse);
|
2020-09-30 17:35:26 +00:00
|
|
|
qCDebug(lcTests) << "expected filtered events: 2 TouchBegin and 3 TouchUpdate" << filteredEventList;
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(filteredEventList.size(), 5);
|
2018-10-02 07:34:05 +00:00
|
|
|
}
|
2016-10-03 15:04:00 +00:00
|
|
|
|
2020-09-30 17:35:26 +00:00
|
|
|
// flickable should have the touchpoint grab: it no longer relies on synth-mouse
|
2020-07-23 11:56:26 +00:00
|
|
|
QCOMPARE(grabMonitor.exclusiveGrabber, flickable);
|
|
|
|
auto devPriv = QPointingDevicePrivate::get(device);
|
|
|
|
QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, flickable);
|
2016-10-03 15:04:00 +00:00
|
|
|
}
|
2013-11-13 11:41:19 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2013-11-13 11:41:19 +00:00
|
|
|
|
2018-10-02 07:34:05 +00:00
|
|
|
if (releaseBeforeDelayIsOver) {
|
|
|
|
// when the touchpoint was released, the child saw the delayed press and the release in sequence
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
qCDebug(lcTests) << "expected delivered events: press(mouse), release(mouse), ungrab" << eventItem1->eventList;
|
|
|
|
qCDebug(lcTests) << "expected filtered events: press(touch), release(touch), delayed press(touch), release (touch)" << filteredEventList;
|
|
|
|
QTRY_COMPARE(eventItem1->eventList.size(), 3);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonRelease);
|
2018-10-02 07:34:05 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.last().type, QEvent::UngrabMouse);
|
|
|
|
// QQuickWindow filters the delayed press and release
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(filteredEventList.size(), 4);
|
|
|
|
QCOMPARE(filteredEventList.at(filteredEventList.size() - 2).type, QEvent::TouchBegin);
|
2020-09-30 17:35:26 +00:00
|
|
|
QCOMPARE(filteredEventList.last().type, QEvent::TouchEnd);
|
2018-10-02 07:34:05 +00:00
|
|
|
} else {
|
2020-09-30 17:35:26 +00:00
|
|
|
// QQuickWindow filters the delayed press if there was one
|
2018-10-02 07:34:05 +00:00
|
|
|
if (scrollBeforeDelayIsOver) {
|
2020-09-30 17:35:26 +00:00
|
|
|
qCDebug(lcTests) << "expected filtered events: 1 TouchBegin, 3 TouchUpdate, 1 TouchEnd" << filteredEventList;
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(filteredEventList.size(), 5);
|
2018-10-02 07:34:05 +00:00
|
|
|
} else {
|
2020-09-30 17:35:26 +00:00
|
|
|
qCDebug(lcTests) << "expected filtered events: 2 TouchBegin, 3 TouchUpdate, 1 TouchEnd" << filteredEventList;
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(filteredEventList.size(), 6);
|
2020-09-30 17:35:26 +00:00
|
|
|
QCOMPARE(filteredEventList.at(0).type, QEvent::TouchBegin);
|
|
|
|
QCOMPARE(filteredEventList.last().type, QEvent::TouchEnd);
|
2018-10-02 07:34:05 +00:00
|
|
|
}
|
|
|
|
}
|
2013-11-13 11:41:19 +00:00
|
|
|
}
|
|
|
|
|
2012-06-26 16:00:59 +00:00
|
|
|
void tst_TouchMouse::buttonOnTouch()
|
|
|
|
{
|
|
|
|
// 400x800
|
|
|
|
// PinchArea - height 400
|
|
|
|
// - eventItem1 y: 100, height 100
|
|
|
|
// - eventItem2 y: 300, height 100
|
|
|
|
// MultiPointTouchArea - height 400
|
|
|
|
// - eventItem1 y: 100, height 100
|
|
|
|
// - eventItem2 y: 300, height 100
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("buttonontouch.qml")));
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickPinchArea *pinchArea = window.rootObject()->findChild<QQuickPinchArea*>("pincharea");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(pinchArea);
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickItem *button1 = window.rootObject()->findChild<QQuickItem*>("button1");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(button1);
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem1 = window.rootObject()->findChild<EventItem*>("eventItem1");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(eventItem1);
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem2 = window.rootObject()->findChild<EventItem*>("eventItem2");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(eventItem2);
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickMultiPointTouchArea *touchArea = window.rootObject()->findChild<QQuickMultiPointTouchArea*>("toucharea");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(touchArea);
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem3 = window.rootObject()->findChild<EventItem*>("eventItem3");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(eventItem3);
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *eventItem4 = window.rootObject()->findChild<EventItem*>("eventItem4");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(eventItem4);
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::QTouchEventSequence touchSeq = QTest::touchEvent(&window, device, false);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
// Test the common case of a mouse area on top of pinch
|
|
|
|
eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
eventItem1->setAcceptTouchEvents(false);
|
2012-06-26 16:00:59 +00:00
|
|
|
eventItem1->acceptMouse = true;
|
|
|
|
|
|
|
|
|
|
|
|
// wait to avoid getting a double click event
|
|
|
|
QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
|
|
|
|
|
|
|
|
// Normal touch click
|
|
|
|
QPoint p1 = QPoint(10, 110);
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.press(0, p1, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
touchSeq.release(0, p1, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 3);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonRelease);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(2).type, QEvent::UngrabMouse);
|
2012-06-26 16:00:59 +00:00
|
|
|
eventItem1->eventList.clear();
|
|
|
|
|
|
|
|
// Normal mouse click
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, p1);
|
2014-10-10 19:54:39 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 3);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
|
|
|
|
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonRelease);
|
2014-10-10 19:54:39 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.at(2).type, QEvent::UngrabMouse);
|
2012-06-26 16:00:59 +00:00
|
|
|
eventItem1->eventList.clear();
|
|
|
|
|
|
|
|
// Pinch starting on the PinchArea should work
|
|
|
|
p1 = QPoint(40, 10);
|
|
|
|
QPoint p2 = QPoint(60, 10);
|
|
|
|
|
|
|
|
// Start the events after each other
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.press(0, p1, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
touchSeq.stationary(0).press(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QCOMPARE(button1->scale(), 1);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
p1 -= QPoint(10, 0);
|
|
|
|
p2 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
p1 -= QPoint(10, 0);
|
|
|
|
p2 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
QCOMPARE(button1->scale(), 1.5);
|
|
|
|
qCDebug(lcTests) << "Button scale: " << button1->scale();
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
p1 -= QPoint(10, 0);
|
|
|
|
p2 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
QCOMPARE(button1->scale(), 2);
|
|
|
|
qCDebug(lcTests) << "Button scale: " << button1->scale();
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.release(0, p1, &window).release(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
QVERIFY(eventItem1->eventList.isEmpty());
|
|
|
|
QCOMPARE(button1->scale(), 2);
|
|
|
|
qCDebug(lcTests) << "Button scale: " << button1->scale();
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
// wait to avoid getting a double click event
|
|
|
|
QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
|
|
|
|
|
|
|
|
// Start pinching while on the button
|
|
|
|
button1->setScale(1.0);
|
|
|
|
p1 = QPoint(40, 110);
|
|
|
|
p2 = QPoint(60, 110);
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.press(0, p1, &window).press(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
QCOMPARE(button1->scale(), 1);
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.size(), 1);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
p1 -= QPoint(10, 0);
|
|
|
|
p2 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
p1 -= QPoint(10, 0);
|
|
|
|
p2 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
qCDebug(lcTests) << "Button scale: " << button1->scale();
|
|
|
|
QEXPECT_FAIL("", "No pinch: eventItem1 grabbed both touchpoints", Continue);
|
|
|
|
QCOMPARE(button1->scale(), 1.5);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
p1 -= QPoint(10, 0);
|
|
|
|
p2 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
qCDebug(lcTests) << "Button scale: " << button1->scale();
|
|
|
|
QEXPECT_FAIL("", "No pinch: eventItem1 grabbed both touchpoints", Continue);
|
|
|
|
QCOMPARE(button1->scale(), 2);
|
|
|
|
|
|
|
|
touchSeq.release(0, p1, &window).release(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
QCOMPARE(eventItem1->eventList.size(), 6);
|
|
|
|
qCDebug(lcTests) << "Button scale: " << button1->scale();
|
|
|
|
QEXPECT_FAIL("", "No pinch: eventItem1 grabbed both touchpoints", Continue);
|
|
|
|
QCOMPARE(button1->scale(), 2);
|
2012-06-26 16:00:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_TouchMouse::pinchOnFlickable()
|
|
|
|
{
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("pinchonflickable.qml")));
|
2020-10-28 08:36:33 +00:00
|
|
|
const int threshold = qApp->styleHints()->startDragDistance();
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickPinchArea *pinchArea = window.rootObject()->findChild<QQuickPinchArea*>("pincharea");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(pinchArea);
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickFlickable *flickable = window.rootObject()->findChild<QQuickFlickable*>("flickable");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(flickable);
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickItem *rect = window.rootObject()->findChild<QQuickItem*>("rect");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(rect);
|
|
|
|
|
2020-10-28 08:36:33 +00:00
|
|
|
// flick the flickable with one touchpoint
|
|
|
|
QCOMPARE(flickable->contentX(), 0);
|
2012-06-26 16:00:59 +00:00
|
|
|
QPoint p = QPoint(100, 100);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2020-10-28 08:36:33 +00:00
|
|
|
QCOMPARE(rect->position(), QPointF(200, 200));
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
|
|
p -= QPoint(threshold, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2020-10-28 08:36:33 +00:00
|
|
|
if (!flickable->isAtXBeginning()) // currently happens when i == 3
|
|
|
|
qCDebug(lcTests, "flicking after %d moves: %lf", i + 1, flickable->contentX());
|
|
|
|
}
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p, &window);
|
2020-10-28 08:36:33 +00:00
|
|
|
QTRY_COMPARE(flickable->isAtXBeginning(), false);
|
2012-06-26 16:00:59 +00:00
|
|
|
// wait until flicking is done
|
2020-10-28 08:36:33 +00:00
|
|
|
QTRY_COMPARE(flickable->isFlicking(), false);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-10-28 08:36:33 +00:00
|
|
|
// pinch with two touchpoints
|
2012-06-26 16:00:59 +00:00
|
|
|
QPoint p1 = QPoint(40, 20);
|
|
|
|
QPoint p2 = QPoint(60, 20);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(&window, device);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
pinchSequence.press(0, p1, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
// In order for the stationary point to remember its previous position,
|
|
|
|
// we have to reuse the same pinchSequence object. Otherwise if we let it
|
|
|
|
// be destroyed and then start a new sequence, point 0 will default to being
|
|
|
|
// stationary at 0, 0, and PinchArea will filter out that touchpoint because
|
|
|
|
// it is outside its bounds.
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.stationary(0).press(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2020-10-28 08:36:33 +00:00
|
|
|
QCOMPARE(rect->scale(), 1);
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
|
|
p1 -= QPoint(threshold, 0);
|
|
|
|
p2 += QPoint(threshold, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2020-10-28 08:36:33 +00:00
|
|
|
qCDebug(lcTests, "pinch scale after %d moves: %lf", i + 1, rect->scale());
|
|
|
|
}
|
2014-07-22 01:31:04 +00:00
|
|
|
QVERIFY(!flickable->isDragging());
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
pinchSequence.release(0, p1, &window).release(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2020-10-28 08:36:33 +00:00
|
|
|
QVERIFY(rect->scale() > 1); // depends on threshold
|
2012-06-26 16:00:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_TouchMouse::flickableOnPinch()
|
|
|
|
{
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("flickableonpinch.qml")));
|
|
|
|
|
|
|
|
QQuickPinchArea *pinchArea = window.rootObject()->findChild<QQuickPinchArea*>("pincharea");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(pinchArea);
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickFlickable *flickable = window.rootObject()->findChild<QQuickFlickable*>("flickable");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(flickable);
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickItem *rect = window.rootObject()->findChild<QQuickItem*>("rect");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(rect);
|
|
|
|
|
|
|
|
// flickable - single touch point
|
2015-07-24 13:32:22 +00:00
|
|
|
QCOMPARE(flickable->contentX(), 0.0);
|
2012-06-26 16:00:59 +00:00
|
|
|
QPoint p = QPoint(100, 100);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-10-22 14:59:25 +00:00
|
|
|
QCOMPARE(rect->position(), QPointF(200.0, 200.0));
|
2012-06-26 16:00:59 +00:00
|
|
|
p -= QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
p -= QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
QTest::qWait(1000);
|
|
|
|
|
|
|
|
p -= QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
QTest::touchEvent(&window, device).release(0, p, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
QTest::qWait(1000);
|
|
|
|
|
|
|
|
//QVERIFY(flickable->isMovingHorizontally());
|
2020-11-17 09:11:08 +00:00
|
|
|
qCDebug(lcTests) << "Pos: " << rect->position();
|
2012-06-26 16:00:59 +00:00
|
|
|
// wait until flicking is done
|
|
|
|
QTRY_VERIFY(!flickable->isFlicking());
|
|
|
|
|
|
|
|
// pinch
|
|
|
|
QPoint p1 = QPoint(40, 20);
|
|
|
|
QPoint p2 = QPoint(60, 20);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(&window, device);
|
|
|
|
pinchSequence.press(0, p1, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
// In order for the stationary point to remember its previous position,
|
|
|
|
// we have to reuse the same pinchSequence object. Otherwise if we let it
|
|
|
|
// be destroyed and then start a new sequence, point 0 will default to being
|
|
|
|
// stationary at 0, 0, and PinchArea will filter out that touchpoint because
|
|
|
|
// it is outside its bounds.
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.stationary(0).press(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
p1 -= QPoint(10,10);
|
|
|
|
p2 += QPoint(10,10);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(rect->scale(), 1.0);
|
|
|
|
p1 -= QPoint(10, 0);
|
|
|
|
p2 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
p1 -= QPoint(10, 0);
|
|
|
|
p2 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
p1 -= QPoint(10, 0);
|
|
|
|
p2 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
pinchSequence.release(0, p1, &window).release(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(rect->scale() > 1.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_TouchMouse::mouseOnFlickableOnPinch()
|
|
|
|
{
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("mouseonflickableonpinch.qml")));
|
2017-01-11 15:40:28 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickPinchArea *pinchArea = window.rootObject()->findChild<QQuickPinchArea*>("pincharea");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(pinchArea);
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickFlickable *flickable = window.rootObject()->findChild<QQuickFlickable*>("flickable");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(flickable);
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickItem *rect = window.rootObject()->findChild<QQuickItem*>("rect");
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(rect);
|
|
|
|
|
|
|
|
// flickable - single touch point
|
2015-07-24 13:32:22 +00:00
|
|
|
QCOMPARE(flickable->contentX(), 0.0);
|
2012-06-26 16:00:59 +00:00
|
|
|
QPoint p = QPoint(100, 100);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-10-22 14:59:25 +00:00
|
|
|
QCOMPARE(rect->position(), QPointF(200.0, 200.0));
|
2012-06-26 16:00:59 +00:00
|
|
|
p -= QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
p -= QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
p -= QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).move(0, p, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
QTest::touchEvent(&window, device).release(0, p, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QVERIFY(flickable->isMovingHorizontally());
|
2013-08-12 03:28:17 +00:00
|
|
|
|
|
|
|
// Wait for flick to end
|
|
|
|
QTRY_VERIFY(!flickable->isMoving());
|
2020-11-17 09:11:08 +00:00
|
|
|
qCDebug(lcTests) << "Pos: " << rect->position();
|
2012-06-26 16:00:59 +00:00
|
|
|
|
|
|
|
// pinch
|
|
|
|
QPoint p1 = QPoint(40, 20);
|
|
|
|
QPoint p2 = QPoint(60, 20);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(&window, device);
|
|
|
|
pinchSequence.press(0, p1, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
// In order for the stationary point to remember its previous position,
|
|
|
|
// we have to reuse the same pinchSequence object. Otherwise if we let it
|
|
|
|
// be destroyed and then start a new sequence, point 0 will default to being
|
|
|
|
// stationary at 0, 0, and PinchArea will filter out that touchpoint because
|
|
|
|
// it is outside its bounds.
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.stationary(0).press(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
p1 -= QPoint(10,10);
|
|
|
|
p2 += QPoint(10,10);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(rect->scale(), 1.0);
|
|
|
|
p1 -= QPoint(10, 0);
|
|
|
|
p2 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
p1 -= QPoint(10, 0);
|
|
|
|
p2 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
p1 -= QPoint(10, 0);
|
|
|
|
p2 += QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
pinchSequence.release(0, p1, &window).release(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(rect->scale() > 1.0);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
// first pinch is done
|
2012-06-26 16:00:59 +00:00
|
|
|
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
// Press one point and drag left: Flickable flicks
|
2012-06-26 16:00:59 +00:00
|
|
|
rect->setScale(1.0);
|
|
|
|
flickable->setContentX(0.0);
|
|
|
|
p = QPoint(100, 100);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.press(0, p, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-10-22 14:59:25 +00:00
|
|
|
QCOMPARE(rect->position(), QPointF(200.0, 200.0));
|
2012-06-26 16:00:59 +00:00
|
|
|
p -= QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
p -= QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-11-08 16:43:46 +00:00
|
|
|
QGuiApplication::processEvents();
|
2012-06-26 16:00:59 +00:00
|
|
|
p -= QPoint(10, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
// Add a second finger: PinchArea should grab one touchpoint and steal the other, even though flicking is ongoing
|
2012-06-26 16:00:59 +00:00
|
|
|
p1 = QPoint(40, 100);
|
|
|
|
p2 = QPoint(60, 100);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.stationary(0).press(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
QCOMPARE(rect->scale(), 1.0);
|
|
|
|
|
|
|
|
p1 -= QPoint(5, 0);
|
|
|
|
p2 += QPoint(5, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
p1 -= QPoint(5, 0);
|
|
|
|
p2 += QPoint(5, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
p1 -= QPoint(5, 0);
|
|
|
|
p2 += QPoint(5, 0);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.move(0, p1, &window).move(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
pinchSequence.release(0, p1, &window).release(1, p2, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
qCDebug(lcTests) << "pinch scaled to" << rect->scale();
|
2012-06-26 16:00:59 +00:00
|
|
|
QVERIFY(rect->scale() > 1.0);
|
2020-11-17 09:11:08 +00:00
|
|
|
pinchSequence.release(0, p, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-06-26 16:00:59 +00:00
|
|
|
}
|
|
|
|
|
2012-12-19 17:29:49 +00:00
|
|
|
/*
|
|
|
|
Regression test for the following use case:
|
|
|
|
You have two mouse areas, on on top of the other.
|
|
|
|
1 - You tap the top one.
|
|
|
|
2 - That top mouse area receives a mouse press event but doesn't accept it
|
|
|
|
Expected outcome:
|
|
|
|
3 - the bottom mouse area gets clicked (besides press and release mouse events)
|
|
|
|
Bogus outcome:
|
|
|
|
3 - the bottom mouse area gets double clicked.
|
|
|
|
*/
|
|
|
|
void tst_TouchMouse::tapOnDismissiveTopMouseAreaClicksBottomOne()
|
|
|
|
{
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("twoMouseAreas.qml")));
|
2012-12-19 17:29:49 +00:00
|
|
|
|
|
|
|
QQuickMouseArea *bottomMouseArea =
|
2020-11-17 09:11:08 +00:00
|
|
|
window.rootObject()->findChild<QQuickMouseArea*>("rear mouseArea");
|
2012-12-19 17:29:49 +00:00
|
|
|
|
|
|
|
QSignalSpy bottomClickedSpy(bottomMouseArea, SIGNAL(clicked(QQuickMouseEvent*)));
|
|
|
|
QSignalSpy bottomDoubleClickedSpy(bottomMouseArea,
|
|
|
|
SIGNAL(doubleClicked(QQuickMouseEvent*)));
|
|
|
|
|
|
|
|
// tap the front mouse area (see qml file)
|
|
|
|
QPoint p1(20, 20);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-12-19 17:29:49 +00:00
|
|
|
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(bottomClickedSpy.size(), 1);
|
|
|
|
QCOMPARE(bottomDoubleClickedSpy.size(), 0);
|
2012-12-19 17:29:49 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2012-12-19 17:29:49 +00:00
|
|
|
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(bottomClickedSpy.size(), 1);
|
|
|
|
QCOMPARE(bottomDoubleClickedSpy.size(), 1);
|
2012-12-19 17:29:49 +00:00
|
|
|
}
|
|
|
|
|
2014-10-10 19:54:39 +00:00
|
|
|
/*
|
|
|
|
If an item grabs a touch that is currently being used for mouse pointer emulation,
|
|
|
|
the current mouse grabber should lose the mouse as mouse events will no longer
|
|
|
|
be generated from that touch point.
|
|
|
|
*/
|
|
|
|
void tst_TouchMouse::touchGrabCausesMouseUngrab()
|
|
|
|
{
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("twosiblingitems.qml")));
|
|
|
|
|
|
|
|
EventItem *leftItem = window.rootObject()->findChild<EventItem*>("leftItem");
|
2014-10-10 19:54:39 +00:00
|
|
|
QVERIFY(leftItem);
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *rightItem = window.rootObject()->findChild<EventItem*>("rightItem");
|
2014-10-10 19:54:39 +00:00
|
|
|
QVERIFY(leftItem);
|
|
|
|
|
|
|
|
// Send a touch to the leftItem. But leftItem accepts only mouse events, thus
|
|
|
|
// a mouse event will be synthesized out of this touch and will get accepted by
|
|
|
|
// leftItem.
|
|
|
|
leftItem->acceptMouse = true;
|
|
|
|
leftItem->setAcceptedMouseButtons(Qt::LeftButton);
|
|
|
|
QPoint p1;
|
|
|
|
p1 = QPoint(leftItem->width() / 2, leftItem->height() / 2);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
qCDebug(lcTests) << "expected delivered events: press(mouse)" << leftItem->eventList;
|
|
|
|
QCOMPARE(leftItem->eventList.size(), 1);
|
|
|
|
QCOMPARE(leftItem->eventList.at(0).type, QEvent::MouseButtonPress);
|
2020-07-23 11:56:26 +00:00
|
|
|
QCOMPARE(grabMonitor.exclusiveGrabber, leftItem);
|
2014-10-10 19:54:39 +00:00
|
|
|
leftItem->eventList.clear();
|
|
|
|
|
|
|
|
rightItem->acceptTouch = true;
|
2020-07-23 11:56:26 +00:00
|
|
|
auto devPriv = QPointingDevicePrivate::get(device);
|
|
|
|
auto epd = devPriv->queryPointById(0);
|
|
|
|
QVERIFY(epd);
|
|
|
|
devPriv->setExclusiveGrabber(nullptr, epd->eventPoint, rightItem);
|
2014-10-10 19:54:39 +00:00
|
|
|
|
|
|
|
// leftItem should have lost the mouse as the touch point that was being used to emulate it
|
|
|
|
// has been grabbed by another item.
|
|
|
|
QCOMPARE(leftItem->eventList.size(), 1);
|
|
|
|
QCOMPARE(leftItem->eventList.at(0).type, QEvent::UngrabMouse);
|
2020-07-23 11:56:26 +00:00
|
|
|
QCOMPARE(grabMonitor.exclusiveGrabber, rightItem);
|
2014-10-10 19:54:39 +00:00
|
|
|
}
|
|
|
|
|
2016-08-01 12:13:20 +00:00
|
|
|
void tst_TouchMouse::touchPointDeliveryOrder()
|
|
|
|
{
|
|
|
|
// Touch points should be first delivered to the item under the primary finger
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("touchpointdeliveryorder.qml")));
|
2017-01-11 15:40:28 +00:00
|
|
|
|
2016-08-01 12:13:20 +00:00
|
|
|
/*
|
|
|
|
The items are positioned from left to right:
|
|
|
|
| background |
|
|
|
|
| left |
|
|
|
|
| | right |
|
|
|
|
| middle |
|
|
|
|
0 150 300 450 600
|
|
|
|
*/
|
|
|
|
QPoint pLeft = QPoint(100, 100);
|
|
|
|
QPoint pRight = QPoint(500, 100);
|
|
|
|
QPoint pLeftMiddle = QPoint(200, 100);
|
|
|
|
QPoint pRightMiddle = QPoint(350, 100);
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::QTouchEventSequence touchSeq = QTest::touchEvent(&window, device, false);
|
2016-08-01 12:13:20 +00:00
|
|
|
|
|
|
|
QVector<QQuickItem*> events;
|
2020-11-17 09:11:08 +00:00
|
|
|
EventItem *background = window.rootObject()->findChild<EventItem*>("background");
|
|
|
|
EventItem *left = window.rootObject()->findChild<EventItem*>("left");
|
|
|
|
EventItem *middle = window.rootObject()->findChild<EventItem*>("middle");
|
|
|
|
EventItem *right = window.rootObject()->findChild<EventItem*>("right");
|
2016-08-01 12:13:20 +00:00
|
|
|
QVERIFY(background);
|
|
|
|
QVERIFY(left);
|
|
|
|
QVERIFY(middle);
|
|
|
|
QVERIFY(right);
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
background->setAcceptTouchEvents(true);
|
|
|
|
left->setAcceptTouchEvents(true);
|
|
|
|
middle->setAcceptTouchEvents(true);
|
|
|
|
right->setAcceptTouchEvents(true);
|
2016-08-01 12:13:20 +00:00
|
|
|
connect(background, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); });
|
|
|
|
connect(left, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); });
|
|
|
|
connect(middle, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); });
|
|
|
|
connect(right, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); });
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.press(0, pLeft, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2016-08-01 12:13:20 +00:00
|
|
|
|
|
|
|
// Touch on left, then background
|
|
|
|
QCOMPARE(events.size(), 2);
|
|
|
|
QCOMPARE(events.at(0), left);
|
|
|
|
QCOMPARE(events.at(1), background);
|
|
|
|
events.clear();
|
|
|
|
|
|
|
|
// New press events are deliverd first, the stationary point was not accepted, thus it doesn't get delivered
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.stationary(0).press(1, pRightMiddle, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2016-08-01 12:13:20 +00:00
|
|
|
QCOMPARE(events.size(), 3);
|
|
|
|
QCOMPARE(events.at(0), middle);
|
|
|
|
QCOMPARE(events.at(1), right);
|
|
|
|
QCOMPARE(events.at(2), background);
|
|
|
|
events.clear();
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.release(0, pLeft, &window).release(1, pRightMiddle, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2016-08-01 12:13:20 +00:00
|
|
|
QCOMPARE(events.size(), 0); // no accepted events
|
|
|
|
|
|
|
|
// Two presses, the first point should come first
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.press(0, pLeft, &window).press(1, pRight, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2016-08-01 12:13:20 +00:00
|
|
|
QCOMPARE(events.size(), 3);
|
|
|
|
QCOMPARE(events.at(0), left);
|
|
|
|
QCOMPARE(events.at(1), right);
|
|
|
|
QCOMPARE(events.at(2), background);
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.release(0, pLeft, &window).release(1, pRight, &window).commit();
|
2016-08-01 12:13:20 +00:00
|
|
|
events.clear();
|
|
|
|
|
|
|
|
// Again, pressing right first
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.press(0, pRight, &window).press(1, pLeft, &window).commit();
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2016-08-01 12:13:20 +00:00
|
|
|
QCOMPARE(events.size(), 3);
|
|
|
|
QCOMPARE(events.at(0), right);
|
|
|
|
QCOMPARE(events.at(1), left);
|
|
|
|
QCOMPARE(events.at(2), background);
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.release(0, pRight, &window).release(1, pLeft, &window).commit();
|
2016-08-01 12:13:20 +00:00
|
|
|
events.clear();
|
|
|
|
|
|
|
|
// Two presses, both hitting the middle item on top, then branching left and right, then bottom
|
|
|
|
// Each target should be offered the events exactly once, middle first, left must come before right (id 0)
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.press(0, pLeftMiddle, &window).press(1, pRightMiddle, &window).commit();
|
2016-08-01 12:13:20 +00:00
|
|
|
QCOMPARE(events.size(), 4);
|
|
|
|
QCOMPARE(events.at(0), middle);
|
|
|
|
QCOMPARE(events.at(1), left);
|
|
|
|
QCOMPARE(events.at(2), right);
|
|
|
|
QCOMPARE(events.at(3), background);
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.release(0, pLeftMiddle, &window).release(1, pRightMiddle, &window).commit();
|
2016-08-01 12:13:20 +00:00
|
|
|
events.clear();
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.press(0, pRightMiddle, &window).press(1, pLeftMiddle, &window).commit();
|
|
|
|
qCDebug(lcTests) << events;
|
2016-08-01 12:13:20 +00:00
|
|
|
QCOMPARE(events.size(), 4);
|
|
|
|
QCOMPARE(events.at(0), middle);
|
|
|
|
QCOMPARE(events.at(1), right);
|
|
|
|
QCOMPARE(events.at(2), left);
|
|
|
|
QCOMPARE(events.at(3), background);
|
2020-11-17 09:11:08 +00:00
|
|
|
touchSeq.release(0, pRightMiddle, &window).release(1, pLeftMiddle, &window).commit();
|
2016-08-01 12:13:20 +00:00
|
|
|
}
|
|
|
|
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
void tst_TouchMouse::hoverEnabled() // QTBUG-40856
|
2015-11-30 15:39:15 +00:00
|
|
|
{
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("hoverMouseAreas.qml")));
|
|
|
|
QQuickItem *root = window.rootObject();
|
2015-11-30 15:39:15 +00:00
|
|
|
|
|
|
|
QQuickMouseArea *mouseArea1 = root->findChild<QQuickMouseArea*>("mouseArea1");
|
2018-02-21 09:41:54 +00:00
|
|
|
QVERIFY(mouseArea1 != nullptr);
|
2015-11-30 15:39:15 +00:00
|
|
|
|
|
|
|
QQuickMouseArea *mouseArea2 = root->findChild<QQuickMouseArea*>("mouseArea2");
|
2018-02-21 09:41:54 +00:00
|
|
|
QVERIFY(mouseArea2 != nullptr);
|
2015-11-30 15:39:15 +00:00
|
|
|
|
|
|
|
QSignalSpy enterSpy1(mouseArea1, SIGNAL(entered()));
|
|
|
|
QSignalSpy exitSpy1(mouseArea1, SIGNAL(exited()));
|
|
|
|
QSignalSpy clickSpy1(mouseArea1, SIGNAL(clicked(QQuickMouseEvent *)));
|
|
|
|
|
|
|
|
QSignalSpy enterSpy2(mouseArea2, SIGNAL(entered()));
|
|
|
|
QSignalSpy exitSpy2(mouseArea2, SIGNAL(exited()));
|
|
|
|
QSignalSpy clickSpy2(mouseArea2, SIGNAL(clicked(QQuickMouseEvent *)));
|
|
|
|
|
|
|
|
QPoint p1(150, 150);
|
|
|
|
QPoint p2(150, 250);
|
|
|
|
|
|
|
|
// ------------------------- Mouse move to mouseArea1
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::mouseMove(&window, p1);
|
2015-11-30 15:39:15 +00:00
|
|
|
|
2022-10-05 05:29:16 +00:00
|
|
|
QVERIFY(enterSpy1.size() == 1);
|
2015-11-30 15:39:15 +00:00
|
|
|
QVERIFY(mouseArea1->hovered());
|
|
|
|
QVERIFY(!mouseArea2->hovered());
|
|
|
|
|
|
|
|
// ------------------------- Touch click on mouseArea1
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
2015-11-30 15:39:15 +00:00
|
|
|
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(enterSpy1.size(), 1);
|
|
|
|
QCOMPARE(enterSpy2.size(), 0);
|
2023-01-11 09:37:21 +00:00
|
|
|
QVERIFY(mouseArea1->isPressed());
|
2015-11-30 15:39:15 +00:00
|
|
|
QVERIFY(mouseArea1->hovered());
|
|
|
|
QVERIFY(!mouseArea2->hovered());
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
2022-10-05 05:29:16 +00:00
|
|
|
QVERIFY(clickSpy1.size() == 1);
|
2015-11-30 15:39:15 +00:00
|
|
|
QVERIFY(mouseArea1->hovered());
|
|
|
|
QVERIFY(!mouseArea2->hovered());
|
|
|
|
|
|
|
|
// ------------------------- Touch click on mouseArea2
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p2, &window);
|
2015-11-30 15:39:15 +00:00
|
|
|
|
|
|
|
QVERIFY(mouseArea1->hovered());
|
|
|
|
QVERIFY(mouseArea2->hovered());
|
2023-01-11 09:37:21 +00:00
|
|
|
QVERIFY(mouseArea2->isPressed());
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(enterSpy1.size(), 1);
|
|
|
|
QCOMPARE(enterSpy2.size(), 1);
|
2015-11-30 15:39:15 +00:00
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p2, &window);
|
2015-11-30 15:39:15 +00:00
|
|
|
|
2022-10-05 05:29:16 +00:00
|
|
|
QVERIFY(clickSpy2.size() == 1);
|
2015-11-30 15:39:15 +00:00
|
|
|
QVERIFY(mouseArea1->hovered());
|
|
|
|
QVERIFY(!mouseArea2->hovered());
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(exitSpy1.size(), 0);
|
|
|
|
QCOMPARE(exitSpy2.size(), 1);
|
2015-11-30 15:39:15 +00:00
|
|
|
|
|
|
|
// ------------------------- Another touch click on mouseArea1
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1, &window);
|
2015-11-30 15:39:15 +00:00
|
|
|
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(enterSpy1.size(), 1);
|
|
|
|
QCOMPARE(enterSpy2.size(), 1);
|
2023-01-11 09:37:21 +00:00
|
|
|
QVERIFY(mouseArea1->isPressed());
|
2015-11-30 15:39:15 +00:00
|
|
|
QVERIFY(mouseArea1->hovered());
|
|
|
|
QVERIFY(!mouseArea2->hovered());
|
|
|
|
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1, &window);
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(clickSpy1.size(), 2);
|
2015-11-30 15:39:15 +00:00
|
|
|
QVERIFY(mouseArea1->hovered());
|
2023-01-11 09:37:21 +00:00
|
|
|
QVERIFY(!mouseArea1->isPressed());
|
2015-11-30 15:39:15 +00:00
|
|
|
QVERIFY(!mouseArea2->hovered());
|
|
|
|
}
|
|
|
|
|
2017-01-13 09:02:23 +00:00
|
|
|
void tst_TouchMouse::implicitUngrab()
|
|
|
|
{
|
2020-11-17 09:11:08 +00:00
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("singleitem.qml")));
|
|
|
|
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(&window);
|
|
|
|
|
|
|
|
QQuickItem *root = window.rootObject();
|
2018-02-21 09:41:54 +00:00
|
|
|
QVERIFY(root != nullptr);
|
2017-01-13 09:02:23 +00:00
|
|
|
EventItem *eventItem = root->findChild<EventItem*>("eventItem1");
|
|
|
|
eventItem->acceptMouse = true;
|
Don't synthesize mouse from touch for items that accept touch
Followup to 1457df74f4c1d770e1e820de8cd082be1bd2489e : if an item that
has acceptTouchEvents() == true merely fails to accept one touch event,
that does not mean a mouse event should be sent.
Finish changing the default to false: handling touch events is opt-in,
just like handling mouse events; most items don't. And if you opt in,
then you MUST handle touch events, because you will NOT receive mouse
events as a fall-back.
Now that Flickable handles touch, filtering multi-touch events becomes
relevant. There was a failure in tst_touchmouse::mouseOnFlickableOnPinch
when Flickable grabs a stationary touchpoint at the same time as another
touchpoint is pressed, preventing a child PinchArea from reacting.
So there's a new rule: just as we start over with event delivery when a
new point is pressed, QQuickFlickable::filterPointerEvent() should also
not immediately grab when any point is newly pressed; it can afford to
wait, because it's filtering, so it will be able to see if one point is
dragged past the drag threshold later on.
When a parent (such as Flickable) contains only mouse-handling items
(such as MouseArea), the parent should filter the touch event if it is
able (if acceptTouchEvents() returns true). Flickable is now able to.
Filtering parents that are not able to filter touch events can still
filter a synth-mouse event as before. But filtering both must be
avoided: then we would have the problem that Flickable filters a touch
move, sees that it's being dragged past the drag threshold, and sets
d->stealMouse to true to indicate that it wants to steal the _next_
event; then it filters a synth-mouse move, and that's perceived as being
the next event even though it's just a different view of the same event,
so it steals it. In tst_qquickflickable::nestedMouseAreaUsingTouch we
rely on the delay caused by waiting for the next event: the MouseArea is
trying to drag an item and the Flickable wants to flick; both of them
decide on the same event that the drag threshold is exceeded. But
MouseArea calls setKeepMouseGrab() immediately, whereas Flickable
doesn't try to steal the grab until the next event, and then it sees the
keepMouseGrab flag has been set, so it doesn't do it. If Flickable
could filter the same event twice (once as touch, once as synth-mouse),
this logic doesn't work, so it's effectively "more grabby" than
intended. So it works better to have it filter only the actual touch
event, not the synth-mouse that comes after.
When the child has pointer handlers, we need to visit them, and
therefore we should let Flickable filter a touch event on the way.
tst_FlickableInterop::touchDragFlickableBehindButton() depends on this.
[ChangeLog][QtQuick][QQuickWindow] In Qt 6, a QQuickItem subclass must
explicitly call setAcceptTouchEvents(true) to receive QTouchEvents,
and then it must handle them: we no longer fall back to sending a
QMouseEvent if the touch event is not accepted. If it has additionally
called setFiltersChildMouseEvents(true), then it will filter touch
events, not any synthetic mouse events that may be needed for some
children.
Task-number: QTBUG-87018
Fixes: QTBUG-88169
Change-Id: I8784fe097198c99c754c4ebe205bef8fe490f6f4
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2020-09-30 17:36:09 +00:00
|
|
|
eventItem->setAcceptTouchEvents(false);
|
2017-01-13 09:02:23 +00:00
|
|
|
QPoint p1(20, 20);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1);
|
2017-01-13 09:02:23 +00:00
|
|
|
|
2020-07-23 11:56:26 +00:00
|
|
|
QCOMPARE(grabMonitor.exclusiveGrabber, eventItem);
|
2017-01-13 09:02:23 +00:00
|
|
|
eventItem->eventList.clear();
|
|
|
|
eventItem->setEnabled(false);
|
|
|
|
QVERIFY(!eventItem->eventList.isEmpty());
|
|
|
|
QCOMPARE(eventItem->eventList.at(0).type, QEvent::UngrabMouse);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1); // clean up potential state
|
2020-07-14 18:09:57 +00:00
|
|
|
QCOMPARE(windowPriv->deliveryAgentPrivate()->touchMouseId, -1);
|
2017-01-13 09:02:23 +00:00
|
|
|
|
|
|
|
eventItem->setEnabled(true);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).press(0, p1);
|
2017-01-13 09:02:23 +00:00
|
|
|
eventItem->eventList.clear();
|
|
|
|
eventItem->setVisible(false);
|
|
|
|
QVERIFY(!eventItem->eventList.isEmpty());
|
|
|
|
QCOMPARE(eventItem->eventList.at(0).type, QEvent::UngrabMouse);
|
2020-11-17 09:11:08 +00:00
|
|
|
QTest::touchEvent(&window, device).release(0, p1); // clean up potential state
|
2017-01-13 09:02:23 +00:00
|
|
|
}
|
2021-10-26 13:43:31 +00:00
|
|
|
|
|
|
|
void tst_TouchMouse::touchCancelWillCancelMousePress()
|
|
|
|
{
|
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("singleitem.qml")));
|
|
|
|
QQuickItem *root = window.rootObject();
|
|
|
|
QVERIFY(root != nullptr);
|
|
|
|
|
|
|
|
EventItem *eventItem = root->findChild<EventItem*>("eventItem1");
|
|
|
|
eventItem->acceptMouse = true;
|
|
|
|
eventItem->setAcceptTouchEvents(false);
|
|
|
|
QPoint p1(20, 20);
|
|
|
|
|
|
|
|
// Begin a new touch, that gets converted to a mouse press
|
|
|
|
QTest::touchEvent(&window, device).press(0, p1);
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(eventItem->eventList.size(), 1);
|
2021-10-26 13:43:31 +00:00
|
|
|
QCOMPARE(eventItem->eventList.at(0).type, QEvent::MouseButtonPress);
|
|
|
|
|
|
|
|
// Cancel it...
|
|
|
|
QTouchEvent cancelEvent(QEvent::TouchCancel, device);
|
|
|
|
QCoreApplication::sendEvent(&window, &cancelEvent);
|
2022-10-05 05:29:16 +00:00
|
|
|
QCOMPARE(eventItem->eventList.size(), 3);
|
2021-10-26 13:43:31 +00:00
|
|
|
QCOMPARE(eventItem->eventList.at(1).type, QEvent::TouchCancel);
|
|
|
|
QCOMPARE(eventItem->eventList.at(2).type, QEvent::UngrabMouse);
|
|
|
|
|
|
|
|
// Begin a second touch. Since the last one was cancelled, this
|
|
|
|
// should end up as a new mouse press on the target item.
|
|
|
|
QTest::touchEvent(&window, device).press(0, p1);
|
2022-10-05 05:29:16 +00:00
|
|
|
QVERIFY(eventItem->eventList.size() >= 5);
|
2021-10-26 13:43:31 +00:00
|
|
|
QCOMPARE(eventItem->eventList.at(3).type, QEvent::MouseButtonPress);
|
|
|
|
|
|
|
|
QTest::touchEvent(&window, device).release(0, p1); // clean up potential state
|
|
|
|
}
|
|
|
|
|
2022-04-29 19:49:57 +00:00
|
|
|
void tst_TouchMouse::oneTouchInsideAndOneOutside() // QTBUG-102996
|
|
|
|
{
|
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("oneMouseArea.qml")));
|
|
|
|
QQuickItem *root = window.rootObject();
|
|
|
|
QVERIFY(root);
|
|
|
|
QQuickMouseArea *ma = root->findChild<QQuickMouseArea*>();
|
|
|
|
QVERIFY(ma);
|
|
|
|
|
|
|
|
// Press the MouseArea
|
|
|
|
QPoint p1 = ma->mapToScene(ma->boundingRect().center()).toPoint();
|
|
|
|
QTest::touchEvent(&window, device).press(1, p1);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2023-01-11 09:37:21 +00:00
|
|
|
QVERIFY(ma->isPressed());
|
2022-04-29 19:49:57 +00:00
|
|
|
|
|
|
|
// Tap outside the MouseArea with a second finger
|
|
|
|
QPoint p2(100, 100);
|
|
|
|
QTest::touchEvent(&window, device).stationary(1).press(2, p2);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
QTest::touchEvent(&window, device).stationary(1).release(2, p2);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2023-01-11 09:37:21 +00:00
|
|
|
QVERIFY(ma->isPressed());
|
2022-04-29 19:49:57 +00:00
|
|
|
|
|
|
|
// Press again outside the MouseArea with a second finger
|
|
|
|
QTest::touchEvent(&window, device).stationary(1).press(2, p2);
|
|
|
|
|
|
|
|
// Release the first finger: MouseArea should be released
|
|
|
|
QTest::touchEvent(&window, device).release(1, p1).stationary(2);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
2023-01-11 09:37:21 +00:00
|
|
|
QCOMPARE(ma->isPressed(), false);
|
2022-04-29 19:49:57 +00:00
|
|
|
|
|
|
|
// Release the second finger
|
|
|
|
QTest::touchEvent(&window, device).release(2, p2);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
}
|
|
|
|
|
2022-10-21 08:36:14 +00:00
|
|
|
void tst_TouchMouse::strayTouchDoesntAutograb() // QTBUG-107867
|
|
|
|
{
|
|
|
|
QQuickView window;
|
|
|
|
QVERIFY(QQuickTest::showView(window, testFileUrl("singleitem.qml")));
|
|
|
|
QQuickItem *root = window.rootObject();
|
|
|
|
QVERIFY(root);
|
|
|
|
EventItem *eventItem = root->findChild<EventItem*>();
|
|
|
|
QVERIFY(eventItem);
|
|
|
|
// This item accepts (synth-)mouse events but NOT touch
|
|
|
|
eventItem->acceptMouse = true;
|
|
|
|
QCOMPARE(eventItem->acceptTouchEvents(), false); // the default in Qt 6
|
|
|
|
QPoint p1(6, 6);
|
2022-11-11 07:56:31 +00:00
|
|
|
grabMonitor.reset();
|
2022-10-21 08:36:14 +00:00
|
|
|
|
|
|
|
// Begin a new touch, that gets converted to a mouse press
|
|
|
|
QTest::touchEvent(&window, device).press(0, p1);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
qCDebug(lcTests) << "after touch press:" << eventItem->eventList;
|
|
|
|
QCOMPARE(eventItem->eventList.size(), 1);
|
|
|
|
QCOMPARE(eventItem->eventList.at(0).type, QEvent::MouseButtonPress);
|
|
|
|
QCOMPARE(grabMonitor.exclusiveGrabber, eventItem);
|
|
|
|
|
|
|
|
// Drag
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
|
|
QTest::touchEvent(&window, device).move(0, p1 + QPoint(i * 5, i * 5), &window);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
QCOMPARE(grabMonitor.transitionCount, 1); // no new grab
|
|
|
|
QCOMPARE(eventItem->eventList.size(), i + 2);
|
|
|
|
QCOMPARE(eventItem->eventList.last().type, QEvent::MouseMove);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Press an extra point: EventItem should see nothing
|
|
|
|
QTest::touchEvent(&window, device).stationary(0).press(1, p1);
|
|
|
|
QQuickTouchUtils::flush(&window);
|
|
|
|
qCDebug(lcTests) << "after press of second touchpoint:" << eventItem->eventList;
|
|
|
|
QCOMPARE(eventItem->eventList.size(), 4);
|
|
|
|
QCOMPARE(grabMonitor.transitionCount, 1); // no new grab
|
|
|
|
|
|
|
|
QTest::touchEvent(&window, device).release(0, p1).release(1, p1);
|
|
|
|
}
|
|
|
|
|
2012-06-26 16:00:59 +00:00
|
|
|
QTEST_MAIN(tst_TouchMouse)
|
|
|
|
|
|
|
|
#include "tst_touchmouse.moc"
|
|
|
|
|