/src/qt/qtbase/src/gui/kernel/qinputdevice.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | 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 | | */ |
162 | | QRect QInputDevice::availableVirtualGeometry() const |
163 | 0 | { |
164 | 0 | Q_D(const QInputDevice); |
165 | 0 | return d->availableVirtualGeometry; |
166 | 0 | } |
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 | | */ |
175 | | QString QInputDevice::name() const |
176 | 0 | { |
177 | 0 | Q_D(const QInputDevice); |
178 | 0 | return d->name; |
179 | 0 | } |
180 | | |
181 | | /*! |
182 | | Returns the device type. |
183 | | */ |
184 | | QInputDevice::DeviceType QInputDevice::type() const |
185 | 0 | { |
186 | 0 | Q_D(const QInputDevice); |
187 | 0 | return d->deviceType; |
188 | 0 | } |
189 | | |
190 | | /*! |
191 | | Returns the device capabilities. |
192 | | */ |
193 | | QInputDevice::Capabilities QInputDevice::capabilities() const |
194 | 0 | { |
195 | 0 | Q_D(const QInputDevice); |
196 | 0 | return QInputDevice::Capabilities(d->capabilities); |
197 | 0 | } |
198 | | |
199 | | /*! |
200 | | Returns whether the device capabilities include the given \a capability. |
201 | | */ |
202 | | bool QInputDevice::hasCapability(QInputDevice::Capability capability) const |
203 | 0 | { |
204 | 0 | return capabilities().testFlag(capability); |
205 | 0 | } |
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 | | */ |
212 | | qint64 QInputDevice::systemId() const |
213 | 0 | { |
214 | 0 | Q_D(const QInputDevice); |
215 | 0 | return d->systemId; |
216 | 0 | } |
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 | | */ |
225 | | QString QInputDevice::seatName() const |
226 | 0 | { |
227 | 0 | Q_D(const QInputDevice); |
228 | 0 | return d->seatName; |
229 | 0 | } |
230 | | |
231 | | using InputDevicesList = QList<const QInputDevice *>; |
232 | | Q_GLOBAL_STATIC(InputDevicesList, deviceList) |
233 | | Q_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 | | */ |
250 | | QList<const QInputDevice *> QInputDevice::devices() |
251 | 0 | { |
252 | 0 | QMutexLocker lock(&devicesMutex); |
253 | 0 | return *deviceList(); |
254 | 0 | } |
255 | | |
256 | | /*! |
257 | | \since 6.3 |
258 | | |
259 | | Returns a list of seat names for all registered input devices (keyboards and pointing devices). |
260 | | */ |
261 | | QStringList QInputDevice::seatNames() |
262 | 0 | { |
263 | 0 | QMutexLocker locker(&devicesMutex); |
264 | 0 | const InputDevicesList devices = *deviceList(); |
265 | 0 | locker.unlock(); |
266 | 0 | QStringList result; |
267 | 0 | for (const QInputDevice *d : devices) { |
268 | 0 | if (!result.contains(d->seatName())) |
269 | 0 | result.append(d->seatName()); |
270 | 0 | } |
271 | |
|
272 | 0 | return result; |
273 | 0 | } |
274 | | |
275 | | /*! |
276 | | Returns the core or master keyboard on the given seat \a seatName. |
277 | | */ |
278 | | const QInputDevice *QInputDevice::primaryKeyboard(const QString& seatName) |
279 | 0 | { |
280 | 0 | QMutexLocker locker(&devicesMutex); |
281 | 0 | const InputDevicesList devices = *deviceList(); |
282 | 0 | locker.unlock(); |
283 | 0 | const QInputDevice *ret = nullptr; |
284 | 0 | for (const QInputDevice *d : devices) { |
285 | 0 | if (d->type() != DeviceType::Keyboard) |
286 | 0 | continue; |
287 | 0 | if (seatName.isNull() || d->seatName() == seatName) { |
288 | | // the master keyboard's parent is not another input device |
289 | 0 | if (!d->parent() || !qobject_cast<const QInputDevice *>(d->parent())) |
290 | 0 | return d; |
291 | 0 | if (!ret) |
292 | 0 | ret = d; |
293 | 0 | } |
294 | 0 | } |
295 | 0 | if (!ret) { |
296 | 0 | qCDebug(lcQpaInputDevices) << "no keyboards registered for seat" << seatName |
297 | 0 | << "The platform plugin should have provided one via " |
298 | 0 | "QWindowSystemInterface::registerInputDevice(). Creating a default one for now."; |
299 | 0 | ret = new QInputDevice("core keyboard"_L1, 0, DeviceType::Keyboard, seatName, QCoreApplication::instance()); |
300 | 0 | QInputDevicePrivate::registerDevice(ret); |
301 | 0 | return ret; |
302 | 0 | } |
303 | 0 | qWarning() << "core keyboard ambiguous for seat" << seatName; |
304 | 0 | return ret; |
305 | 0 | } |
306 | | |
307 | 0 | QInputDevicePrivate::~QInputDevicePrivate() |
308 | | = default; |
309 | | |
310 | | /*! |
311 | | \internal |
312 | | Checks whether a matching device is already registered |
313 | | (via operator==, not pointer equality). |
314 | | */ |
315 | | bool QInputDevicePrivate::isRegistered(const QInputDevice *dev) |
316 | 0 | { |
317 | 0 | if (!dev) |
318 | 0 | return false; |
319 | 0 | QMutexLocker locker(&devicesMutex); |
320 | 0 | InputDevicesList v = *deviceList(); |
321 | 0 | for (const QInputDevice *d : v) |
322 | 0 | if (d && *d == *dev) |
323 | 0 | return true; |
324 | 0 | return false; |
325 | 0 | } |
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 | | */ |
337 | | const QInputDevice *QInputDevicePrivate::fromId(qint64 systemId) |
338 | 0 | { |
339 | 0 | QMutexLocker locker(&devicesMutex); |
340 | 0 | for (const QInputDevice *dev : *deviceList()) { |
341 | 0 | if (dev->systemId() == systemId) |
342 | 0 | return dev; |
343 | 0 | } |
344 | 0 | return nullptr; |
345 | 0 | } |
346 | | |
347 | | void QInputDevicePrivate::registerDevice(const QInputDevice *dev) |
348 | 0 | { |
349 | 0 | QMutexLocker lock(&devicesMutex); |
350 | 0 | deviceList()->append(dev); |
351 | 0 | qCInfo(lcQpaInputDevices) << "Registered" << dev; |
352 | 0 | } |
353 | | |
354 | | /*! |
355 | | \internal |
356 | | */ |
357 | | void QInputDevicePrivate::unregisterDevice(const QInputDevice *dev) |
358 | 0 | { |
359 | 0 | if (deviceList.isDestroyed()) |
360 | 0 | return; // nothing to remove! |
361 | | |
362 | 0 | QMutexLocker lock(&devicesMutex); |
363 | 0 | deviceList()->removeOne(dev); |
364 | 0 | qCInfo(lcQpaInputDevices) << "Unregistered" << dev; |
365 | 0 | } |
366 | | |
367 | | bool QInputDevice::operator==(const QInputDevice &other) const |
368 | 0 | { |
369 | 0 | return systemId() == other.systemId(); |
370 | 0 | } |
371 | | |
372 | | #ifndef QT_NO_DEBUG_STREAM |
373 | | QDebug operator<<(QDebug debug, const QInputDevice *device) |
374 | 0 | { |
375 | 0 | QDebugStateSaver saver(debug); |
376 | 0 | debug.nospace(); |
377 | 0 | debug.noquote(); |
378 | |
|
379 | 0 | debug << "QInputDevice("; |
380 | 0 | if (!device) |
381 | 0 | return debug << "0x0)"; |
382 | | |
383 | 0 | const QInputDevicePrivate *d = QInputDevicePrivate::get(device); |
384 | |
|
385 | 0 | if (d->pointingDeviceType) |
386 | 0 | return operator<<(debug, static_cast<const QPointingDevice *>(device)); |
387 | | |
388 | 0 | debug << "QInputDevice("; |
389 | 0 | debug << '"' << device->name() << "\", type=" << device->type() |
390 | 0 | << ", ID=" << device->systemId() << ", seat='" << device->seatName() << "'"; |
391 | 0 | debug << ')'; |
392 | 0 | return debug; |
393 | 0 | } |
394 | | #endif // !QT_NO_DEBUG_STREAM |
395 | | |
396 | | QT_END_NAMESPACE |
397 | | |
398 | | #include "moc_qinputdevice.cpp" |