summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qpointingdevice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel/qpointingdevice.cpp')
-rw-r--r--src/gui/kernel/qpointingdevice.cpp552
1 files changed, 465 insertions, 87 deletions
diff --git a/src/gui/kernel/qpointingdevice.cpp b/src/gui/kernel/qpointingdevice.cpp
index 05bea8ccd7..c4c1e5fd5c 100644
--- a/src/gui/kernel/qpointingdevice.cpp
+++ b/src/gui/kernel/qpointingdevice.cpp
@@ -1,44 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpointingdevice.h"
#include "qpointingdevice_p.h"
+#include "qwindowsysteminterface_p.h"
+#include "qeventpoint_p.h"
+
#include <QList>
#include <QLoggingCategory>
#include <QMutex>
@@ -48,7 +15,9 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcQpaInputDevices)
+using namespace Qt::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcPointerGrab, "qt.pointer.grab");
/*!
\class QPointingDevice
@@ -103,6 +72,9 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaInputDevices)
A device that is similar to a flat mouse with a transparent circle with
cross-hairs.
+ \value Keyboard
+ A keyboard.
+
\value AllDevices
Any of the above (used as a default filter value).
*/
@@ -133,47 +105,61 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaInputDevices)
\value Eraser
The other end of the stylus (if it has a virtual eraser on the other end).
\value Cursor
- A transparent circle with cross-hairs as found on a \l {DeviceType.Puck}{Puck} device.
+ A transparent circle with cross-hairs as found on a
+ \l {QInputDevice::DeviceType}{Puck} device.
\value AllPointerTypes
Any of the above (used as a default filter value).
*/
-/*! \enum QPointingDevice::Capability
+/*! \enum QPointingDevice::GrabTransition
- This enum is used with QPointingDevice::capabilities() to indicate what kind of information the
- touch device or its driver can provide.
+ This enum represents a transition of exclusive or passive grab
+ from one object (possibly \c nullptr) to another (possibly \c nullptr).
+ It is emitted as an argument of the QPointingDevice::grabChanged() signal.
- \value Position
- Indicates that position information is available, meaning that the
- pos() family of functions in the touch points return valid points.
+ Valid values are:
- \value Area
- Indicates that touch area information is available, meaning that the
- rect() family of functions in the touch points return valid rectangles.
+ \value GrabExclusive
+ Emitted after QPointerEvent::setExclusiveGrabber().
+ \value UngrabExclusive
+ Emitted after QPointerEvent::setExclusiveGrabber() when the grabber is
+ set to \c nullptr, to notify that the grab has terminated normally.
+ \value CancelGrabExclusive
+ Emitted after QPointerEvent::setExclusiveGrabber() when the grabber is set
+ to a different object, to notify that the old grabber's grab is "stolen".
+ \value GrabPassive
+ Emitted after QPointerEvent::addPassiveGrabber().
+ \value UngrabPassive
+ Emitted when a passive grab is terminated normally,
+ for example after QPointerEvent::removePassiveGrabber().
+ \value CancelGrabPassive
+ Emitted when a passive grab is terminated abnormally (a gesture is canceled).
+ \value OverrideGrabPassive
+ This value is not currently used.
+*/
- \value Pressure
- Indicates that pressure information is available, meaning that
- QPointerEvent::EventPoint::pressure() returns a valid value.
+/*! \fn void QPointingDevice::grabChanged(QObject *grabber, QPointingDevice::GrabTransition transition, const QPointerEvent *event, const QEventPoint &point) const
- \value Velocity
- Indicates that velocity information is available, meaning that
- QPointerEvent::EventPoint::velocity() returns a valid vector.
+ This signal is emitted when the \a grabber object gains or loses an
+ exclusive or passive grab of \a point during delivery of \a event.
+ The \a transition tells what happened, from the perspective of the
+ \c grabber object.
- \value NormalizedPosition
- Indicates that the normalized position is available, meaning that
- QPointerEvent::EventPoint::normalizedPos() returns a valid value.
+ \note A grab transition from one object to another results in two signals,
+ to notify that one object has lost its grab, and to notify that there is
+ another grabber. In other cases, when transitioning to or from a non-grabbing
+ state, only one signal is emitted: the \a grabber argument is never \c nullptr.
- \value MouseEmulation
- Indicates that the device synthesizes mouse events.
+ \sa QPointerEvent::setExclusiveGrabber(), QPointerEvent::addPassiveGrabber(), QPointerEvent::removePassiveGrabber()
*/
/*!
- Creates a new invalid pointing device instance.
+ Creates a new invalid pointing device instance as a child of \a parent.
*/
-QPointingDevice::QPointingDevice()
- : QInputDevice(*(new QPointingDevicePrivate(QLatin1String("unknown"), -1,
+QPointingDevice::QPointingDevice(QObject *parent)
+ : QInputDevice(*(new QPointingDevicePrivate("unknown"_L1, -1,
DeviceType::Unknown, PointerType::Unknown,
- Capability::None, 0, 0)))
+ Capability::None, 0, 0)), parent)
{
}
@@ -183,8 +169,8 @@ QPointingDevice::~QPointingDevice()
/*!
Creates a new pointing device instance with the given
- \a deviceType, \a pointerType, \a capabilities, \a maxPoints,
- \a buttonCount, \a name, \a id and \a seatId.
+ \a name, \a deviceType, \a pointerType, \a capabilities, \a maxPoints,
+ \a buttonCount, \a seatName, \a uniqueId and \a parent.
*/
QPointingDevice::QPointingDevice(const QString &name, qint64 id, QInputDevice::DeviceType deviceType,
QPointingDevice::PointerType pointerType, Capabilities capabilities, int maxPoints, int buttonCount,
@@ -201,9 +187,10 @@ QPointingDevice::QPointingDevice(QPointingDevicePrivate &d, QObject *parent)
{
}
+#if QT_DEPRECATED_SINCE(6, 0)
/*!
\internal
- \deprecated Please use the constructor rather than setters.
+ \deprecated [6.0] Please use the constructor rather than setters.
Sets the device type \a devType and infers the pointer type.
*/
@@ -234,7 +221,7 @@ void QPointingDevice::setType(DeviceType devType)
/*!
\internal
- \deprecated Please use the constructor rather than setters.
+ \deprecated [6.0] Please use the constructor rather than setters.
*/
void QPointingDevice::setCapabilities(QInputDevice::Capabilities caps)
{
@@ -244,13 +231,14 @@ void QPointingDevice::setCapabilities(QInputDevice::Capabilities caps)
/*!
\internal
- \deprecated Please use the constructor rather than setters.
+ \deprecated [6.0] Please use the constructor rather than setters.
*/
void QPointingDevice::setMaximumTouchPoints(int c)
{
Q_D(QPointingDevice);
d->maximumTouchPoints = c;
}
+#endif // QT_DEPRECATED_SINCE(6, 0)
/*!
Returns the pointer type.
@@ -308,7 +296,7 @@ const QPointingDevice *QPointingDevice::primaryPointingDevice(const QString& sea
const QPointingDevice *mouse = nullptr;
const QPointingDevice *touchpad = nullptr;
for (const QInputDevice *dev : v) {
- if (dev->seatName() != seatName)
+ if (!seatName.isNull() && dev->seatName() != seatName)
continue;
if (dev->type() == QInputDevice::DeviceType::Mouse) {
if (!mouse)
@@ -325,19 +313,22 @@ const QPointingDevice *QPointingDevice::primaryPointingDevice(const QString& sea
qCDebug(lcQpaInputDevices) << "no mouse-like devices registered for seat" << seatName
<< "The platform plugin should have provided one via "
"QWindowSystemInterface::registerInputDevice(). Creating a default mouse for now.";
- mouse = new QPointingDevice(QLatin1String("core pointer"), 1, DeviceType::Mouse,
+ mouse = new QPointingDevice("core pointer"_L1, 1, DeviceType::Mouse,
PointerType::Generic, Capability::Position, 1, 3, seatName,
QPointingDeviceUniqueId(), QCoreApplication::instance());
QInputDevicePrivate::registerDevice(mouse);
return mouse;
}
- if (v.length() > 1)
+ if (v.size() > 1)
qCDebug(lcQpaInputDevices) << "core pointer ambiguous for seat" << seatName;
if (mouse)
return mouse;
return touchpad;
}
+QPointingDevicePrivate::~QPointingDevicePrivate()
+ = default;
+
/*!
\internal
Finds the device instance belonging to the drawing or eraser end of a particular stylus,
@@ -348,14 +339,16 @@ const QPointingDevice *QPointingDevice::primaryPointingDevice(const QString& sea
If an instance matching the given \a deviceType and \a pointerType but with
only a default-constructed \c uniqueId is found, it will be assumed to be
- the one we're looking for, and its \c uniqueId will be updated to match the
- given \a uniqueId. This is for the benefit of any platform plugin that can
+ the one we're looking for, its \c uniqueId will be updated to match the
+ given \a uniqueId, and its \c capabilities will be updated to match the
+ given \a capabilities. This is for the benefit of any platform plugin that can
discover the tablet itself at startup, along with the supported stylus types,
but then discovers specific styli later on as they come into proximity.
*/
const QPointingDevice *QPointingDevicePrivate::queryTabletDevice(QInputDevice::DeviceType deviceType,
QPointingDevice::PointerType pointerType,
QPointingDeviceUniqueId uniqueId,
+ QPointingDevice::Capabilities capabilities,
qint64 systemId)
{
const auto &devices = QInputDevice::devices();
@@ -370,7 +363,9 @@ const QPointingDevice *QPointingDevicePrivate::queryTabletDevice(QInputDevice::D
(devPriv->uniqueId == uniqueId || uniqueIdDiscovered)) {
if (uniqueIdDiscovered) {
const_cast<QPointingDevicePrivate *>(devPriv)->uniqueId = uniqueId;
- qCDebug(lcQpaInputDevices) << "discovered unique ID of tablet tool" << pdev;
+ if (capabilities)
+ const_cast<QPointingDevicePrivate *>(devPriv)->capabilities = capabilities;
+ qCDebug(lcQpaInputDevices) << "discovered unique ID and capabilities of tablet tool" << pdev;
}
return pdev;
}
@@ -380,6 +375,293 @@ const QPointingDevice *QPointingDevicePrivate::queryTabletDevice(QInputDevice::D
/*!
\internal
+ Finds the device instance identified by its \a systemId.
+ Returns the device found, or \c nullptr if none was found.
+*/
+const QPointingDevice *QPointingDevicePrivate::pointingDeviceById(qint64 systemId)
+{
+ const auto &devices = QInputDevice::devices();
+ for (const QInputDevice *dev : devices) {
+ if (dev->type() >= QPointingDevice::DeviceType::Keyboard)
+ continue;
+ const QPointingDevice *pdev = static_cast<const QPointingDevice *>(dev);
+ const auto devPriv = QPointingDevicePrivate::get(pdev);
+ if (devPriv->systemId == systemId)
+ return pdev;
+ }
+ return nullptr;
+}
+
+/*!
+ \internal
+ First, ensure that the \a cancelEvent's QTouchEvent::points() list contains
+ all points that have exclusive grabs. Then send the event to each object
+ that has an exclusive grab of any of the points.
+*/
+void QPointingDevicePrivate::sendTouchCancelEvent(QTouchEvent *cancelEvent)
+{
+ // An incoming TouchCancel event will typically not contain any points, but
+ // QQuickPointerHandler::onGrabChanged needs to be called for each point
+ // that has an exclusive grabber. Adding those points to the event makes it
+ // an easy iteration there.
+ if (cancelEvent->points().isEmpty()) {
+ for (auto &epd : activePoints.values()) {
+ if (epd.exclusiveGrabber)
+ QMutableTouchEvent::from(cancelEvent)->addPoint(epd.eventPoint);
+ }
+ }
+ for (auto &epd : activePoints.values()) {
+ if (epd.exclusiveGrabber)
+ QCoreApplication::sendEvent(epd.exclusiveGrabber, cancelEvent);
+ // The next touch event can only be a TouchBegin, so clean up.
+ cancelEvent->setExclusiveGrabber(epd.eventPoint, nullptr);
+ cancelEvent->clearPassiveGrabbers(epd.eventPoint);
+ }
+}
+
+/*! \internal
+ Returns the active EventPointData instance with the given \a id, if available,
+ or \c nullptr if not.
+*/
+QPointingDevicePrivate::EventPointData *QPointingDevicePrivate::queryPointById(int id) const
+{
+ auto it = activePoints.find(id);
+ if (it == activePoints.end())
+ return nullptr;
+ return &it.value();
+}
+
+/*! \internal
+ Returns the active EventPointData instance with the given \a id, if available;
+ if not, appends a new instance and returns it.
+*/
+QPointingDevicePrivate::EventPointData *QPointingDevicePrivate::pointById(int id) const
+{
+ const auto [it, inserted] = activePoints.try_emplace(id);
+ if (inserted) {
+ Q_Q(const QPointingDevice);
+ auto &epd = it.value();
+ QMutableEventPoint::setId(epd.eventPoint, id);
+ QMutableEventPoint::setDevice(epd.eventPoint, q);
+ }
+ return &it.value();
+}
+
+/*! \internal
+ Remove the active EventPointData instance with the given \a id.
+*/
+void QPointingDevicePrivate::removePointById(int id)
+{
+ activePoints.remove(id);
+}
+
+/*!
+ \internal
+ Find the first non-null target (widget) via QMutableEventPoint::target()
+ in the active points. This is the widget that will receive any event that
+ comes from a touchpad, even if some of the touchpoints fall spatially on
+ other windows.
+*/
+QObject *QPointingDevicePrivate::firstActiveTarget() const
+{
+ for (auto &pt : activePoints.values()) {
+ if (auto target = QMutableEventPoint::target(pt.eventPoint))
+ return target;
+ }
+ return nullptr;
+}
+
+/*! \internal
+ Find the first non-null QWindow instance via QMutableEventPoint::window()
+ in the active points. This is the window that will receive any event that
+ comes from a touchpad, even if some of the touchpoints fall spatially on
+ other windows.
+*/
+QWindow *QPointingDevicePrivate::firstActiveWindow() const
+{
+ for (auto &pt : activePoints.values()) {
+ if (auto window = QMutableEventPoint::window(pt.eventPoint))
+ return window;
+ }
+ return nullptr;
+}
+
+/*! \internal
+ Return the exclusive grabber of the first point in activePoints.
+ This is mainly for autotests that try to verify the "current" grabber
+ outside the context of event delivery, which is something that the rest
+ of the codebase should not be doing.
+*/
+QObject *QPointingDevicePrivate::firstPointExclusiveGrabber() const
+{
+ if (activePoints.isEmpty())
+ return nullptr;
+ return activePoints.values().first().exclusiveGrabber;
+}
+
+void QPointingDevicePrivate::setExclusiveGrabber(const QPointerEvent *event, const QEventPoint &point, QObject *exclusiveGrabber)
+{
+ Q_Q(QPointingDevice);
+ auto persistentPoint = queryPointById(point.id());
+ if (!persistentPoint) {
+ qWarning() << "point is not in activePoints" << point;
+ return;
+ }
+ Q_ASSERT(persistentPoint->eventPoint.id() == point.id());
+ if (persistentPoint->exclusiveGrabber == exclusiveGrabber)
+ return;
+ auto oldGrabber = persistentPoint->exclusiveGrabber;
+ persistentPoint->exclusiveGrabber = exclusiveGrabber;
+ if (oldGrabber)
+ emit q->grabChanged(oldGrabber, exclusiveGrabber ? QPointingDevice::CancelGrabExclusive : QPointingDevice::UngrabExclusive,
+ event, persistentPoint->eventPoint);
+ if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
+ qCDebug(lcPointerGrab) << name << "point" << point.id() << point.state()
+ << "@" << point.scenePosition()
+ << ": grab" << oldGrabber << "->" << exclusiveGrabber;
+ }
+ QMutableEventPoint::setGlobalGrabPosition(persistentPoint->eventPoint, point.globalPosition());
+ if (exclusiveGrabber)
+ emit q->grabChanged(exclusiveGrabber, QPointingDevice::GrabExclusive, event, point);
+ else
+ persistentPoint->exclusiveGrabberContext.clear();
+}
+
+/*!
+ \internal
+ Call QEventPoint::setExclusiveGrabber(nullptr) on each active point that has a grabber.
+*/
+bool QPointingDevicePrivate::removeExclusiveGrabber(const QPointerEvent *event, const QObject *grabber)
+{
+ bool ret = false;
+ for (auto &pt : activePoints.values()) {
+ if (pt.exclusiveGrabber == grabber) {
+ setExclusiveGrabber(event, pt.eventPoint, nullptr);
+ ret = true;
+ }
+ }
+ return ret;
+}
+
+bool QPointingDevicePrivate::addPassiveGrabber(const QPointerEvent *event, const QEventPoint &point, QObject *grabber)
+{
+ Q_Q(QPointingDevice);
+ auto persistentPoint = queryPointById(point.id());
+ if (!persistentPoint) {
+ qWarning() << "point is not in activePoints" << point;
+ return false;
+ }
+ if (persistentPoint->passiveGrabbers.contains(grabber))
+ return false;
+ if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
+ qCDebug(lcPointerGrab) << name << "point" << point.id() << point.state()
+ << ": grab (passive)" << grabber;
+ }
+ persistentPoint->passiveGrabbers << grabber;
+ emit q->grabChanged(grabber, QPointingDevice::GrabPassive, event, point);
+ return true;
+}
+
+bool QPointingDevicePrivate::setPassiveGrabberContext(QPointingDevicePrivate::EventPointData *epd, QObject *grabber, QObject *context)
+{
+ qsizetype i = epd->passiveGrabbers.indexOf(grabber);
+ if (i < 0)
+ return false;
+ if (epd->passiveGrabbersContext.size() <= i)
+ epd->passiveGrabbersContext.resize(i + 1);
+ epd->passiveGrabbersContext[i] = context;
+ return true;
+}
+
+bool QPointingDevicePrivate::removePassiveGrabber(const QPointerEvent *event, const QEventPoint &point, QObject *grabber)
+{
+ Q_Q(QPointingDevice);
+ auto persistentPoint = queryPointById(point.id());
+ if (!persistentPoint) {
+ qWarning() << "point is not in activePoints" << point;
+ return false;
+ }
+ qsizetype i = persistentPoint->passiveGrabbers.indexOf(grabber);
+ if (i >= 0) {
+ if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
+ qCDebug(lcPointerGrab) << name << "point" << point.id() << point.state()
+ << ": removing passive grabber" << grabber;
+ }
+ emit q->grabChanged(grabber, QPointingDevice::UngrabPassive, event, point);
+ persistentPoint->passiveGrabbers.removeAt(i);
+ if (persistentPoint->passiveGrabbersContext.size()) {
+ Q_ASSERT(persistentPoint->passiveGrabbersContext.size() > i);
+ persistentPoint->passiveGrabbersContext.removeAt(i);
+ }
+ return true;
+ }
+ return false;
+}
+
+void QPointingDevicePrivate::clearPassiveGrabbers(const QPointerEvent *event, const QEventPoint &point)
+{
+ Q_Q(QPointingDevice);
+ auto persistentPoint = queryPointById(point.id());
+ if (!persistentPoint) {
+ qWarning() << "point is not in activePoints" << point;
+ return;
+ }
+ if (persistentPoint->passiveGrabbers.isEmpty())
+ return;
+ if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
+ qCDebug(lcPointerGrab) << name << "point" << point.id() << point.state()
+ << ": clearing" << persistentPoint->passiveGrabbers;
+ }
+ for (auto g : persistentPoint->passiveGrabbers)
+ emit q->grabChanged(g, QPointingDevice::UngrabPassive, event, point);
+ persistentPoint->passiveGrabbers.clear();
+ persistentPoint->passiveGrabbersContext.clear();
+}
+
+/*!
+ \internal
+ Removes the given \a grabber as both passive and exclusive grabber from all
+ points in activePoints where it's currently found. If \a cancel is \c true,
+ the transition emitted from the grabChanged() signal will be
+ \c CancelGrabExclusive or \c CancelGrabPassive. Otherwise it will be
+ \c UngrabExclusive or \c UngrabPassive.
+
+ \note This function provides a way to work around the limitation that we
+ normally change grabbers only during event delivery; but it's also more expensive.
+*/
+void QPointingDevicePrivate::removeGrabber(QObject *grabber, bool cancel)
+{
+ Q_Q(QPointingDevice);
+ for (auto ap : activePoints) {
+ auto &epd = ap.second;
+ if (epd.exclusiveGrabber.data() == grabber) {
+ qCDebug(lcPointerGrab) << name << "point" << epd.eventPoint.id() << epd.eventPoint.state()
+ << "@" << epd.eventPoint.scenePosition()
+ << ": grab" << grabber << "-> nullptr";
+ epd.exclusiveGrabber.clear();
+ epd.exclusiveGrabberContext.clear();
+ emit q->grabChanged(grabber,
+ cancel ? QPointingDevice::CancelGrabExclusive : QPointingDevice::UngrabExclusive,
+ nullptr, epd.eventPoint);
+ }
+ qsizetype pi = epd.passiveGrabbers.indexOf(grabber);
+ if (pi >= 0) {
+ qCDebug(lcPointerGrab) << name << "point" << epd.eventPoint.id() << epd.eventPoint.state()
+ << ": removing passive grabber" << grabber;
+ epd.passiveGrabbers.removeAt(pi);
+ if (epd.passiveGrabbersContext.size()) {
+ Q_ASSERT(epd.passiveGrabbersContext.size() > pi);
+ epd.passiveGrabbersContext.removeAt(pi);
+ }
+ emit q->grabChanged(grabber,
+ cancel ? QPointingDevice::CancelGrabPassive : QPointingDevice::UngrabPassive,
+ nullptr, epd.eventPoint);
+ }
+ }
+}
+
+/*!
+ \internal
Finds the device instance belonging to the drawing or eraser end of a particular stylus,
identified by its \a deviceType, \a pointerType and \a uniqueId. If an existing device
is not found, a new one is created and registered, with a warning.
@@ -398,9 +680,9 @@ const QPointingDevice *QPointingDevicePrivate::tabletDevice(QInputDevice::Device
<< deviceType << pointerType << Qt::hex << uniqueId.numericId()
<< "The platform plugin should have provided one via "
"QWindowSystemInterface::registerInputDevice(). Creating a default one for now.";
- dev = new QPointingDevice(QLatin1String("fake tablet"), 2, deviceType, pointerType,
- QInputDevice::Capability::Position | QInputDevice::Capability::Pressure,
- 1, 1, QString(), uniqueId, QCoreApplication::instance());
+ dev = new QPointingDevice("fake tablet"_L1, 2, deviceType, pointerType,
+ QInputDevice::Capability::Position | QInputDevice::Capability::Pressure,
+ 1, 1, QString(), uniqueId, QCoreApplication::instance());
QInputDevicePrivate::registerDevice(dev);
}
return dev;
@@ -424,16 +706,23 @@ QDebug operator<<(QDebug debug, const QPointingDevice *device)
debug.noquote();
debug << "QPointingDevice(";
if (device) {
- debug << '"' << device->name() << "\", type=";
+ debug << '"' << device->name() << "\" ";
QtDebugUtils::formatQEnum(debug, device->type());
- debug << ", id=" << Qt::hex << device->systemId() << Qt::dec << ", seat=" << device->seatName();
- debug << ", pointerType=";
- QtDebugUtils::formatQEnum(debug, device->pointerType());
- debug << ", capabilities=";
- QtDebugUtils::formatQFlags(debug, device->capabilities());
- debug << ", maximumTouchPoints=" << device->maximumPoints();
- if (device->uniqueId().numericId())
- debug << ", uniqueId=" << Qt::hex << device->uniqueId().numericId() << Qt::dec;
+ debug << " id=" << device->systemId();
+ if (!device->seatName().isEmpty())
+ debug << " seat=" << device->seatName();
+ if (device->pointerType() != QPointingDevice::PointerType::Generic) {
+ debug << " ptrType=";
+ QtDebugUtils::formatQEnum(debug, device->pointerType());
+ }
+ if (int(device->capabilities()) != int(QInputDevice::Capability::Position)) {
+ debug << " caps=";
+ QtDebugUtils::formatQFlags(debug, device->capabilities());
+ }
+ if (device->maximumPoints() > 1)
+ debug << " maxPts=" << device->maximumPoints();
+ if (device->uniqueId().isValid())
+ debug << " uniqueId=" << Qt::hex << device->uniqueId().numericId() << Qt::dec;
} else {
debug << '0';
}
@@ -442,4 +731,93 @@ QDebug operator<<(QDebug debug, const QPointingDevice *device)
}
#endif // !QT_NO_DEBUG_STREAM
+/*!
+ \class QPointingDeviceUniqueId
+ \since 5.8
+ \ingroup events
+ \inmodule QtGui
+
+ \brief QPointingDeviceUniqueId identifies a unique object, such as a tagged token
+ or stylus, which is used with a pointing device.
+
+ QPointingDeviceUniqueIds can be compared for equality, and can be used as keys in a QHash.
+ You get access to the numerical ID via numericId(), if the device supports such IDs.
+ For future extensions, though, you should not use that function, but compare objects
+ of this type using the equality operator.
+
+ This class is a thin wrapper around an integer ID. You pass it into and out of
+ functions by value.
+
+ \sa QEventPoint
+*/
+
+/*!
+ \fn QPointingDeviceUniqueId::QPointingDeviceUniqueId()
+ Constructs an invalid unique pointer ID.
+*/
+
+/*!
+ Constructs a unique pointer ID from numeric ID \a id.
+*/
+QPointingDeviceUniqueId QPointingDeviceUniqueId::fromNumericId(qint64 id)
+{
+ QPointingDeviceUniqueId result;
+ result.m_numericId = id;
+ return result;
+}
+
+/*!
+ \fn bool QPointingDeviceUniqueId::isValid() const
+
+ Returns whether this unique pointer ID is valid, that is, it represents an actual
+ pointer.
+*/
+
+/*!
+ \property QPointingDeviceUniqueId::numericId
+ \brief the numeric unique ID of the token represented by a touchpoint
+
+ If the device provides a numeric ID, isValid() returns true, and this
+ property provides the numeric ID;
+ otherwise it is -1.
+
+ You should not use the value of this property in portable code, but
+ instead rely on equality to identify pointers.
+
+ \sa isValid()
+*/
+qint64 QPointingDeviceUniqueId::numericId() const noexcept
+{
+ return m_numericId;
+}
+
+/*!
+ \fn bool QPointingDeviceUniqueId::operator==(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs)
+ \since 5.8
+
+ Returns whether the two unique pointer IDs \a lhs and \a rhs identify the same pointer
+ (\c true) or not (\c false).
+*/
+
+/*!
+ \fn bool QPointingDeviceUniqueId::operator!=(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs)
+ \since 5.8
+
+ Returns whether the two unique pointer IDs \a lhs and \a rhs identify different pointers
+ (\c true) or not (\c false).
+*/
+
+/*!
+ \relates QPointingDeviceUniqueId
+ \since 5.8
+
+ Returns the hash value for \a key, using \a seed to seed the calculation.
+*/
+size_t qHash(QPointingDeviceUniqueId key, size_t seed) noexcept
+{
+ return qHash(key.numericId(), seed);
+}
+
QT_END_NAMESPACE
+
+#include "moc_qpointingdevice.cpp"