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
13QT_BEGIN_NAMESPACE
14
15using 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*/
103QInputDevice::QInputDevice(QObject *parent)
104 : QObject(*(new QInputDevicePrivate(QString(), -1, QInputDevice::DeviceType::Unknown)), parent)
105{
106}
107
108QInputDevice::~QInputDevice()
109{
110 QInputDevicePrivate::unregisterDevice(dev: this);
111}
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*/
131QInputDevice::QInputDevice(const QString &name, qint64 id, QInputDevice::DeviceType type,
132 const QString &seatName, QObject *parent)
133 : QObject(*new QInputDevicePrivate(name, id, type, QInputDevice::Capability::None, seatName), parent)
134{
135}
136
137/*!
138 \internal
139*/
140QInputDevice::QInputDevice(QInputDevicePrivate &d, QObject *parent)
141 : QObject(d, parent)
142{
143}
144
145/*!
146 Returns the region within the \l{QScreen::availableVirtualGeometry}{virtual desktop}
147 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 a
152 \l {QInputDevice::DeviceType}{Mouse} can probably access all screens
153 on the virtual desktop. A Wacom graphics tablet may be configured in a way
154 that it's mapped to all screens, or only to the screen where the user
155 prefers to create drawings, or to the window in which drawing occurs.
156 A \l {QInputDevice::DeviceType}{Stylus} device that is integrated
157 with a touchscreen may be physically limited to that screen.
158
159 If the returned rectangle is \l {QRect::isNull()}{null}, it means this device
160 can access the entire virtual desktop.
161*/
162QRect QInputDevice::availableVirtualGeometry() const
163{
164 Q_D(const QInputDevice);
165 return d->availableVirtualGeometry;
166}
167
168/*!
169 Returns the device name.
170
171 This string may be empty. It is however useful on systems that have
172 multiple input devices: it can be used to differentiate from which device a
173 QPointerEvent originates.
174*/
175QString QInputDevice::name() const
176{
177 Q_D(const QInputDevice);
178 return d->name;
179}
180
181/*!
182 Returns the device type.
183*/
184QInputDevice::DeviceType QInputDevice::type() const
185{
186 Q_D(const QInputDevice);
187 return d->deviceType;
188}
189
190/*!
191 Returns the device capabilities.
192*/
193QInputDevice::Capabilities QInputDevice::capabilities() const
194{
195 Q_D(const QInputDevice);
196 return QInputDevice::Capabilities(d->capabilities);
197}
198
199/*!
200 Returns whether the device capabilities include the given \a capability.
201*/
202bool QInputDevice::hasCapability(QInputDevice::Capability capability) const
203{
204 return capabilities().testFlag(flag: capability);
205}
206
207/*!
208 Returns the platform specific system ID (for example xinput ID on the X11 platform).
209
210 All platforms are expected to provide a unique system ID for each device.
211*/
212qint64 QInputDevice::systemId() const
213{
214 Q_D(const QInputDevice);
215 return d->systemId;
216}
217
218/*!
219 Returns the seat with which the device is associated, if known; otherwise empty.
220
221 Devices that are intended to be used together by one user may be configured
222 to have the same seat name. That is only possible on Wayland and X11
223 platforms so far.
224*/
225QString QInputDevice::seatName() const
226{
227 Q_D(const QInputDevice);
228 return d->seatName;
229}
230
231using InputDevicesList = QList<const QInputDevice *>;
232Q_GLOBAL_STATIC(InputDevicesList, deviceList)
233Q_CONSTINIT static QBasicMutex devicesMutex;
234
235/*!
236 Returns a list of all registered input devices (keyboards and pointing devices).
237
238 \note The list of devices is not always complete on all platforms. So far,
239 the most-complete information is available on the \l {Qt for Linux/X11}{X11}
240 platform, at startup and in response to hot-plugging. Most other platforms
241 are only able to provide generic devices of various types, only after receiving
242 events from them; and most platforms do not tell Qt when a device is plugged in,
243 or when it is unplugged at runtime.
244
245 \note The returned list cannot be used to add new devices. To add a simulated
246 touch screen for an autotest, QTest::createTouchDevice() can be used.
247 Platform plugins should call QWindowSystemInterface::registerInputDevice()
248 to add devices as they are discovered.
249*/
250QList<const QInputDevice *> QInputDevice::devices()
251{
252 QMutexLocker lock(&devicesMutex);
253 return *deviceList();
254}
255
256/*!
257 \since 6.3
258
259 Returns a list of seat names for all registered input devices (keyboards and pointing devices).
260*/
261QStringList QInputDevice::seatNames()
262{
263 QMutexLocker locker(&devicesMutex);
264 const InputDevicesList devices = *deviceList();
265 locker.unlock();
266 QStringList result;
267 for (const QInputDevice *d : devices) {
268 if (!result.contains(str: d->seatName()))
269 result.append(t: d->seatName());
270 }
271
272 return result;
273}
274
275/*!
276 Returns the core or master keyboard on the given seat \a seatName.
277*/
278const QInputDevice *QInputDevice::primaryKeyboard(const QString& seatName)
279{
280 QMutexLocker locker(&devicesMutex);
281 const InputDevicesList devices = *deviceList();
282 locker.unlock();
283 const QInputDevice *ret = nullptr;
284 for (const QInputDevice *d : devices) {
285 if (d->type() != DeviceType::Keyboard)
286 continue;
287 if (seatName.isNull() || d->seatName() == seatName) {
288 // the master keyboard's parent is not another input device
289 if (!d->parent() || !qobject_cast<const QInputDevice *>(object: d->parent()))
290 return d;
291 if (!ret)
292 ret = d;
293 }
294 }
295 if (!ret) {
296 qCDebug(lcQpaInputDevices) << "no keyboards registered for seat" << seatName
297 << "The platform plugin should have provided one via "
298 "QWindowSystemInterface::registerInputDevice(). Creating a default one for now.";
299 ret = new QInputDevice("core keyboard"_L1, 0, DeviceType::Keyboard, seatName, QCoreApplication::instance());
300 QInputDevicePrivate::registerDevice(dev: ret);
301 return ret;
302 }
303 qWarning() << "core keyboard ambiguous for seat" << seatName;
304 return ret;
305}
306
307QInputDevicePrivate::~QInputDevicePrivate()
308 = default;
309
310/*!
311 \internal
312 Checks whether a matching device is already registered
313 (via operator==, not pointer equality).
314*/
315bool QInputDevicePrivate::isRegistered(const QInputDevice *dev)
316{
317 if (!dev)
318 return false;
319 QMutexLocker locker(&devicesMutex);
320 InputDevicesList v = *deviceList();
321 for (const QInputDevice *d : v)
322 if (d && *d == *dev)
323 return true;
324 return false;
325}
326
327/*!
328 \internal
329 Find the device with the given \a systemId (for example the xinput
330 device ID on X11), which is expected to be unique if nonzero.
331
332 If the \a systemId is not unique, this function returns the first one found.
333
334 \note Use QInputDevicePrivate::queryTabletDevice() if the device is a
335 tablet or a tablet stylus; in that case, \a id is not unique.
336*/
337const QInputDevice *QInputDevicePrivate::fromId(qint64 systemId)
338{
339 QMutexLocker locker(&devicesMutex);
340 for (const QInputDevice *dev : *deviceList()) {
341 if (dev->systemId() == systemId)
342 return dev;
343 }
344 return nullptr;
345}
346
347void QInputDevicePrivate::registerDevice(const QInputDevice *dev)
348{
349 QMutexLocker lock(&devicesMutex);
350 deviceList()->append(t: dev);
351}
352
353/*!
354 \internal
355*/
356void QInputDevicePrivate::unregisterDevice(const QInputDevice *dev)
357{
358 QMutexLocker lock(&devicesMutex);
359 deviceList()->removeOne(t: dev);
360}
361
362bool QInputDevice::operator==(const QInputDevice &other) const
363{
364 return systemId() == other.systemId();
365}
366
367#ifndef QT_NO_DEBUG_STREAM
368QDebug operator<<(QDebug debug, const QInputDevice *device)
369{
370 QDebugStateSaver saver(debug);
371 debug.nospace();
372 debug.noquote();
373
374 debug << "QInputDevice(";
375 if (!device) {
376 debug << "0)";
377 return debug;
378 }
379
380 const QInputDevicePrivate *d = QInputDevicePrivate::get(q: device);
381
382 if (d->pointingDeviceType)
383 return operator<<(debug, static_cast<const QPointingDevice *>(device));
384
385 debug << "QInputDevice(";
386 debug << '"' << device->name() << "\", type=" << device->type()
387 << ", ID=" << device->systemId() << ", seat='" << device->seatName() << "'";
388 debug << ')';
389 return debug;
390}
391#endif // !QT_NO_DEBUG_STREAM
392
393QT_END_NAMESPACE
394
395#include "moc_qinputdevice.cpp"
396

source code of qtbase/src/gui/kernel/qinputdevice.cpp