Coverage Report

Created: 2026-01-25 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/kernel/qinputdevice.cpp
Line
Count
Source
1
// Copyright (C) 2020 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4
#include "qinputdevice.h"
5
#include "qinputdevice_p.h"
6
#include "qpointingdevice.h"
7
#include "qwindowsysteminterface_p.h"
8
#include <QCoreApplication>
9
#include <QDebug>
10
#include <QMutex>
11
#include <QScreen>
12
13
QT_BEGIN_NAMESPACE
14
15
using namespace Qt::StringLiterals;
16
17
/*!
18
    \class QInputDevice
19
    \brief The QInputDevice class describes a device from which a QInputEvent originates.
20
    \since 6.0
21
    \inmodule QtGui
22
23
    Each QInputEvent contains a QInputDevice pointer to allow accessing
24
    device-specific properties like type, capabilities and seat. It is the
25
    responsibility of the platform or generic plug-ins to discover, create and
26
    register an instance of this class corresponding to each available input
27
    device, via QWindowSystemInterface::registerInputDevice(), before
28
    generating any input event referring to that device.
29
30
    Applications do not need to instantiate this class, but can read the
31
    instances pointed to by QInputEvent::device() and QInputDevice::devices().
32
*/
33
34
/*!
35
    \enum QInputDevice::Capability
36
37
    Indicates what kind of information the input device or its driver can
38
    provide.
39
40
    \value None
41
           No information about input device capabilities available.
42
43
    \value Position
44
           Indicates that position information is available, meaning that the
45
           position() family of functions in the touch points return valid points.
46
47
    \value Area
48
           Indicates that touch area information is available, meaning that
49
           QEventPoint::ellipseDiameters() in the touch points return valid
50
           values.
51
52
    \value Pressure
53
           Indicates that pressure information is available, meaning that
54
           QEventPoint::pressure() returns a valid value.
55
56
    \value Velocity
57
           Indicates that velocity information is available, meaning that
58
           QEventPoint::velocity() returns a valid vector.
59
60
    \value NormalizedPosition
61
           Indicates that the normalized position is available, meaning that
62
           QEventPoint::globalPosition() returns a valid value.
63
64
    \value MouseEmulation
65
           Indicates that the device synthesizes mouse events.
66
67
    \value Scroll
68
           Indicates that the device has a scroll capability.
69
70
    \value [since 6.2] PixelScroll
71
           Indicates that the device (usually a
72
           \l {QInputDevice::DeviceType::TouchPad}{touchpad})
73
           scrolls with \l {QWheelEvent::pixelDelta()}{pixel precision}.
74
75
    \value Hover
76
           Indicates that the device has a hover capability.
77
78
    \value Rotation
79
           Indicates that \l {QEventPoint::}{rotation} information is available.
80
81
    \value XTilt
82
           Indicates that \l {QTabletEvent::xTilt()}{tilt} information is
83
           available for the X-axis.
84
85
    \value YTilt
86
           Indicates that \l {QTabletEvent::yTilt()}{tilt} information is
87
           available for the Y-axis.
88
89
    \value TangentialPressure
90
           Indicates that \l {QTabletEvent::tangentialPressure()}
91
           {tangential pressure} information is  available.
92
93
    \value ZPosition
94
           Indicates that position information for the \l {QTabletEvent::z()}
95
           {Z-axis} is available.
96
97
    \value All
98
*/
99
100
/*!
101
    Creates a new invalid input device instance as a child of \a parent.
102
*/
103
QInputDevice::QInputDevice(QObject *parent)
104
0
    : QObject(*(new QInputDevicePrivate(QString(), -1, QInputDevice::DeviceType::Unknown)), parent)
105
0
{
106
0
}
107
108
QInputDevice::~QInputDevice()
109
0
{
110
0
    QInputDevicePrivate::unregisterDevice(this);
111
0
}
112
113
/*!
114
    Creates a new input device instance. The given \a name is normally a
115
    manufacturer-assigned model name if available, or something else
116
    identifiable; \a id is a platform-specific number that will be unique per
117
    device (for example the xinput ID on X11); \a type identifies what kind of
118
    device. On window systems that are capable of handling input from multiple
119
    users or sets of input devices at the same time (such as Wayland or X11),
120
    \a seatName identifies the name of the set of devices that will be used
121
    together. If the device is a child or slave device (for example one of
122
    several mice that can take turns moving the "core pointer"), the master
123
    device should be given as the \a parent.
124
125
    The platform plugin creates, registers and continues to own each device
126
    instance; usually \a parent should be given for memory management purposes
127
    even if there is no master for a particular device.
128
129
    By default, capabilities() are \c None.
130
*/
131
QInputDevice::QInputDevice(const QString &name, qint64 id, QInputDevice::DeviceType type,
132
                           const QString &seatName, QObject *parent)
133
0
    : QObject(*new QInputDevicePrivate(name, id, type, QInputDevice::Capability::None, seatName), parent)
134
0
{
135
0
}
136
137
/*!
138
    \internal
139
*/
140
QInputDevice::QInputDevice(QInputDevicePrivate &d, QObject *parent)
141
0
    : QObject(d, parent)
142
0
{
143
0
}
144
145
/*!
146
    \property QInputDevice::availableVirtualGeometry
147
    \brief the region within the virtual desktop that this device can access.
148
149
    For example, a \l {QInputDevice::DeviceType}{TouchScreen} input
150
    device is fixed in place upon a single physical screen and usually
151
    calibrated so that this area is the same as QScreen::geometry(), whereas
152
    a \l {QInputDevice::DeviceType}{Mouse} is typically able to access all
153
    screens on the virtual desktop.
154
155
    Alternatively, a Wacom graphics tablet may be configured so that it is
156
    mapped to all screens, or only to the screen where the user prefers to
157
    create drawings, or only to the window in which drawing occurs.
158
159
    A \l {QInputDevice::DeviceType}{Stylus} device that is integrated
160
    with a touchscreen may be physically limited to that screen.
161
162
    If the returned rectangle is \l {QRect::isNull()}{null}, it means this device
163
    can access the entire virtual desktop.
164
*/
165
QRect QInputDevice::availableVirtualGeometry() const
166
0
{
167
0
    Q_D(const QInputDevice);
168
0
    return d->availableVirtualGeometry;
169
0
}
170
171
/*!
172
    \property QInputDevice::name
173
    \brief the device name.
174
*/
175
176
/*!
177
    Returns the device name.
178
179
    This string may be empty. It is however useful on systems that have
180
    multiple input devices: it can be used to differentiate from which device a
181
    QPointerEvent originates.
182
*/
183
QString QInputDevice::name() const
184
0
{
185
0
    Q_D(const QInputDevice);
186
0
    return d->name;
187
0
}
188
189
/*!
190
    \property QInputDevice::type
191
    \brief the device type
192
*/
193
194
/*!
195
    Returns the device type.
196
*/
197
QInputDevice::DeviceType QInputDevice::type() const
198
0
{
199
0
    Q_D(const QInputDevice);
200
0
    return d->deviceType;
201
0
}
202
203
/*!
204
    \property QInputDevice::capabilities
205
    \brief the device capabilities.
206
*/
207
208
/*!
209
    Returns the device capabilities.
210
*/
211
QInputDevice::Capabilities QInputDevice::capabilities() const
212
0
{
213
0
    Q_D(const QInputDevice);
214
0
    return QInputDevice::Capabilities(d->capabilities);
215
0
}
216
217
/*!
218
    Returns whether the device capabilities include the given \a capability.
219
*/
220
bool QInputDevice::hasCapability(QInputDevice::Capability capability) const
221
0
{
222
0
    return capabilities().testFlag(capability);
223
0
}
224
225
/*!
226
    \property QInputDevice::systemId
227
    \brief the platform-specific system ID.
228
*/
229
230
/*!
231
    Returns the platform specific system ID (for example xinput ID on the X11 platform).
232
233
    All platforms are expected to provide a unique system ID for each device.
234
*/
235
qint64 QInputDevice::systemId() const
236
0
{
237
0
    Q_D(const QInputDevice);
238
0
    return d->systemId;
239
0
}
240
241
/*!
242
    \property QInputDevice::seatName
243
    \brief the seat associated with the device.
244
*/
245
246
/*!
247
    Returns the seat with which the device is associated, if known; otherwise empty.
248
249
    Devices that are intended to be used together by one user may be configured
250
    to have the same seat name. That is only possible on Wayland and X11
251
    platforms so far.
252
*/
253
QString QInputDevice::seatName() const
254
0
{
255
0
    Q_D(const QInputDevice);
256
0
    return d->seatName;
257
0
}
258
259
using InputDevicesList = QList<const QInputDevice *>;
260
Q_GLOBAL_STATIC(InputDevicesList, deviceList)
261
Q_CONSTINIT static QBasicMutex devicesMutex;
262
263
/*!
264
    Returns a list of all registered input devices (keyboards and pointing devices).
265
266
    \note The list of devices is not always complete on all platforms. So far,
267
    the most-complete information is available on the \l {Qt for Linux/X11}{X11}
268
    platform, at startup and in response to hot-plugging. Most other platforms
269
    are only able to provide generic devices of various types, only after receiving
270
    events from them; and most platforms do not tell Qt when a device is plugged in,
271
    or when it is unplugged at runtime.
272
273
    \note The returned list cannot be used to add new devices. To add a simulated
274
    touch screen for an autotest, QTest::createTouchDevice() can be used.
275
    Platform plugins should call QWindowSystemInterface::registerInputDevice()
276
    to add devices as they are discovered.
277
*/
278
QList<const QInputDevice *> QInputDevice::devices()
279
0
{
280
0
    QMutexLocker lock(&devicesMutex);
281
0
    return *deviceList();
282
0
}
283
284
/*!
285
    \since 6.3
286
287
    Returns a list of seat names for all registered input devices (keyboards and pointing devices).
288
*/
289
QStringList QInputDevice::seatNames()
290
0
{
291
0
    QMutexLocker locker(&devicesMutex);
292
0
    const InputDevicesList devices = *deviceList();
293
0
    locker.unlock();
294
0
    QStringList result;
295
0
    for (const QInputDevice *d : devices) {
296
0
        if (!result.contains(d->seatName()))
297
0
            result.append(d->seatName());
298
0
    }
299
300
0
    return result;
301
0
}
302
303
/*!
304
    Returns the core or master keyboard on the given seat \a seatName.
305
*/
306
const QInputDevice *QInputDevice::primaryKeyboard(const QString& seatName)
307
0
{
308
0
    QMutexLocker locker(&devicesMutex);
309
0
    const InputDevicesList devices = *deviceList();
310
0
    locker.unlock();
311
0
    const QInputDevice *ret = nullptr;
312
0
    for (const QInputDevice *d : devices) {
313
0
        if (d->type() != DeviceType::Keyboard)
314
0
            continue;
315
0
        if (seatName.isNull() || d->seatName() == seatName) {
316
            // the master keyboard's parent is not another input device
317
0
            if (!d->parent() || !qobject_cast<const QInputDevice *>(d->parent()))
318
0
                return d;
319
0
            if (!ret)
320
0
                ret = d;
321
0
        }
322
0
    }
323
0
    if (!ret) {
324
0
        qCDebug(lcQpaInputDevices) << "no keyboards registered for seat" << seatName
325
0
                                   << "The platform plugin should have provided one via "
326
0
                                      "QWindowSystemInterface::registerInputDevice(). Creating a default one for now.";
327
0
        ret = new QInputDevice("core keyboard"_L1, 0, DeviceType::Keyboard, seatName, QCoreApplication::instance());
328
0
        QInputDevicePrivate::registerDevice(ret);
329
0
        return ret;
330
0
    }
331
0
    qWarning() << "core keyboard ambiguous for seat" << seatName;
332
0
    return ret;
333
0
}
334
335
0
QInputDevicePrivate::~QInputDevicePrivate()
336
    = default;
337
338
/*!
339
    \internal
340
    Checks whether a matching device is already registered
341
    (via operator==, not pointer equality).
342
*/
343
bool QInputDevicePrivate::isRegistered(const QInputDevice *dev)
344
0
{
345
0
    if (!dev)
346
0
        return false;
347
0
    QMutexLocker locker(&devicesMutex);
348
0
    InputDevicesList v = *deviceList();
349
0
    for (const QInputDevice *d : v)
350
0
        if (d && *d == *dev)
351
0
            return true;
352
0
    return false;
353
0
}
354
355
/*!
356
    \internal
357
    Find the device with the given \a systemId (for example the xinput
358
    device ID on X11), which is expected to be unique if nonzero.
359
360
    If the \a systemId is not unique, this function returns the first one found.
361
362
    \note Use QInputDevicePrivate::queryTabletDevice() if the device is a
363
    tablet or a tablet stylus; in that case, \a id is not unique.
364
*/
365
const QInputDevice *QInputDevicePrivate::fromId(qint64 systemId)
366
0
{
367
0
    QMutexLocker locker(&devicesMutex);
368
0
    for (const QInputDevice *dev : *deviceList()) {
369
0
        if (dev->systemId() == systemId)
370
0
            return dev;
371
0
    }
372
0
    return nullptr;
373
0
}
374
375
void QInputDevicePrivate::registerDevice(const QInputDevice *dev)
376
0
{
377
0
    QMutexLocker lock(&devicesMutex);
378
0
    deviceList()->append(dev);
379
0
    qCInfo(lcQpaInputDevices) << "Registered" << dev;
380
0
}
381
382
/*!
383
    \internal
384
*/
385
void QInputDevicePrivate::unregisterDevice(const QInputDevice *dev)
386
0
{
387
0
    if (deviceList.isDestroyed())
388
0
        return;     // nothing to remove!
389
390
0
    QMutexLocker lock(&devicesMutex);
391
0
    deviceList()->removeOne(dev);
392
0
    qCInfo(lcQpaInputDevices) << "Unregistered" << dev;
393
0
}
394
395
bool QInputDevice::operator==(const QInputDevice &other) const
396
0
{
397
0
    return systemId() == other.systemId();
398
0
}
399
400
#ifndef QT_NO_DEBUG_STREAM
401
QDebug operator<<(QDebug debug, const QInputDevice *device)
402
0
{
403
0
    QDebugStateSaver saver(debug);
404
0
    debug.nospace();
405
0
    debug.noquote();
406
407
0
    debug << "QInputDevice(";
408
0
    if (!device)
409
0
        return debug << "0x0)";
410
411
0
    const QInputDevicePrivate *d = QInputDevicePrivate::get(device);
412
413
0
    if (d->pointingDeviceType)
414
0
        return operator<<(debug, static_cast<const QPointingDevice *>(device));
415
416
0
    debug << "QInputDevice(";
417
0
    debug << '"' << device->name() << "\", type=" << device->type()
418
0
          << ", ID=" << device->systemId() << ", seat='" << device->seatName() << "'";
419
0
    debug << ')';
420
0
    return debug;
421
0
}
422
#endif // !QT_NO_DEBUG_STREAM
423
424
QT_END_NAMESPACE
425
426
#include "moc_qinputdevice.cpp"