/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" |