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 | : QObject(*(new QInputDevicePrivate(QString(), -1, QInputDevice::DeviceType::Unknown)), parent) |
105 | { |
106 | } |
107 | |
108 | QInputDevice::~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 | */ |
131 | QInputDevice::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 | */ |
140 | QInputDevice::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 | */ |
162 | QRect 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 | */ |
175 | QString QInputDevice::name() const |
176 | { |
177 | Q_D(const QInputDevice); |
178 | return d->name; |
179 | } |
180 | |
181 | /*! |
182 | Returns the device type. |
183 | */ |
184 | QInputDevice::DeviceType QInputDevice::type() const |
185 | { |
186 | Q_D(const QInputDevice); |
187 | return d->deviceType; |
188 | } |
189 | |
190 | /*! |
191 | Returns the device capabilities. |
192 | */ |
193 | QInputDevice::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 | */ |
202 | bool 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 | */ |
212 | qint64 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 | */ |
225 | QString QInputDevice::seatName() const |
226 | { |
227 | Q_D(const QInputDevice); |
228 | return d->seatName; |
229 | } |
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 | { |
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 | */ |
261 | QStringList 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 | */ |
278 | const 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 | |
307 | 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 | { |
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 | */ |
337 | const 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 | |
347 | void QInputDevicePrivate::registerDevice(const QInputDevice *dev) |
348 | { |
349 | QMutexLocker lock(&devicesMutex); |
350 | deviceList()->append(t: dev); |
351 | } |
352 | |
353 | /*! |
354 | \internal |
355 | */ |
356 | void QInputDevicePrivate::unregisterDevice(const QInputDevice *dev) |
357 | { |
358 | QMutexLocker lock(&devicesMutex); |
359 | deviceList()->removeOne(t: dev); |
360 | } |
361 | |
362 | bool QInputDevice::operator==(const QInputDevice &other) const |
363 | { |
364 | return systemId() == other.systemId(); |
365 | } |
366 | |
367 | #ifndef QT_NO_DEBUG_STREAM |
368 | QDebug 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 | |
393 | QT_END_NAMESPACE |
394 | |
395 | #include "moc_qinputdevice.cpp" |
396 | |