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.cpp425
1 files changed, 425 insertions, 0 deletions
diff --git a/src/gui/kernel/qpointingdevice.cpp b/src/gui/kernel/qpointingdevice.cpp
new file mode 100644
index 0000000000..b56c83efc4
--- /dev/null
+++ b/src/gui/kernel/qpointingdevice.cpp
@@ -0,0 +1,425 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qpointingdevice.h"
+#include "qpointingdevice_p.h"
+#include <QList>
+#include <QLoggingCategory>
+#include <QMutex>
+#include <QCoreApplication>
+
+#include <private/qdebug_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcQpaInputDevices)
+
+/*!
+ \class QPointingDevice
+ \brief The QPointingDevice class describes a device from which mouse, touch or tablet events originate.
+ \since 6.0
+ \ingroup events
+ \inmodule QtGui
+
+ Each QPointerEvent contains a QPointingDevice pointer to allow accessing
+ device-specific properties like type and capabilities. It is the
+ responsibility of the platform or generic plug-ins to register the
+ available pointing devices via QWindowSystemInterface before generating any
+ pointer events. Applications do not need to instantiate this class, they
+ should just access the global instances pointed to by QPointerEvent::device().
+*/
+
+/*! \enum QInputDevice::DeviceType
+
+ This enum represents the type of device that generated a QPointerEvent.
+
+ \value Unknown
+ The device cannot be identified.
+
+ \value Mouse
+ A mouse.
+
+ \value TouchScreen
+ In this type of device, the touch surface and display are integrated.
+ This means the surface and display typically have the same size, such
+ that there is a direct relationship between the touch points' physical
+ positions and the coordinate reported by QTouchEvent::TouchPoint. As a
+ result, Qt allows the user to interact directly with multiple QWidgets,
+ QGraphicsItems, or Qt Quick Items at the same time.
+
+ \value TouchPad
+ In this type of device, the touch surface is separate from the display.
+ There is not a direct relationship between the physical touch location
+ and the on-screen coordinates. Instead, they are calculated relative to
+ the current mouse position, and the user must use the touch-pad to move
+ this reference point. Unlike touch-screens, Qt allows users to only
+ interact with a single QWidget or QGraphicsItem at a time.
+
+ \value Stylus
+ A pen-like device used on a graphics tablet such as a Wacom tablet,
+ or on a touchscreen that provides a separate stylus sensing capability.
+
+ \value Airbrush
+ A stylus with a thumbwheel to adjust
+ \l {QTabletEvent::tangentialPressure}{tangentialPressure}.
+
+ \value Puck
+ A device that is similar to a flat mouse with a transparent circle with
+ cross-hairs.
+
+ \value AllDevices
+ Any of the above (used as a default filter value).
+*/
+
+/*! \enum QPointingDevice::PointerType
+
+ This enum represents what is interacting with the pointing device.
+
+ There is some redundancy between this property and \l {QInputDevice::DeviceType}.
+ For example, if a touchscreen is used, then the \c DeviceType is
+ \c TouchScreen and \c PointerType is \c Finger (always). But on a graphics
+ tablet, it's often possible for both ends of the stylus to be used, and
+ programs need to distinguish them. Therefore the concept is extended so
+ that every QPointerEvent has a PointerType, and it can simplify some event
+ handling code to ignore the DeviceType and react differently depending on
+ the PointerType alone.
+
+ Valid values are:
+
+ \value Unknown
+ The pointer type is unknown.
+ \value Generic
+ A mouse or something acting like a mouse (the core pointer on X11).
+ \value Finger
+ The user's finger.
+ \value Pen
+ The drawing end of a stylus.
+ \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.
+ \value AllPointerTypes
+ Any of the above (used as a default filter value).
+*/
+
+/*! \enum QPointingDevice::Capability
+
+ This enum is used with QPointingDevice::capabilities() to indicate what kind of information the
+ touch device or its driver can provide.
+
+ \value Position
+ Indicates that position information is available, meaning that the
+ pos() family of functions in the touch points return valid points.
+
+ \value Area
+ Indicates that touch area information is available, meaning that the
+ rect() family of functions in the touch points return valid rectangles.
+
+ \value Pressure
+ Indicates that pressure information is available, meaning that
+ QPointerEvent::EventPoint::pressure() returns a valid value.
+
+ \value Velocity
+ Indicates that velocity information is available, meaning that
+ QPointerEvent::EventPoint::velocity() returns a valid vector.
+
+ \value RawPositions
+ Indicates that the list returned by
+ QPointerEvent::EventPoint::rawScreenPositions() may contain one or more
+ positions for each touch point. This is relevant when the touch input
+ gets filtered or corrected on the driver level.
+
+ \value NormalizedPosition
+ Indicates that the normalized position is available, meaning that
+ QPointerEvent::EventPoint::normalizedPos() returns a valid value.
+
+ \value MouseEmulation
+ Indicates that the device synthesizes mouse events.
+*/
+
+/*!
+ Creates a new invalid pointing device instance.
+*/
+QPointingDevice::QPointingDevice()
+ : QInputDevice(*(new QPointingDevicePrivate(QLatin1String("unknown"), -1,
+ DeviceType::Unknown, PointerType::Unknown,
+ Capability::None, 0, 0)))
+{
+}
+
+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.
+*/
+QPointingDevice::QPointingDevice(const QString &name, qint64 id, QInputDevice::DeviceType deviceType,
+ QPointingDevice::PointerType pointerType, Capabilities capabilities, int maxPoints, int buttonCount,
+ const QString &seatName, QPointingDeviceUniqueId uniqueId, QObject *parent)
+ : QInputDevice(*(new QPointingDevicePrivate(name, id, deviceType, pointerType, capabilities, maxPoints, buttonCount, seatName, uniqueId)), parent)
+{
+}
+
+/*!
+ \internal
+*/
+QPointingDevice::QPointingDevice(QPointingDevicePrivate &d, QObject *parent)
+ : QInputDevice(d, parent)
+{
+}
+
+/*!
+ \internal
+ \deprecated Please use the constructor rather than setters.
+
+ Sets the device type \a devType and infers the pointer type.
+*/
+void QPointingDevice::setType(DeviceType devType)
+{
+ Q_D(QPointingDevice);
+ d->deviceType = devType;
+ if (d->pointerType == PointerType::Unknown)
+ switch (devType) {
+ case DeviceType::Mouse:
+ d->pointerType = PointerType::Generic;
+ break;
+ case DeviceType::TouchScreen:
+ case DeviceType::TouchPad:
+ d->pointerType = PointerType::Finger;
+ break;
+ case DeviceType::Puck:
+ d->pointerType = PointerType::Cursor;
+ break;
+ case DeviceType::Stylus:
+ case DeviceType::Airbrush:
+ d->pointerType = PointerType::Pen;
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ \internal
+ \deprecated Please use the constructor rather than setters.
+*/
+void QPointingDevice::setCapabilities(QInputDevice::Capabilities caps)
+{
+ Q_D(QPointingDevice);
+ d->capabilities = caps;
+}
+
+/*!
+ \internal
+ \deprecated Please use the constructor rather than setters.
+*/
+void QPointingDevice::setMaximumTouchPoints(int c)
+{
+ Q_D(QPointingDevice);
+ d->maximumTouchPoints = c;
+}
+
+/*!
+ Returns the pointer type.
+*/
+QPointingDevice::PointerType QPointingDevice::pointerType() const
+{
+ Q_D(const QPointingDevice);
+ return d->pointerType;
+}
+
+/*!
+ Returns the maximum number of simultaneous touch points (fingers) that
+ can be detected.
+*/
+int QPointingDevice::maximumPoints() const
+{
+ Q_D(const QPointingDevice);
+ return d->maximumTouchPoints;
+}
+
+/*!
+ Returns the maximum number of on-device buttons that can be detected.
+*/
+int QPointingDevice::buttonCount() const
+{
+ Q_D(const QPointingDevice);
+ return d->buttonCount;
+}
+
+/*!
+ Returns a unique ID (of dubious utility) for the device.
+
+ You probably should rather be concerned with QPointerEventPoint::uniqueId().
+*/
+QPointingDeviceUniqueId QPointingDevice::uniqueId() const
+{
+ Q_D(const QPointingDevice);
+ return d->uniqueId;
+}
+
+/*!
+ Returns the primary pointing device (the core pointer, traditionally
+ assumed to be a mouse) on the given seat \a seatName.
+
+ If multiple pointing devices are registered, this function prefers a
+ mouse, touchpad, or touchscreen (in that order) that matches the given
+ \a seatName and that does not have another device as its parent.
+ Usually only one master or core device does not have a parent device.
+*/
+const QPointingDevice *QPointingDevice::primaryPointingDevice(const QString& seatName)
+{
+ const auto v = devices();
+ const QPointingDevice *mouse = nullptr;
+ const QPointingDevice *touchpad = nullptr;
+ const QPointingDevice *touchscreen = nullptr;
+ for (const QInputDevice *dev : v) {
+ if (dev->seatName() != seatName)
+ continue;
+ if (dev->type() == QInputDevice::DeviceType::Mouse) {
+ if (!mouse)
+ mouse = static_cast<const QPointingDevice *>(dev);
+ // the core pointer is likely a mouse, and its parent is not another input device
+ if (!mouse->parent() || !qobject_cast<const QInputDevice *>(mouse->parent()))
+ return mouse;
+ } else if (dev->type() == QInputDevice::DeviceType::TouchPad) {
+ if (!touchpad || !dev->parent() || dev->parent()->metaObject() != dev->metaObject())
+ touchpad = static_cast<const QPointingDevice *>(dev);
+ } else if (dev->type() == QInputDevice::DeviceType::TouchScreen) {
+ if (!touchscreen || !dev->parent() || dev->parent()->metaObject() != dev->metaObject())
+ touchscreen = static_cast<const QPointingDevice *>(dev);
+ }
+ }
+ if (!mouse && !touchpad && !touchscreen) {
+ qWarning() << "no pointing 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,
+ PointerType::Generic, Capability::Position, 1, 3, seatName);
+ QInputDevicePrivate::registerDevice(mouse);
+ return mouse;
+ }
+ if (v.length() > 1)
+ qCWarning(lcQpaInputDevices) << "core pointer ambiguous for seat" << seatName;
+ if (mouse)
+ return mouse;
+ if (touchpad)
+ return touchpad;
+ return touchscreen;
+}
+
+/*!
+ 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. The given \a busId
+ may be used to update the stored USB ID, if it was not known before.
+*/
+const QPointingDevice *QPointingDevice::tabletDevice(QInputDevice::DeviceType deviceType,
+ QPointingDevice::PointerType pointerType,
+ QPointingDeviceUniqueId uniqueId, quint32 busId)
+{
+ const QVector<const QInputDevice *> devices = QInputDevice::devices();
+ for (const QInputDevice *dev : devices) {
+ if (dev->type() < DeviceType::Puck || dev->type() > DeviceType::Airbrush)
+ continue;
+ const QPointingDevice *pdev = static_cast<const QPointingDevice *>(dev);
+ const auto devPriv = QPointingDevicePrivate::get(pdev);
+ bool uniqueIdDiscovered = (devPriv->uniqueId.numericId() == 0 && uniqueId.numericId() != 0);
+ if (devPriv->deviceType == deviceType && devPriv->pointerType == pointerType &&
+ (devPriv->uniqueId == uniqueId || uniqueIdDiscovered)) {
+ if (uniqueIdDiscovered) {
+ const_cast<QPointingDevicePrivate *>(devPriv)->uniqueId = uniqueId;
+ qCDebug(lcQpaInputDevices) << "discovered unique ID of tablet tool" << pdev;
+ }
+ if (devPriv->busId.isEmpty() && busId) {
+ const_cast<QPointingDevicePrivate *>(devPriv)->busId = QString::number(busId, 16);
+ qCDebug(lcQpaInputDevices) << "discovered USB ID" << devPriv->busId << "of" << pdev;
+ }
+ return pdev;
+ }
+ }
+ qWarning() << "failed to find registered tablet device" << deviceType << pointerType << Qt::hex << uniqueId.numericId()
+ << "The platform plugin should have provided one via "
+ "QWindowSystemInterface::registerInputDevice(). Creating a default one for now.";
+ QPointingDevice *dev = new QPointingDevice(QLatin1String("fake tablet"), 2, deviceType, pointerType,
+ QInputDevice::Capability::Position | QInputDevice::Capability::Pressure,
+ 1, 1, QString(), uniqueId);
+ QInputDevicePrivate::registerDevice(dev);
+ return dev;
+}
+
+bool QPointingDevice::operator==(const QPointingDevice &other) const
+{
+ // Wacom tablets generate separate instances for each end of each stylus;
+ // QInputDevice::operator==() says they are all the same, but we use
+ // the stylus unique serial number and pointerType to distinguish them
+ return QInputDevice::operator==(other) &&
+ pointerType() == other.pointerType() &&
+ uniqueId() == other.uniqueId();
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QPointingDevice *device)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug.noquote();
+ debug << "QPointingDevice(";
+ if (device) {
+ debug << '"' << device->name() << "\", type=";
+ QtDebugUtils::formatQEnum(debug, device->type());
+ debug << "id=" << Qt::hex << device->id() << 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;
+ } else {
+ debug << '0';
+ }
+ debug << ')';
+ return debug;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+QT_END_NAMESPACE