aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/handlers/qquickhandlerpoint.cpp5
-rw-r--r--src/quick/handlers/qquickhoverhandler.cpp19
-rw-r--r--src/quick/handlers/qquickhoverhandler_p.h1
-rw-r--r--src/quick/items/qquickevents.cpp162
-rw-r--r--src/quick/items/qquickevents_p_p.h71
-rw-r--r--src/quick/items/qquickwindow.cpp33
-rw-r--r--src/quick/items/qquickwindow.h3
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();