From 31f90e99b8f04d9a228c5a0b01319b3f112c1490 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 26 Mar 2021 14:10:28 +0100 Subject: [PATCH] Add storage for (pixel) deltas and fingerCount to QNativeGestureEvent It's not clear now whether trackpad gestures on Windows will need to be so different than on macOS; however, any reasonable int value can be stored in a qreal, and in Qt Quick we like to use floating-point numbers for all "real" values and measurements. So since we need to add more storage, and quint64 m_intValue has never been used, we now replace it with a QVector2D, which should have the same size. The intended use is that PanNativeGesture will include a displacement, probably in pixels, by which the viewport or some target item should be panned or moved. The naming of deltas() is flexible enough to support any gesture with some incremental 2D valuators, though, just as value() has gesture-dependent semantics. fingerCount() will be useful for Qt Quick pointer handlers to filter out events that have the wrong number of fingers, e.g. to require that either a 3-finger pan gesture or 3 individual touchpoints are required to activate DragHandler { minimumPointCount: 3 } (assuming we implement pan gesture support in DragHandler). Fixes: QTBUG-92179 Task-number: QTBUG-92098 Change-Id: I5462aea9047beed6e99075294a62011edd8a59f5 Reviewed-by: Povilas Kanapickas Reviewed-by: Volker Hilsheimer --- src/gui/kernel/qevent.cpp | 70 ++++++++++++++++++- src/gui/kernel/qevent.h | 13 +++- src/gui/kernel/qguiapplication.cpp | 3 +- src/gui/kernel/qwindowsysteminterface.cpp | 19 +++-- src/gui/kernel/qwindowsysteminterface.h | 6 +- src/gui/kernel/qwindowsysteminterface_p.h | 7 +- .../platforms/cocoa/qnsview_gestures.mm | 2 +- 7 files changed, 106 insertions(+), 14 deletions(-) diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index adc10297541..7e5e7ac7032 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -64,6 +64,7 @@ QT_BEGIN_NAMESPACE static_assert(sizeof(QMutableTouchEvent) == sizeof(QTouchEvent)); static_assert(sizeof(QMutableSinglePointEvent) == sizeof(QSinglePointEvent)); static_assert(sizeof(QMouseEvent) == sizeof(QSinglePointEvent)); +static_assert(sizeof(QVector2D) == sizeof(quint64)); /*! \class QEnterEvent @@ -2774,6 +2775,9 @@ QTabletEvent::~QTabletEvent() */ /*! + \obsolete + Use the other constructor, because \a intValue is no longer stored separately. + Constructs a native gesture event of type \a type originating from \a device. The points \a localPos, \a scenePos and \a globalPos specify the @@ -2782,15 +2786,54 @@ QTabletEvent::~QTabletEvent() \a realValue is the \macos event parameter, \a sequenceId and \a intValue are the Windows event parameters. \since 5.10 + + \note It's not possible to store realValue and \a intValue simultaneously: + one or the other must be zero. If \a realValue == 0 and \a intValue != 0, + it is stored in the same variable, such that value() returns the value + given as \a intValue. */ +#if QT_DEPRECATED_SINCE(6, 2) QNativeGestureEvent::QNativeGestureEvent(Qt::NativeGestureType type, const QPointingDevice *device, const QPointF &localPos, const QPointF &scenePos, const QPointF &globalPos, qreal realValue, quint64 sequenceId, quint64 intValue) : QSinglePointEvent(QEvent::NativeGesture, device, localPos, scenePos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier), - m_sequenceId(sequenceId), m_intValue(intValue), m_realValue(realValue), m_gestureType(type) + m_sequenceId(sequenceId), m_realValue(realValue), m_gestureType(type) { + if (qIsNull(realValue) && intValue != 0) + m_realValue = intValue; +} +#endif // deprecated + +/*! + Constructs a native gesture event of type \a type originating from \a device + describing a gesture at \a scenePos in which \a fingerCount fingers are involved. + + The points \a localPos, \a scenePos and \a globalPos specify the gesture + position relative to the receiving widget or item, window, and screen or + desktop, respectively. + + \a value has a gesture-dependent interpretation: for RotateNativeGesture or + SwipeNativeGesture, it's an angle in degrees. For ZoomNativeGesture, + \a value is an incremental scaling factor, usually much less than 1, + indicating that the target item should have its scale adjusted like this: + item.scale = item.scale * (1 + event.value) + + For PanNativeGesture, \a deltas gives the distance in pixels that the + viewport, widget or item should be moved or panned. + + \since 6.2 +*/ +QNativeGestureEvent::QNativeGestureEvent(Qt::NativeGestureType type, const QPointingDevice *device, int fingerCount, + const QPointF &localPos, const QPointF &scenePos, + const QPointF &globalPos, qreal value, QVector2D deltas, + quint64 sequenceId) + : QSinglePointEvent(QEvent::NativeGesture, device, localPos, scenePos, globalPos, Qt::NoButton, + Qt::NoButton, Qt::NoModifier), + m_sequenceId(sequenceId), m_deltas(deltas), m_realValue(value), m_gestureType(type), m_fingerCount(fingerCount) +{ + Q_ASSERT(fingerCount < 16); // we store it in 4 bits unsigned } QNativeGestureEvent::~QNativeGestureEvent() = default; @@ -2802,6 +2845,15 @@ QNativeGestureEvent::~QNativeGestureEvent() = default; Returns the gesture type. */ +/*! + \fn QNativeGestureEvent::fingerCount() const + \since 6.2 + + Returns the number of fingers participating in the gesture, if known. + When gestureType() is Qt::BeginNativeGesture or Qt::EndNativeGesture, often + this information is unknown, and fingerCount() returns \c 0. +*/ + /*! \fn QNativeGestureEvent::value() const \since 5.2 @@ -2813,6 +2865,14 @@ QNativeGestureEvent::~QNativeGestureEvent() = default; \sa QNativeGestureEvent, gestureType() */ +/*! + \fn QNativeGestureEvent::deltas() const + \since 6.2 + + Returns the distance moved. A Pan gesture provides the distance in pixels by which + the target widget, item or viewport contents should be moved. +*/ + /*! \fn QPoint QNativeGestureEvent::globalPos() const \since 5.2 @@ -4113,7 +4173,13 @@ QT_WARNING_POP QtDebugUtils::formatQEnum(dbg, ne->gestureType()); dbg << ", localPos="; QtDebugUtils::formatQPoint(dbg, ne->position()); - dbg << ", value=" << ne->value() << ')'; + if (!qIsNull(ne->value())) + dbg << ", value=" << ne->value(); + if (!ne->deltas().isNull()) { + dbg << ", deltas="; + QtDebugUtils::formatQPoint(dbg, ne->deltas()); + } + dbg << ')'; } break; # endif // !QT_NO_GESTURES diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 3f8b53262f0..db886bdd988 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -408,14 +408,22 @@ class Q_GUI_EXPORT QNativeGestureEvent : public QSinglePointEvent { Q_EVENT_DISABLE_COPY(QNativeGestureEvent); public: +#if QT_DEPRECATED_SINCE(6, 2) + QT_DEPRECATED_VERSION_X_6_2("Use the other constructor") QNativeGestureEvent(Qt::NativeGestureType type, const QPointingDevice *dev, const QPointF &localPos, const QPointF &scenePos, const QPointF &globalPos, qreal value, quint64 sequenceId, quint64 intArgument); +#endif + QNativeGestureEvent(Qt::NativeGestureType type, const QPointingDevice *dev, int fingerCount, + const QPointF &localPos, const QPointF &scenePos, const QPointF &globalPos, + qreal value, QVector2D deltas, quint64 sequenceId = UINT64_MAX); ~QNativeGestureEvent(); QNativeGestureEvent *clone() const override { return new QNativeGestureEvent(*this); } Qt::NativeGestureType gestureType() const { return m_gestureType; } + int fingerCount() const { return m_fingerCount; } qreal value() const { return m_realValue; } + QVector2D deltas() const { return m_deltas; } #if QT_DEPRECATED_SINCE(6, 0) #ifndef QT_NO_INTEGER_EVENT_COORDINATES @@ -434,10 +442,11 @@ public: protected: quint64 m_sequenceId; - quint64 m_intValue; + QVector2D m_deltas; qreal m_realValue; Qt::NativeGestureType m_gestureType; - quint32 m_reserved; + quint32 m_fingerCount : 4; + quint32 m_reserved : 28; }; #endif // QT_CONFIG(gestures) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index dc62b079ded..247d9a8d1b7 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -2775,7 +2775,8 @@ void QGuiApplicationPrivate::processGestureEvent(QWindowSystemInterfacePrivate:: return; const QPointingDevice *device = static_cast(e->device); - QNativeGestureEvent ev(e->type, device, e->pos, e->pos, e->globalPos, e->realValue, e->sequenceId, e->intValue); + QNativeGestureEvent ev(e->type, device, e->fingerCount, e->pos, e->pos, e->globalPos, (e->intValue ? e->intValue : e->realValue), + e->deltas, e->sequenceId); ev.setTimestamp(e->timestamp); QGuiApplication::sendSpontaneousEvent(e->window, &ev); } diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index a79ff07c54a..dcce42ffe0e 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -1043,21 +1043,32 @@ void QWindowSystemInterface::handleTabletLeaveProximityEvent(int deviceType, int #ifndef QT_NO_GESTURES bool QWindowSystemInterface::handleGestureEvent(QWindow *window, ulong timestamp, const QPointingDevice *device, - Qt::NativeGestureType type, const QPointF &local, const QPointF &global) + Qt::NativeGestureType type, const QPointF &local, const QPointF &global, int fingerCount) { QWindowSystemInterfacePrivate::GestureEvent *e = - new QWindowSystemInterfacePrivate::GestureEvent(window, timestamp, type, device, local, global); + new QWindowSystemInterfacePrivate::GestureEvent(window, timestamp, type, device, fingerCount, local, global); return QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } bool QWindowSystemInterface::handleGestureEventWithRealValue(QWindow *window, ulong timestamp, const QPointingDevice *device, - Qt::NativeGestureType type, qreal value, const QPointF &local, const QPointF &global) + Qt::NativeGestureType type, qreal value, const QPointF &local, const QPointF &global, int fingerCount) { QWindowSystemInterfacePrivate::GestureEvent *e = - new QWindowSystemInterfacePrivate::GestureEvent(window, timestamp, type, device, local, global); + new QWindowSystemInterfacePrivate::GestureEvent(window, timestamp, type, device, fingerCount, local, global); e->realValue = value; return QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } + +bool QWindowSystemInterface::handleGestureEventWithValueAndDeltas(QWindow *window, ulong timestamp, const QPointingDevice *device, + Qt::NativeGestureType type, qreal value, QVector2D deltas, + const QPointF &local, const QPointF &global, int fingerCount) +{ + QWindowSystemInterfacePrivate::GestureEvent *e = + new QWindowSystemInterfacePrivate::GestureEvent(window, timestamp, type, device, fingerCount, local, global); + e->realValue = value; + e->deltas = deltas; + return QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); +} #endif // QT_NO_GESTURES void QWindowSystemInterface::handlePlatformPanelEvent(QWindow *w) diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index 1df4873c687..dc03b00dc7e 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -299,9 +299,11 @@ public: #ifndef QT_NO_GESTURES static bool handleGestureEvent(QWindow *window, ulong timestamp, const QPointingDevice *device, Qt::NativeGestureType type, - const QPointF &local, const QPointF &global); + const QPointF &local, const QPointF &global, int fingerCount = 0); static bool handleGestureEventWithRealValue(QWindow *window, ulong timestamp, const QPointingDevice *device, Qt::NativeGestureType type, - qreal value, const QPointF &local, const QPointF &global); + qreal value, const QPointF &local, const QPointF &global, int fingerCount = 2); + static bool handleGestureEventWithValueAndDeltas(QWindow *window, ulong timestamp, const QPointingDevice *device, Qt::NativeGestureType type, qreal value, + QVector2D deltas, const QPointF &local, const QPointF &global, int fingerCount = 2); #endif // QT_NO_GESTURES static void handlePlatformPanelEvent(QWindow *window); diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index d094dc401ae..742e22f7e8e 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -451,12 +451,15 @@ public: #ifndef QT_NO_GESTURES class GestureEvent : public PointerEvent { public: - GestureEvent(QWindow *window, ulong time, Qt::NativeGestureType type, const QPointingDevice *dev, QPointF pos, QPointF globalPos) + GestureEvent(QWindow *window, ulong time, Qt::NativeGestureType type, const QPointingDevice *dev, + int fingerCount, QPointF pos, QPointF globalPos) : PointerEvent(window, time, Gesture, Qt::NoModifier, dev), type(type), pos(pos), globalPos(globalPos), - realValue(0), sequenceId(0), intValue(0) { } + fingerCount(fingerCount), realValue(0), sequenceId(0), intValue(0) { } Qt::NativeGestureType type; QPointF pos; QPointF globalPos; + QVector2D deltas; + int fingerCount; // Mac qreal realValue; // Windows diff --git a/src/plugins/platforms/cocoa/qnsview_gestures.mm b/src/plugins/platforms/cocoa/qnsview_gestures.mm index c17eecf4f66..b92f69c7e50 100644 --- a/src/plugins/platforms/cocoa/qnsview_gestures.mm +++ b/src/plugins/platforms/cocoa/qnsview_gestures.mm @@ -137,7 +137,7 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures") QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), timestamp, QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]), - Qt::SwipeNativeGesture, angle, windowPoint, screenPoint); + Qt::SwipeNativeGesture, angle, windowPoint, screenPoint, 3); } - (void)beginGestureWithEvent:(NSEvent *)event