diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/quick/handlers/qquickhandlerpoint.cpp | 5 | ||||
-rw-r--r-- | src/quick/handlers/qquickhoverhandler.cpp | 19 | ||||
-rw-r--r-- | src/quick/handlers/qquickhoverhandler_p.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquickevents.cpp | 162 | ||||
-rw-r--r-- | src/quick/items/qquickevents_p_p.h | 71 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 33 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.h | 3 |
7 files changed, 274 insertions, 20 deletions
diff --git a/src/quick/handlers/qquickhandlerpoint.cpp b/src/quick/handlers/qquickhandlerpoint.cpp index f3d92cf200..e6148ca072 100644 --- a/src/quick/handlers/qquickhandlerpoint.cpp +++ b/src/quick/handlers/qquickhandlerpoint.cpp @@ -120,7 +120,10 @@ void QQuickHandlerPoint::reset(const QQuickEventPoint *point) m_pressure = tp->pressure(); m_ellipseDiameters = tp->ellipseDiameters(); } else if (event->asPointerTabletEvent()) { - // TODO + m_uniqueId = event->device()->uniqueId(); + m_rotation = static_cast<const QQuickEventTabletPoint *>(point)->rotation(); + m_pressure = static_cast<const QQuickEventTabletPoint *>(point)->pressure(); + m_ellipseDiameters = QSizeF(); } else { m_uniqueId = event->device()->uniqueId(); m_rotation = 0; diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp index 1216eda477..b12d85784a 100644 --- a/src/quick/handlers/qquickhoverhandler.cpp +++ b/src/quick/handlers/qquickhoverhandler.cpp @@ -93,11 +93,22 @@ bool QQuickHoverHandler::wantsPointerEvent(QQuickPointerEvent *event) { QQuickEventPoint *point = event->point(0); if (QQuickPointerDeviceHandler::wantsPointerEvent(event) && wantsEventPoint(point) && parentContains(point)) { - // assume this is a mouse event, so there's only one point + // assume this is a mouse or tablet event, so there's only one point setPointId(point->pointId()); return true; } - setHovered(false); + + // Some hover events come from QQuickWindow::tabletEvent(). In between, + // some hover events come from QQWindowPrivate::flushFrameSynchronousEvents(), + // but those look like mouse events. If a particular HoverHandler instance + // is filtering for tablet events only (e.g. by setting + // acceptedDevices:PointerDevice.Stylus), those events should not cause + // the hovered property to transition to false prematurely. + // If a QQuickPointerTabletEvent caused the hovered property to become true, + // then only another QQuickPointerTabletEvent can make it become false. + if (!(m_hoveredTablet && event->asPointerMouseEvent())) + setHovered(false); + return false; } @@ -107,6 +118,8 @@ void QQuickHoverHandler::handleEventPoint(QQuickEventPoint *point) if (point->state() == QQuickEventPoint::Released && point->pointerEvent()->device()->pointerType() == QQuickPointerDevice::Finger) hovered = false; + else if (point->pointerEvent()->asPointerTabletEvent()) + m_hoveredTablet = true; setHovered(hovered); setPassiveGrab(point); } @@ -124,6 +137,8 @@ void QQuickHoverHandler::setHovered(bool hovered) if (m_hovered != hovered) { qCDebug(lcHoverHandler) << objectName() << "hovered" << m_hovered << "->" << hovered; m_hovered = hovered; + if (!hovered) + m_hoveredTablet = false; emit hoveredChanged(); } } diff --git a/src/quick/handlers/qquickhoverhandler_p.h b/src/quick/handlers/qquickhoverhandler_p.h index e4786bfa53..313b87217c 100644 --- a/src/quick/handlers/qquickhoverhandler_p.h +++ b/src/quick/handlers/qquickhoverhandler_p.h @@ -84,6 +84,7 @@ private: private: bool m_hovered = false; + bool m_hoveredTablet = false; }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 0a6faf04af..0a9abb3322 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -658,14 +658,73 @@ QQuickPointerDevice *QQuickPointerDevice::genericMouseDevice() return g_genericMouseDevice; } -QQuickPointerDevice *QQuickPointerDevice::tabletDevice(qint64 id) -{ - auto it = g_tabletDevices->find(id); +QQuickPointerDevice *QQuickPointerDevice::tabletDevice(const QTabletEvent *event) +{ + // QTabletEvent::uniqueId() is the same for the pointy end and the eraser end of the stylus. + // We need to make those unique. QTabletEvent::PointerType only needs 2 bits' worth of storage. + // The key into g_tabletDevices just needs to be unique; we don't need to extract uniqueId + // back out of it, because QQuickPointerDevice stores that separately anyway. + // So the shift-and-add can be thought of as a sort of hash function, even though + // most of the time the result will be recognizable because the uniqueId MSBs are often 0. + qint64 key = event->uniqueId() + (qint64(event->pointerType()) << 60); + auto it = g_tabletDevices->find(key); if (it != g_tabletDevices->end()) return it.value(); - // ### Figure out how to populate the tablet devices - return nullptr; + DeviceType type = UnknownDevice; + int buttonCount = 0; + Capabilities caps = Position | Pressure | Hover; + // TODO Qt 6: we can't know for sure about XTilt or YTilt until we have a + // QTabletDevice populated with capabilities provided by QPA plugins + + switch (event->device()) { + case QTabletEvent::Stylus: + type = QQuickPointerDevice::Stylus; + buttonCount = 3; + break; + case QTabletEvent::RotationStylus: + type = QQuickPointerDevice::Stylus; + caps |= QQuickPointerDevice::Rotation; + buttonCount = 1; + break; + case QTabletEvent::Airbrush: + type = QQuickPointerDevice::Airbrush; + buttonCount = 2; + break; + case QTabletEvent::Puck: + type = QQuickPointerDevice::Puck; + buttonCount = 3; + break; + case QTabletEvent::FourDMouse: + type = QQuickPointerDevice::Mouse; + caps |= QQuickPointerDevice::Rotation; + buttonCount = 3; + break; + default: + type = QQuickPointerDevice::UnknownDevice; + break; + } + + PointerType ptype = GenericPointer; + switch (event->pointerType()) { + case QTabletEvent::Pen: + ptype = Pen; + break; + case QTabletEvent::Eraser: + ptype = Eraser; + break; + case QTabletEvent::Cursor: + ptype = Cursor; + break; + case QTabletEvent::UnknownPointer: + break; + } + + QQuickPointerDevice *device = new QQuickPointerDevice(type, ptype, caps, 1, buttonCount, + QLatin1String("tablet tool ") + QString::number(event->uniqueId()), event->uniqueId()); + + g_tabletDevices->insert(key, device); + return device; } /*! @@ -1284,6 +1343,12 @@ QVector2D QQuickEventPoint::estimatedVelocity() const QQuickPointerEvent::~QQuickPointerEvent() {} +QQuickPointerMouseEvent::QQuickPointerMouseEvent(QObject *parent, QQuickPointerDevice *device) + : QQuickSinglePointEvent(parent, device) +{ + m_point = new QQuickEventPoint(this); +} + QQuickPointerEvent *QQuickPointerMouseEvent::reset(QEvent *event) { auto ev = static_cast<QMouseEvent*>(event); @@ -1398,6 +1463,12 @@ void QQuickPointerTouchEvent::localize(QQuickItem *target) } #if QT_CONFIG(gestures) +QQuickPointerNativeGestureEvent::QQuickPointerNativeGestureEvent(QObject *parent, QQuickPointerDevice *device) + : QQuickSinglePointEvent(parent, device) +{ + m_point = new QQuickEventPoint(this); +} + QQuickPointerEvent *QQuickPointerNativeGestureEvent::reset(QEvent *event) { auto ev = static_cast<QNativeGestureEvent*>(event); @@ -1560,6 +1631,12 @@ QQuickEventPoint *QQuickSinglePointEvent::point(int i) const \note Many platforms provide no such information. On such platforms, \c inverted always returns false. */ +QQuickPointerScrollEvent::QQuickPointerScrollEvent(QObject *parent, QQuickPointerDevice *device) + : QQuickSinglePointEvent(parent, device) +{ + m_point = new QQuickEventPoint(this); +} + QQuickPointerEvent *QQuickPointerScrollEvent::reset(QEvent *event) { m_event = static_cast<QInputEvent*>(event); @@ -1832,6 +1909,81 @@ QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickIte return &m_synthMouseEvent; } +#if QT_CONFIG(tabletevent) +QQuickPointerTabletEvent::QQuickPointerTabletEvent(QObject *parent, QQuickPointerDevice *device) + : QQuickSinglePointEvent(parent, device) +{ + m_point = new QQuickEventTabletPoint(this); +} + +QQuickPointerEvent *QQuickPointerTabletEvent::reset(QEvent *event) +{ + auto ev = static_cast<QTabletEvent*>(event); + m_event = ev; + if (!event) + return this; + + Q_ASSERT(m_device == QQuickPointerDevice::tabletDevice(ev)); + m_device->eventDeliveryTargets().clear(); + m_button = ev->button(); + m_pressedButtons = ev->buttons(); + static_cast<QQuickEventTabletPoint *>(m_point)->reset(ev); + return this; +} + +QQuickEventTabletPoint::QQuickEventTabletPoint(QQuickPointerTabletEvent *parent) + : QQuickEventPoint(parent) +{ +} + +void QQuickEventTabletPoint::reset(const QTabletEvent *ev) +{ + Qt::TouchPointState state = Qt::TouchPointStationary; + switch (ev->type()) { + case QEvent::TabletPress: + state = Qt::TouchPointPressed; + clearPassiveGrabbers(); + break; + case QEvent::TabletRelease: + state = Qt::TouchPointReleased; + break; + case QEvent::TabletMove: + state = Qt::TouchPointMoved; + break; + default: + break; + } + QQuickEventPoint::reset(state, ev->posF(), 1, ev->timestamp()); + m_rotation = ev->rotation(); + m_pressure = ev->pressure(); + m_tangentialPressure = ev->tangentialPressure(); + m_tilt = QVector2D(ev->xTilt(), ev->yTilt()); +} + +bool QQuickPointerTabletEvent::isPressEvent() const +{ + auto me = static_cast<QTabletEvent *>(m_event); + return me->type() == QEvent::TabletPress; +} + +bool QQuickPointerTabletEvent::isUpdateEvent() const +{ + auto me = static_cast<QTabletEvent *>(m_event); + return me->type() == QEvent::TabletMove; +} + +bool QQuickPointerTabletEvent::isReleaseEvent() const +{ + auto me = static_cast<QTabletEvent *>(m_event); + return me->type() == QEvent::TabletRelease; +} + +QTabletEvent *QQuickPointerTabletEvent::asTabletEvent() const +{ + return static_cast<QTabletEvent *>(m_event); +} +#endif // QT_CONFIG(tabletevent) + #if QT_CONFIG(gestures) bool QQuickPointerNativeGestureEvent::isPressEvent() const { diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index 4615ce43d2..3a8028678e 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -476,8 +476,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickSinglePointEvent : public QQuickPointerEvent { Q_OBJECT public: - QQuickSinglePointEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr) - : QQuickPointerEvent(parent, device), m_point(new QQuickEventPoint(this)) { } + QQuickSinglePointEvent(QObject *parent, QQuickPointerDevice *device) + : QQuickPointerEvent(parent, device) { } void localize(QQuickItem *target) override; int pointCount() const override { return 1; } @@ -491,7 +491,7 @@ public: bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const override; protected: - QQuickEventPoint *m_point; + QQuickEventPoint *m_point = nullptr; Q_DISABLE_COPY(QQuickSinglePointEvent) }; @@ -505,8 +505,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerMouseEvent : public QQuickSinglePointE QML_ADDED_IN_MINOR_VERSION(12) public: - QQuickPointerMouseEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr) - : QQuickSinglePointEvent(parent, device) { } + QQuickPointerMouseEvent(QObject *parent, QQuickPointerDevice *device); QQuickPointerEvent *reset(QEvent *) override; bool isPressEvent() const override; @@ -568,6 +567,60 @@ private: Q_DISABLE_COPY(QQuickPointerTouchEvent) }; +#if QT_CONFIG(tabletevent) +class Q_QUICK_PRIVATE_EXPORT QQuickEventTabletPoint : public QQuickEventPoint +{ + Q_OBJECT + Q_PROPERTY(qreal rotation READ rotation) + Q_PROPERTY(qreal pressure READ pressure) + Q_PROPERTY(qreal tangentialPressure READ tangentialPressure) + Q_PROPERTY(QVector2D tilt READ tilt) + + QML_NAMED_ELEMENT(EventTabletPoint) + QML_UNCREATABLE("EventTouchPoint is only available as a member of PointerEvent.") + QML_ADDED_IN_MINOR_VERSION(15) + +public: + QQuickEventTabletPoint(QQuickPointerTabletEvent *parent); + + void reset(const QTabletEvent *e); + + qreal rotation() const { return m_rotation; } + qreal pressure() const { return m_pressure; } + qreal tangentialPressure() const { return m_tangentialPressure; } + QVector2D tilt() const { return m_tilt; } + +private: + qreal m_rotation; + qreal m_pressure; + qreal m_tangentialPressure; + QVector2D m_tilt; + + friend class QQuickPointerTouchEvent; + + Q_DISABLE_COPY(QQuickEventTabletPoint) +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickPointerTabletEvent : public QQuickSinglePointEvent +{ + Q_OBJECT +public: + QQuickPointerTabletEvent(QObject *parent, QQuickPointerDevice *device); + + QQuickPointerEvent *reset(QEvent *) override; + bool isPressEvent() const override; + bool isUpdateEvent() const override; + bool isReleaseEvent() const override; + QQuickPointerTabletEvent *asPointerTabletEvent() override { return this; } + const QQuickPointerTabletEvent *asPointerTabletEvent() const override { return this; } + const QQuickEventTabletPoint *tabletPoint() const { return static_cast<QQuickEventTabletPoint *>(m_point); } + + QTabletEvent *asTabletEvent() const; + + Q_DISABLE_COPY(QQuickPointerTabletEvent) +}; +#endif // QT_CONFIG(tabletevent) + #if QT_CONFIG(gestures) class Q_QUICK_PRIVATE_EXPORT QQuickPointerNativeGestureEvent : public QQuickSinglePointEvent { @@ -576,8 +629,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerNativeGestureEvent : public QQuickSing Q_PROPERTY(qreal value READ value CONSTANT) public: - QQuickPointerNativeGestureEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr) - : QQuickSinglePointEvent(parent, device) { } + QQuickPointerNativeGestureEvent(QObject *parent, QQuickPointerDevice *device); QQuickPointerEvent *reset(QEvent *) override; bool isPressEvent() const override; @@ -606,8 +658,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerScrollEvent : public QQuickSinglePoint QML_ADDED_IN_MINOR_VERSION(14) public: - QQuickPointerScrollEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr) - : QQuickSinglePointEvent(parent, device) { } + QQuickPointerScrollEvent(QObject *parent, QQuickPointerDevice *device); QQuickPointerEvent *reset(QEvent *) override; void localize(QQuickItem *target) override; @@ -712,7 +763,7 @@ public: static QQuickPointerDevice *touchDevice(const QTouchDevice *d); static QList<QQuickPointerDevice *> touchDevices(); static QQuickPointerDevice *genericMouseDevice(); - static QQuickPointerDevice *tabletDevice(qint64); + static QQuickPointerDevice *tabletDevice(const QTabletEvent *event); QVector<QQuickPointerHandler *> &eventDeliveryTargets() { return m_eventDeliveryTargets; } diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 6c63b83511..dda0cfef3e 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -93,6 +93,7 @@ Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch") Q_LOGGING_CATEGORY(DBG_TOUCH_TARGET, "qt.quick.touch.target") Q_LOGGING_CATEGORY(DBG_MOUSE, "qt.quick.mouse") Q_LOGGING_CATEGORY(DBG_MOUSE_TARGET, "qt.quick.mouse.target") +Q_LOGGING_CATEGORY(lcTablet, "qt.quick.tablet") Q_LOGGING_CATEGORY(lcWheelTarget, "qt.quick.wheel.target") Q_LOGGING_CATEGORY(lcGestureTarget, "qt.quick.gesture.target") Q_LOGGING_CATEGORY(DBG_HOVER_TRACE, "qt.quick.hover.trace") @@ -2122,6 +2123,17 @@ void QQuickWindow::wheelEvent(QWheelEvent *event) } #endif // wheelevent +#if QT_CONFIG(tabletevent) +/*! \reimp */ +void QQuickWindow::tabletEvent(QTabletEvent *event) +{ + Q_D(QQuickWindow); + qCDebug(lcTablet) << event; + // TODO Qt 6: make sure TabletEnterProximity and TabletLeaveProximity are delivered here + d->deliverPointerEvent(d->pointerEventInstance(event)); +} +#endif // tabletevent + bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event) { qCDebug(DBG_TOUCH) << event; @@ -2400,8 +2412,12 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevic #endif ev = new QQuickPointerTouchEvent(q, device); break; + case QQuickPointerDevice::Stylus: + case QQuickPointerDevice::Airbrush: + case QQuickPointerDevice::Puck: + ev = new QQuickPointerTabletEvent(q, device); + break; default: - // TODO tablet event types break; } pointerEventInstances << ev; @@ -2432,7 +2448,15 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QEvent *event) con case QEvent::TouchCancel: dev = QQuickPointerDevice::touchDevice(static_cast<QTouchEvent *>(event)->device()); break; - // TODO tablet event types +#if QT_CONFIG(tabletevent) + case QEvent::TabletPress: + case QEvent::TabletMove: + case QEvent::TabletRelease: + case QEvent::TabletEnterProximity: + case QEvent::TabletLeaveProximity: + dev = QQuickPointerDevice::tabletDevice(static_cast<QTabletEvent *>(event)); + break; +#endif #if QT_CONFIG(gestures) case QEvent::NativeGesture: dev = QQuickPointerDevice::touchDevice(static_cast<QNativeGestureEvent *>(event)->device()); @@ -2467,6 +2491,11 @@ void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event) deliverTouchEvent(event->asPointerTouchEvent()); } else { deliverSinglePointEventUntilAccepted(event); + // If any handler got interested in the tablet event, we don't want to receive a synth-mouse event from QtGui + // TODO Qt 6: QTabletEvent will be accepted by default, like other events + if (event->asPointerTabletEvent() && + (!event->point(0)->passiveGrabbers().isEmpty() || event->point(0)->exclusiveGrabber())) + event->setAccepted(true); } event->reset(nullptr); diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index d22bba4512..097627374c 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -252,6 +252,9 @@ protected: #if QT_CONFIG(wheelevent) void wheelEvent(QWheelEvent *) override; #endif +#if QT_CONFIG(tabletevent) + void tabletEvent(QTabletEvent *) override; +#endif private Q_SLOTS: void maybeUpdate(); |