1/****************************************************************************
2**
3** Copyright (C) 2020 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qinputdevice.h"
41#include "qinputdevice_p.h"
42#include "qpointingdevice.h"
43#include <QCoreApplication>
44#include <QDebug>
45#include <QLoggingCategory>
46#include <QMutex>
47#include <QScreen>
48
49QT_BEGIN_NAMESPACE
50
51Q_DECLARE_LOGGING_CATEGORY(lcQpaInputDevices)
52
53/*!
54 \class QInputDevice
55 \brief The QInputDevice class describes a device from which a QInputEvent originates.
56 \since 6.0
57 \inmodule QtGui
58
59 Each QInputEvent contains a QInputDevice pointer to allow accessing
60 device-specific properties like type, capabilities and seat. It is the
61 responsibility of the platform or generic plug-ins to discover, create and
62 register an instance of this class corresponding to each available input
63 device, via QWindowSystemInterface::registerInputDevice(), before
64 generating any input event referring to that device.
65
66 Applications do not need to instantiate this class, but can read the
67 instances pointed to by QInputEvent::device() and QInputDevice::devices().
68*/
69
70/*!
71 \enum QInputDevice::Capability
72
73 Indicates what kind of information the input device or its driver can
74 provide.
75
76 \value None
77 No information about input device capabilities available.
78
79 \value Position
80 Indicates that position information is available, meaning that the
81 position() family of functions in the touch points return valid points.
82
83 \value Area
84 Indicates that touch area information is available, meaning that
85 QEventPoint::ellipseDiameters() in the touch points return valid
86 values.
87
88 \value Pressure
89 Indicates that pressure information is available, meaning that
90 QEventPoint::pressure() returns a valid value.
91
92 \value Velocity
93 Indicates that velocity information is available, meaning that
94 QEventPoint::velocity() returns a valid vector.
95
96 \value NormalizedPosition
97 Indicates that the normalized position is available, meaning that
98 QEventPoint::globalPosition() returns a valid value.
99
100 \value MouseEmulation
101 Indicates that the device synthesizes mouse events.
102
103 \value Scroll
104 Indicates that the device has a scroll capability.
105
106 \value Hover
107 Indicates that the device has a hover capability.
108
109 \value Rotation
110 Indicates that \l {QEventPoint::}{rotation} information is available.
111
112 \value XTilt
113 Indicates that \l {QTabletEvent::xTilt()}{tilt} information is
114 available for the X-axis.
115
116 \value YTilt
117 Indicates that \l {QTabletEvent::yTilt()}{tilt} information is
118 available for the Y-axis.
119
120 \value TangentialPressure
121 Indicates that \l {QTabletEvent::tangentialPressure()}
122 {tangential pressure} information is available.
123
124 \value ZPosition
125 Indicates that position information for the \l {QTabletEvent::z()}
126 {Z-axis} is available.
127
128 \value All
129*/
130
131/*!
132 Creates a new invalid input device instance.
133*/
134QInputDevice::QInputDevice()
135 : QObject(*(new QInputDevicePrivate(QString(), -1, QInputDevice::DeviceType::Unknown)), nullptr)
136{
137}
138
139QInputDevice::~QInputDevice()
140{
141 QInputDevicePrivate::unregisterDevice(this);
142}
143
144/*!
145 Creates a new input device instance. The given \a name is normally a
146 manufacturer-assigned model name if available, or something else
147 identifiable; \a id is a platform-specific number that will be unique per
148 device (for example the xinput ID on X11); \a type identifies what kind of
149 device. On window systems that are capable of handling input from multiple
150 users or sets of input devices at the same time (such as Wayland or X11),
151 \a seatName identifies the name of the set of devices that will be used
152 together. If the device is a child or slave device (for example one of
153 several mice that can take turns moving the "core pointer"), the master
154 device should be given as the \a parent.
155
156 The platform plugin creates, registers and continues to own each device
157 instance; usually \a parent should be given for memory management purposes
158 even if there is no master for a particular device.
159
160 By default, capabilities() are \c None.
161*/
162QInputDevice::QInputDevice(const QString &name, qint64 id, QInputDevice::DeviceType type,
163 const QString &seatName, QObject *parent)
164 : QObject(*new QInputDevicePrivate(name, id, type, QInputDevice::Capability::None, seatName), parent)
165{
166}
167
168/*!
169 \internal
170*/
171QInputDevice::QInputDevice(QInputDevicePrivate &d, QObject *parent)
172 : QObject(d, parent)
173{
174}
175
176/*!
177 Returns the region within the \l{QScreen::availableVirtualGeometry}{virtual desktop}
178 that this device can access.
179
180 For example a \l {QInputDevice::DeviceType}{TouchScreen} input
181 device is fixed in place upon a single physical screen, and usually
182 calibrated so that this area is the same as QScreen::geometry(); whereas a
183 \l {QInputDevice::DeviceType}{Mouse} can probably access all screens
184 on the virtual desktop. A Wacom graphics tablet may be configured in a way
185 that it's mapped to all screens, or only to the screen where the user
186 prefers to create drawings, or to the window in which drawing occurs.
187 A \l {QInputDevice::DeviceType}{Stylus} device that is integrated
188 with a touchscreen may be physically limited to that screen.
189
190 If the returned rectangle is \l {QRect::isNull()}{null}, it means this device
191 can access the entire virtual desktop.
192*/
193QRect QInputDevice::availableVirtualGeometry() const
194{
195 Q_D(const QInputDevice);
196 return d->availableVirtualGeometry;
197}
198
199/*!
200 Returns the device name.
201
202 This string may be empty. It is however useful on systems that have
203 multiple input devices: it can be used to differentiate from which device a
204 QPointerEvent originates.
205*/
206QString QInputDevice::name() const
207{
208 Q_D(const QInputDevice);
209 return d->name;
210}
211
212/*!
213 Returns the device type.
214*/
215QInputDevice::DeviceType QInputDevice::type() const
216{
217 Q_D(const QInputDevice);
218 return d->deviceType;
219}
220
221/*!
222 Returns the device capabilities.
223*/
224QInputDevice::Capabilities QInputDevice::capabilities() const
225{
226 Q_D(const QInputDevice);
227 return QInputDevice::Capabilities(d->capabilities);
228}
229
230/*!
231 Returns whether the device capabilities include the given \a capability.
232*/
233bool QInputDevice::hasCapability(QInputDevice::Capability capability) const
234{
235 return capabilities().testFlag(capability);
236}
237
238/*!
239 Returns the platform specific system ID (for example xinput ID on the X11 platform).
240
241 All platforms are expected to provide a unique system ID for each device.
242*/
243qint64 QInputDevice::systemId() const
244{
245 Q_D(const QInputDevice);
246 return d->systemId;
247}
248
249/*!
250 Returns the seat with which the device is associated, if known; otherwise empty.
251
252 Devices that are intended to be used together by one user may be configured
253 to have the same seat name. That is only possible on Wayland and X11
254 platforms so far.
255*/
256QString QInputDevice::seatName() const
257{
258 Q_D(const QInputDevice);
259 return d->seatName;
260}
261
262using InputDevicesList = QList<const QInputDevice *>;
263Q_GLOBAL_STATIC(InputDevicesList, deviceList)
264static QBasicMutex devicesMutex;
265
266/*!
267 Returns a list of all registered input devices (keyboards and pointing devices).
268
269 \note The returned list cannot be used to add new devices. To add a simulated
270 touch screen for an autotest, QTest::createTouchDevice() can be used.
271 Platform plugins should call QWindowSystemInterface::registerInputDevice()
272 to add devices as they are discovered.
273*/
274QList<const QInputDevice *> QInputDevice::devices()
275{
276 QMutexLocker lock(&devicesMutex);
277 return *deviceList();
278}
279
280/*!
281 Returns the core or master keyboard on the given seat \a seatName.
282*/
283const QInputDevice *QInputDevice::primaryKeyboard(const QString& seatName)
284{
285 QMutexLocker locker(&devicesMutex);
286 InputDevicesList v = *deviceList();
287 locker.unlock();
288 const QInputDevice *ret = nullptr;
289 for (const QInputDevice *d : v) {
290 if (d->type() == DeviceType::Keyboard && d->seatName() == seatName) {
291 // the master keyboard's parent is not another input device
292 if (!d->parent() || !qobject_cast<const QInputDevice *>(d->parent()))
293 return d;
294 if (!ret)
295 ret = d;
296 }
297 }
298 if (!ret) {
299 qCDebug(lcQpaInputDevices) << "no keyboards registered for seat" << seatName
300 << "The platform plugin should have provided one via "
301 "QWindowSystemInterface::registerInputDevice(). Creating a default one for now.";
302 ret = new QInputDevice(QLatin1String("core keyboard"), 0, DeviceType::Keyboard, seatName);
303 QInputDevicePrivate::registerDevice(ret);
304 return ret;
305 }
306 qWarning() << "core keyboard ambiguous for seat" << seatName;
307 return ret;
308}
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(dev);
351}
352
353/*!
354 \internal
355*/
356void QInputDevicePrivate::unregisterDevice(const QInputDevice *dev)
357{
358 QMutexLocker lock(&devicesMutex);
359 deviceList()->removeOne(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 const QInputDevicePrivate *d = QInputDevicePrivate::get(device);
371 if (d->pointingDeviceType)
372 return operator<<(debug, static_cast<const QPointingDevice *>(device));
373 QDebugStateSaver saver(debug);
374 debug.nospace();
375 debug.noquote();
376 debug << "QInputDevice(";
377 if (device) {
378 debug << '"' << device->name() << "\", type=" << device->type()
379 << Qt::hex << ", ID=" << device->systemId() << ", seat='" << device->seatName() << "'";
380 } else {
381 debug << '0';
382 }
383 debug << ')';
384 return debug;
385}
386#endif // !QT_NO_DEBUG_STREAM
387
388QT_END_NAMESPACE
389