Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qpointingdevice.cpp
Go to the documentation of this file.
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
// Qt-Security score:significant reason:default
4
5
#
include
"qpointingdevice.h"
6
#
include
"qpointingdevice_p.h"
7
#
include
"qwindowsysteminterface_p.h"
8
#
include
"qeventpoint_p.h"
9
10
#
include
<
QList
>
11
#
include
<
QLoggingCategory
>
12
#
include
<
QMutex
>
13
#
include
<
QCoreApplication
>
14
15
#
include
<
private
/
qdebug_p
.
h
>
16
17
QT_BEGIN_NAMESPACE
18
19
using
namespace
Qt::StringLiterals;
20
21
Q_LOGGING_CATEGORY
(lcPointerGrab,
"qt.pointer.grab"
);
22
23
/*!
24
\class QPointingDevice
25
\brief The QPointingDevice class describes a device from which mouse, touch or tablet events originate.
26
\since 6.0
27
\ingroup events
28
\inmodule QtGui
29
30
Each QPointerEvent contains a QPointingDevice pointer to allow accessing
31
device-specific properties like type and capabilities. It is the
32
responsibility of the platform or generic plug-ins to register the
33
available pointing devices via QWindowSystemInterface before generating any
34
pointer events. Applications do not need to instantiate this class, they
35
should just access the global instances pointed to by QPointerEvent::device().
36
*/
37
38
/*! \enum QInputDevice::DeviceType
39
40
This enum represents the type of device that generated a QPointerEvent.
41
42
\value Unknown
43
The device cannot be identified.
44
45
\value Mouse
46
A mouse.
47
48
\value TouchScreen
49
In this type of device, the touch surface and display are integrated.
50
This means the surface and display typically have the same size, such
51
that there is a direct relationship between the touch points' physical
52
positions and the coordinate reported by QEventPoint. As a
53
result, Qt allows the user to interact directly with multiple QWidgets,
54
QGraphicsItems, or Qt Quick Items at the same time.
55
56
\value TouchPad
57
In this type of device, the touch surface is separate from the display.
58
There is not a direct relationship between the physical touch location
59
and the on-screen coordinates. Instead, they are calculated relative to
60
the current mouse position, and the user must use the touch-pad to move
61
this reference point. Unlike touch-screens, Qt allows users to only
62
interact with a single QWidget or QGraphicsItem at a time.
63
64
\value Stylus
65
A pen-like device used on a graphics tablet such as a Wacom tablet,
66
or on a touchscreen that provides a separate stylus sensing capability.
67
68
\value Airbrush
69
A stylus with a thumbwheel to adjust
70
\l {QTabletEvent::tangentialPressure}{tangentialPressure}.
71
72
\value Puck
73
A device that is similar to a flat mouse with a transparent circle with
74
cross-hairs.
75
76
\value Keyboard
77
A keyboard.
78
79
\value AllDevices
80
Any of the above (used as a default filter value).
81
*/
82
83
/*! \enum QPointingDevice::PointerType
84
85
This enum represents what is interacting with the pointing device.
86
87
There is some redundancy between this property and \l {QInputDevice::DeviceType}.
88
For example, if a touchscreen is used, then the \c DeviceType is
89
\c TouchScreen and \c PointerType is \c Finger (always). But on a graphics
90
tablet, it's often possible for both ends of the stylus to be used, and
91
programs need to distinguish them. Therefore the concept is extended so
92
that every QPointerEvent has a PointerType, and it can simplify some event
93
handling code to ignore the DeviceType and react differently depending on
94
the PointerType alone.
95
96
Valid values are:
97
98
\value Unknown
99
The pointer type is unknown.
100
\value Generic
101
A mouse or something acting like a mouse (the core pointer on X11).
102
\value Finger
103
The user's finger.
104
\value Pen
105
The drawing end of a stylus.
106
\value Eraser
107
The other end of the stylus (if it has a virtual eraser on the other end).
108
\value Cursor
109
A transparent circle with cross-hairs as found on a
110
\l {QInputDevice::DeviceType}{Puck} device.
111
\value [since 6.12] Palm
112
The user's palm.
113
\value AllPointerTypes
114
Any of the above (used as a default filter value).
115
*/
116
117
/*! \enum QPointingDevice::GrabTransition
118
119
This enum represents a transition of exclusive or passive grab
120
from one object (possibly \c nullptr) to another (possibly \c nullptr).
121
It is emitted as an argument of the QPointingDevice::grabChanged() signal.
122
123
Valid values are:
124
125
\value GrabExclusive
126
Emitted after QPointerEvent::setExclusiveGrabber().
127
\value UngrabExclusive
128
Emitted after QPointerEvent::setExclusiveGrabber() when the grabber is
129
set to \c nullptr, to notify that the grab has terminated normally.
130
\value CancelGrabExclusive
131
Emitted after QPointerEvent::setExclusiveGrabber() when the grabber is set
132
to a different object, to notify that the old grabber's grab is "stolen".
133
\value GrabPassive
134
Emitted after QPointerEvent::addPassiveGrabber().
135
\value UngrabPassive
136
Emitted when a passive grab is terminated normally,
137
for example after QPointerEvent::removePassiveGrabber().
138
\value CancelGrabPassive
139
Emitted when a passive grab is terminated abnormally (a gesture is canceled).
140
\value OverrideGrabPassive
141
This value is not currently used.
142
*/
143
144
/*! \fn void QPointingDevice::grabChanged(QObject *grabber, QPointingDevice::GrabTransition transition, const QPointerEvent *event, const QEventPoint &point) const
145
146
This signal is emitted when the \a grabber object gains or loses an
147
exclusive or passive grab of \a point during delivery of \a event.
148
The \a transition tells what happened, from the perspective of the
149
\c grabber object.
150
151
\note A grab transition from one object to another results in two signals,
152
to notify that one object has lost its grab, and to notify that there is
153
another grabber. In other cases, when transitioning to or from a non-grabbing
154
state, only one signal is emitted: the \a grabber argument is never \c nullptr.
155
156
\sa QPointerEvent::setExclusiveGrabber(), QPointerEvent::addPassiveGrabber(), QPointerEvent::removePassiveGrabber()
157
*/
158
159
/*!
160
Creates a new invalid pointing device instance as a child of \a parent.
161
*/
162
QPointingDevice::QPointingDevice(QObject *parent)
163
: QInputDevice(*(
new
QPointingDevicePrivate(
"unknown"_L1
, -1,
164
DeviceType::Unknown, PointerType::Unknown,
165
Capability::None, 0, 0)), parent)
166
{
167
}
168
169
QPointingDevice::~QPointingDevice()
170
{
171
}
172
173
/*!
174
Creates a new pointing device instance with the given
175
\a name, \a deviceType, \a pointerType, \a capabilities, \a maxPoints,
176
\a buttonCount, \a seatName, \a uniqueId and \a parent.
177
*/
178
QPointingDevice::QPointingDevice(
const
QString &name, qint64 id, QInputDevice::DeviceType deviceType,
179
QPointingDevice::PointerType pointerType, Capabilities capabilities,
int
maxPoints,
int
buttonCount,
180
const
QString &seatName, QPointingDeviceUniqueId uniqueId, QObject *parent)
181
: QInputDevice(*(
new
QPointingDevicePrivate(name, id, deviceType, pointerType, capabilities, maxPoints, buttonCount, seatName, uniqueId)), parent)
182
{
183
}
184
185
/*!
186
\internal
187
*/
188
QPointingDevice::QPointingDevice(QPointingDevicePrivate &d, QObject *parent)
189
: QInputDevice(d, parent)
190
{
191
}
192
193
#
if
QT_DEPRECATED_SINCE
(
6
,
0
)
194
/*!
195
\internal
196
\deprecated [6.0] Please use the constructor rather than setters.
197
198
Sets the device type \a devType and infers the pointer type.
199
*/
200
void
QPointingDevice::setType(DeviceType devType)
201
{
202
Q_D(QPointingDevice);
203
d->deviceType = devType;
204
if
(d->pointerType == PointerType::Unknown)
205
switch
(devType) {
206
case
DeviceType::Mouse:
207
d->pointerType = PointerType::Generic;
208
break
;
209
case
DeviceType::TouchScreen:
210
case
DeviceType::TouchPad:
211
d->pointerType = PointerType::Finger;
212
break
;
213
case
DeviceType::Puck:
214
d->pointerType = PointerType::Cursor;
215
break
;
216
case
DeviceType::Stylus:
217
case
DeviceType::Airbrush:
218
d->pointerType = PointerType::Pen;
219
break
;
220
default
:
221
break
;
222
}
223
}
224
225
/*!
226
\internal
227
\deprecated [6.0] Please use the constructor rather than setters.
228
*/
229
void
QPointingDevice::setCapabilities(QInputDevice::Capabilities caps)
230
{
231
Q_D(QPointingDevice);
232
d->setCapabilities(caps);
233
}
234
235
/*!
236
\internal
237
\deprecated [6.0] Please use the constructor rather than setters.
238
*/
239
void
QPointingDevice::setMaximumTouchPoints(
int
c)
240
{
241
Q_D(QPointingDevice);
242
d->maximumTouchPoints = c;
243
}
244
#
endif
// QT_DEPRECATED_SINCE(6, 0)
245
246
/*!
247
\property QPointingDevice::pointerType
248
\brief the pointer type
249
*/
250
251
/*!
252
Returns the pointer type.
253
*/
254
QPointingDevice::PointerType QPointingDevice::pointerType()
const
255
{
256
Q_D(
const
QPointingDevice);
257
return
d->pointerType;
258
}
259
260
/*!
261
\property QPointingDevice::maximumPoints
262
\brief the maximum number of simultaneous touch points (fingers) that
263
can be detected
264
*/
265
266
/*!
267
Returns the maximum number of simultaneous touch points (fingers) that
268
can be detected.
269
*/
270
int
QPointingDevice::maximumPoints()
const
271
{
272
Q_D(
const
QPointingDevice);
273
return
d->maximumTouchPoints;
274
}
275
276
/*!
277
\property QPointingDevice::buttonCount
278
\brief the maximum number of on-device buttons that can be detected
279
*/
280
281
/*!
282
Returns the maximum number of on-device buttons that can be detected.
283
*/
284
int
QPointingDevice::buttonCount()
const
285
{
286
Q_D(
const
QPointingDevice);
287
return
d->buttonCount;
288
}
289
290
/*!
291
\property QPointingDevice::uniqueId
292
\brief a unique ID (of dubious utility) for the device
293
294
You probably should rather be concerned with QPointerEventPoint::uniqueId().
295
*/
296
297
/*!
298
Returns a unique ID (of dubious utility) for the device.
299
300
You probably should rather be concerned with QPointerEventPoint::uniqueId().
301
*/
302
QPointingDeviceUniqueId QPointingDevice::uniqueId()
const
303
{
304
Q_D(
const
QPointingDevice);
305
return
d->uniqueId;
306
}
307
308
/*!
309
Returns the primary pointing device (the core pointer, traditionally
310
assumed to be a mouse) on the given seat \a seatName.
311
312
If multiple pointing devices are registered, this function prefers a mouse
313
or touchpad that matches the given \a seatName and that does not have
314
another device as its parent. Usually only one master or core device does
315
not have a parent device. But if such a device is not found, this function
316
creates a new virtual "core pointer" mouse. Thus Qt continues to work on
317
platforms that are not yet doing input device discovery and registration.
318
*/
319
const
QPointingDevice *QPointingDevice::primaryPointingDevice(
const
QString& seatName)
320
{
321
const
auto
v = devices();
322
const
QPointingDevice *mouse =
nullptr
;
323
const
QPointingDevice *touchpad =
nullptr
;
324
for
(
const
QInputDevice *dev : v) {
325
if
(!seatName.isNull() && dev->seatName() != seatName)
326
continue
;
327
if
(dev->type() == QInputDevice::DeviceType::Mouse) {
328
if
(!mouse)
329
mouse =
static_cast
<
const
QPointingDevice *>(dev);
330
// the core pointer is likely a mouse, and its parent is not another input device
331
if
(!mouse->parent() || !qobject_cast<
const
QInputDevice *>(mouse->parent()))
332
return
mouse;
333
}
else
if
(dev->type() == QInputDevice::DeviceType::TouchPad) {
334
if
(!touchpad || !dev->parent() || dev->parent()->metaObject() != dev->metaObject())
335
touchpad =
static_cast
<
const
QPointingDevice *>(dev);
336
}
337
}
338
if
(!mouse && !touchpad) {
339
qCDebug(lcQpaInputDevices) <<
"no mouse-like devices registered for seat"
<< seatName
340
<<
"The platform plugin should have provided one via "
341
"QWindowSystemInterface::registerInputDevice(). Creating a default mouse for now."
;
342
mouse =
new
QPointingDevice(
"core pointer"_L1
, 1, DeviceType::Mouse,
343
PointerType::Generic, Capability::Position, 1, 3, seatName,
344
QPointingDeviceUniqueId(), QCoreApplication::instance());
345
QInputDevicePrivate::registerDevice(mouse);
346
return
mouse;
347
}
348
if
(v.size() > 1)
349
qCDebug(lcQpaInputDevices) <<
"core pointer ambiguous for seat"
<< seatName;
350
if
(mouse)
351
return
mouse;
352
return
touchpad;
353
}
354
355
QPointingDevicePrivate::~QPointingDevicePrivate()
356
=
default
;
357
358
/*!
359
\internal
360
Finds the device instance belonging to the drawing or eraser end of a particular stylus,
361
identified by its \a deviceType, \a pointerType, \a uniqueId and \a systemId.
362
Returns the device found, or \c nullptr if none was found.
363
364
If \a systemId is \c 0, it's not significant for the search.
365
366
If an instance matching the given \a deviceType and \a pointerType but with
367
only a default-constructed \c uniqueId is found, it will be assumed to be
368
the one we're looking for, its \c uniqueId will be updated to match the
369
given \a uniqueId, and its \c capabilities will be updated to match the
370
given \a capabilities. This is for the benefit of any platform plugin that can
371
discover the tablet itself at startup, along with the supported stylus types,
372
but then discovers specific styli later on as they come into proximity.
373
*/
374
const
QPointingDevice *QPointingDevicePrivate::queryTabletDevice(QInputDevice::DeviceType deviceType,
375
QPointingDevice::PointerType pointerType,
376
QPointingDeviceUniqueId uniqueId,
377
QPointingDevice::Capabilities capabilities,
378
qint64 systemId)
379
{
380
const
auto
&devices = QInputDevice::devices();
381
for
(
const
QInputDevice *dev : devices) {
382
if
(dev->type() < QPointingDevice::DeviceType::Puck || dev->type() > QPointingDevice::DeviceType::Airbrush)
383
continue
;
384
const
QPointingDevice *pdev =
static_cast
<
const
QPointingDevice *>(dev);
385
const
auto
devPriv = QPointingDevicePrivate::get(pdev);
386
bool
uniqueIdDiscovered = (devPriv->uniqueId.numericId() == 0 && uniqueId.numericId() != 0);
387
if
(devPriv->deviceType == deviceType && devPriv->pointerType == pointerType &&
388
(!systemId || devPriv->systemId == systemId) &&
389
(devPriv->uniqueId == uniqueId || uniqueIdDiscovered)) {
390
if
(uniqueIdDiscovered) {
391
const_cast
<QPointingDevicePrivate *>(devPriv)->uniqueId = uniqueId;
392
if
(capabilities)
393
const_cast
<QPointingDevicePrivate *>(devPriv)->capabilities = capabilities;
394
qCDebug(lcQpaInputDevices) <<
"discovered unique ID and capabilities of tablet tool"
<< pdev;
395
}
396
return
pdev;
397
}
398
}
399
return
nullptr
;
400
}
401
402
/*!
403
\internal
404
Finds the device instance identified by its \a systemId.
405
Returns the device found, or \c nullptr if none was found.
406
*/
407
const
QPointingDevice *QPointingDevicePrivate::pointingDeviceById(qint64 systemId)
408
{
409
const
auto
&devices = QInputDevice::devices();
410
for
(
const
QInputDevice *dev : devices) {
411
if
(dev->type() >= QPointingDevice::DeviceType::Keyboard)
412
continue
;
413
const
QPointingDevice *pdev =
static_cast
<
const
QPointingDevice *>(dev);
414
const
auto
devPriv = QPointingDevicePrivate::get(pdev);
415
if
(devPriv->systemId == systemId)
416
return
pdev;
417
}
418
return
nullptr
;
419
}
420
421
/*!
422
\internal
423
First, ensure that the \a cancelEvent's QTouchEvent::points() list contains
424
all points that have exclusive grabs. Then send the event to each object
425
that has an exclusive grab of any of the points.
426
*/
427
void
QPointingDevicePrivate::sendTouchCancelEvent(QTouchEvent *cancelEvent)
428
{
429
// An incoming TouchCancel event will typically not contain any points, but
430
// QQuickPointerHandler::onGrabChanged needs to be called for each point
431
// that has an exclusive grabber. Adding those points to the event makes it
432
// an easy iteration there.
433
if
(cancelEvent->points().isEmpty()) {
434
for
(
auto
&epd : activePoints.values()) {
435
if
(epd.exclusiveGrabber)
436
QMutableTouchEvent::addPoint(cancelEvent, epd.eventPoint);
437
}
438
}
439
for
(
auto
&epd : activePoints.values()) {
440
if
(epd.exclusiveGrabber)
441
QCoreApplication::sendEvent(epd.exclusiveGrabber, cancelEvent);
442
// The next touch event can only be a TouchBegin, so clean up.
443
cancelEvent->setExclusiveGrabber(epd.eventPoint,
nullptr
);
444
cancelEvent->clearPassiveGrabbers(epd.eventPoint);
445
}
446
}
447
448
/*! \internal
449
Returns the active EventPointData instance with the given \a id, if available,
450
or \c nullptr if not.
451
*/
452
QPointingDevicePrivate::EventPointData *QPointingDevicePrivate::queryPointById(
int
id)
const
453
{
454
auto
it = activePoints.find(id);
455
if
(it == activePoints.end())
456
return
nullptr
;
457
return
&it.value();
458
}
459
460
/*! \internal
461
Returns the active EventPointData instance with the given \a id, if available;
462
if not, appends a new instance and returns it.
463
*/
464
QPointingDevicePrivate::EventPointData *QPointingDevicePrivate::pointById(
int
id)
const
465
{
466
const
auto
[it, inserted] = activePoints.try_emplace(id);
467
if
(inserted) {
468
Q_Q(
const
QPointingDevice);
469
auto
&epd = it.value();
470
QMutableEventPoint::setId(epd.eventPoint, id);
471
QMutableEventPoint::setDevice(epd.eventPoint, q);
472
}
473
return
&it.value();
474
}
475
476
/*! \internal
477
Remove the active EventPointData instance with the given \a id.
478
*/
479
void
QPointingDevicePrivate::removePointById(
int
id)
480
{
481
activePoints.remove(id);
482
}
483
484
/*!
485
\internal
486
Find the first non-null target (widget) via QMutableEventPoint::target()
487
in the active points. This is the widget that will receive any event that
488
comes from a touchpad, even if some of the touchpoints fall spatially on
489
other windows.
490
*/
491
QObject *QPointingDevicePrivate::firstActiveTarget()
const
492
{
493
for
(
auto
&pt : activePoints.values()) {
494
if
(
auto
target = QMutableEventPoint::target(pt.eventPoint))
495
return
target;
496
}
497
return
nullptr
;
498
}
499
500
/*! \internal
501
Find the first non-null QWindow instance via QMutableEventPoint::window()
502
in the active points. This is the window that will receive any event that
503
comes from a touchpad, even if some of the touchpoints fall spatially on
504
other windows.
505
*/
506
QWindow *QPointingDevicePrivate::firstActiveWindow()
const
507
{
508
for
(
auto
&pt : activePoints.values()) {
509
if
(
auto
window = QMutableEventPoint::window(pt.eventPoint))
510
return
window;
511
}
512
return
nullptr
;
513
}
514
515
/*! \internal
516
Return the exclusive grabber of the first point in activePoints.
517
This is mainly for autotests that try to verify the "current" grabber
518
outside the context of event delivery, which is something that the rest
519
of the codebase should not be doing.
520
*/
521
QObject *QPointingDevicePrivate::firstPointExclusiveGrabber()
const
522
{
523
if
(activePoints.isEmpty())
524
return
nullptr
;
525
return
activePoints.values().first().exclusiveGrabber;
526
}
527
528
void
QPointingDevicePrivate::setExclusiveGrabber(
const
QPointerEvent *event,
const
QEventPoint &point, QObject *exclusiveGrabber)
529
{
530
Q_Q(QPointingDevice);
531
auto
persistentPoint = queryPointById(point.id());
532
if
(!persistentPoint) {
533
qWarning() <<
"point is not in activePoints"
<< point;
534
return
;
535
}
536
Q_ASSERT(persistentPoint->eventPoint.id() == point.id());
537
if
(persistentPoint->exclusiveGrabber == exclusiveGrabber)
538
return
;
539
auto
oldGrabber = persistentPoint->exclusiveGrabber;
540
persistentPoint->exclusiveGrabber = exclusiveGrabber;
541
if
(oldGrabber)
542
emit q->grabChanged(oldGrabber, exclusiveGrabber ? QPointingDevice::CancelGrabExclusive : QPointingDevice::UngrabExclusive,
543
event, persistentPoint->eventPoint);
544
if
(Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
545
qCDebug(lcPointerGrab) << name <<
"point"
<< point.id() << point.state()
546
<<
"@"
<< point.scenePosition()
547
<<
": grab"
<< oldGrabber <<
"->"
<< exclusiveGrabber;
548
}
549
QMutableEventPoint::setGlobalGrabPosition(persistentPoint->eventPoint, point.globalPosition());
550
if
(exclusiveGrabber)
551
emit q->grabChanged(exclusiveGrabber, QPointingDevice::GrabExclusive, event, point);
552
else
553
persistentPoint->exclusiveGrabberContext.clear();
554
}
555
556
/*!
557
\internal
558
Call QEventPoint::setExclusiveGrabber(nullptr) on each active point that has a grabber.
559
*/
560
bool
QPointingDevicePrivate::removeExclusiveGrabber(
const
QPointerEvent *event,
const
QObject *grabber)
561
{
562
bool
ret =
false
;
563
for
(
auto
&pt : activePoints.values()) {
564
if
(pt.exclusiveGrabber == grabber) {
565
setExclusiveGrabber(event, pt.eventPoint,
nullptr
);
566
ret =
true
;
567
}
568
}
569
return
ret;
570
}
571
572
bool
QPointingDevicePrivate::addPassiveGrabber(
const
QPointerEvent *event,
const
QEventPoint &point, QObject *grabber)
573
{
574
Q_Q(QPointingDevice);
575
auto
persistentPoint = queryPointById(point.id());
576
if
(!persistentPoint) {
577
qWarning() <<
"point is not in activePoints"
<< point;
578
return
false
;
579
}
580
if
(persistentPoint->passiveGrabbers.contains(grabber))
581
return
false
;
582
if
(Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
583
qCDebug(lcPointerGrab) << name <<
"point"
<< point.id() << point.state()
584
<<
": grab (passive)"
<< grabber;
585
}
586
persistentPoint->passiveGrabbers << grabber;
587
emit q->grabChanged(grabber, QPointingDevice::GrabPassive, event, point);
588
return
true
;
589
}
590
591
bool
QPointingDevicePrivate::setPassiveGrabberContext(QPointingDevicePrivate::EventPointData *epd, QObject *grabber, QObject *context)
592
{
593
qsizetype i = epd->passiveGrabbers.indexOf(grabber);
594
if
(i < 0)
595
return
false
;
596
if
(epd->passiveGrabbersContext.size() <= i)
597
epd->passiveGrabbersContext.resize(i + 1);
598
epd->passiveGrabbersContext[i] = context;
599
return
true
;
600
}
601
602
bool
QPointingDevicePrivate::removePassiveGrabber(
const
QPointerEvent *event,
const
QEventPoint &point, QObject *grabber)
603
{
604
Q_Q(QPointingDevice);
605
auto
persistentPoint = queryPointById(point.id());
606
if
(!persistentPoint) {
607
qWarning() <<
"point is not in activePoints"
<< point;
608
return
false
;
609
}
610
qsizetype i = persistentPoint->passiveGrabbers.indexOf(grabber);
611
if
(i >= 0) {
612
if
(Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
613
qCDebug(lcPointerGrab) << name <<
"point"
<< point.id() << point.state()
614
<<
": removing passive grabber"
<< grabber;
615
}
616
emit q->grabChanged(grabber, QPointingDevice::UngrabPassive, event, point);
617
persistentPoint->passiveGrabbers.removeAt(i);
618
if
(persistentPoint->passiveGrabbersContext.size()) {
619
Q_ASSERT(persistentPoint->passiveGrabbersContext.size() > i);
620
persistentPoint->passiveGrabbersContext.removeAt(i);
621
}
622
return
true
;
623
}
624
return
false
;
625
}
626
627
void
QPointingDevicePrivate::clearPassiveGrabbers(
const
QPointerEvent *event,
const
QEventPoint &point)
628
{
629
Q_Q(QPointingDevice);
630
auto
persistentPoint = queryPointById(point.id());
631
if
(!persistentPoint) {
632
qWarning() <<
"point is not in activePoints"
<< point;
633
return
;
634
}
635
if
(persistentPoint->passiveGrabbers.isEmpty())
636
return
;
637
if
(Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
638
qCDebug(lcPointerGrab) << name <<
"point"
<< point.id() << point.state()
639
<<
": clearing"
<< persistentPoint->passiveGrabbers;
640
}
641
for
(
auto
g : persistentPoint->passiveGrabbers)
642
emit q->grabChanged(g, QPointingDevice::UngrabPassive, event, point);
643
persistentPoint->passiveGrabbers.clear();
644
persistentPoint->passiveGrabbersContext.clear();
645
}
646
647
/*!
648
\internal
649
Removes the given \a grabber as both passive and exclusive grabber from all
650
points in activePoints where it's currently found. If \a cancel is \c true,
651
the transition emitted from the grabChanged() signal will be
652
\c CancelGrabExclusive or \c CancelGrabPassive. Otherwise it will be
653
\c UngrabExclusive or \c UngrabPassive.
654
655
\note This function provides a way to work around the limitation that we
656
normally change grabbers only during event delivery; but it's also more expensive.
657
*/
658
void
QPointingDevicePrivate::removeGrabber(QObject *grabber,
bool
cancel)
659
{
660
Q_Q(QPointingDevice);
661
for
(
auto
ap : activePoints) {
662
auto
&epd = ap.second;
663
if
(epd.exclusiveGrabber.data() == grabber) {
664
qCDebug(lcPointerGrab) << name <<
"point"
<< epd.eventPoint.id() << epd.eventPoint.state()
665
<<
"@"
<< epd.eventPoint.scenePosition()
666
<<
": grab"
<< grabber <<
"-> nullptr"
;
667
epd.exclusiveGrabber.clear();
668
epd.exclusiveGrabberContext.clear();
669
emit q->grabChanged(grabber,
670
cancel ? QPointingDevice::CancelGrabExclusive : QPointingDevice::UngrabExclusive,
671
nullptr
, epd.eventPoint);
672
}
673
qsizetype pi = epd.passiveGrabbers.indexOf(grabber);
674
if
(pi >= 0) {
675
qCDebug(lcPointerGrab) << name <<
"point"
<< epd.eventPoint.id() << epd.eventPoint.state()
676
<<
": removing passive grabber"
<< grabber;
677
epd.passiveGrabbers.removeAt(pi);
678
if
(epd.passiveGrabbersContext.size()) {
679
Q_ASSERT(epd.passiveGrabbersContext.size() > pi);
680
epd.passiveGrabbersContext.removeAt(pi);
681
}
682
emit q->grabChanged(grabber,
683
cancel ? QPointingDevice::CancelGrabPassive : QPointingDevice::UngrabPassive,
684
nullptr
, epd.eventPoint);
685
}
686
}
687
}
688
689
/*!
690
\internal
691
Finds the device instance belonging to the drawing or eraser end of a particular stylus,
692
identified by its \a deviceType, \a pointerType and \a uniqueId. If an existing device
693
is not found, a new one is created and registered, with a warning.
694
695
This function is called from QWindowSystemInterface. Platform plugins should use
696
\l queryTabletDeviceInstance() to check whether a tablet stylus coming into proximity
697
is previously known; if not known, the plugin should create and register the stylus.
698
*/
699
const
QPointingDevice *QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType deviceType,
700
QPointingDevice::PointerType pointerType,
701
QPointingDeviceUniqueId uniqueId)
702
{
703
const
QPointingDevice *dev = queryTabletDevice(deviceType, pointerType, uniqueId);
704
if
(!dev) {
705
qCDebug(lcQpaInputDevices) <<
"failed to find registered tablet device"
706
<< deviceType << pointerType << Qt::hex << uniqueId.numericId()
707
<<
"The platform plugin should have provided one via "
708
"QWindowSystemInterface::registerInputDevice(). Creating a default one for now."
;
709
dev =
new
QPointingDevice(
"fake tablet"_L1
, 2, deviceType, pointerType,
710
QInputDevice::Capability::Position | QInputDevice::Capability::Pressure,
711
1, 1, QString(), uniqueId, QCoreApplication::instance());
712
QInputDevicePrivate::registerDevice(dev);
713
}
714
return
dev;
715
}
716
717
bool
QPointingDevice::operator==(
const
QPointingDevice &other)
const
718
{
719
// Wacom tablets generate separate instances for each end of each stylus;
720
// QInputDevice::operator==() says they are all the same, but we use
721
// the stylus unique serial number and pointerType to distinguish them
722
return
QInputDevice::operator==(other) &&
723
pointerType() == other.pointerType() &&
724
uniqueId() == other.uniqueId();
725
}
726
727
#
ifndef
QT_NO_DEBUG_STREAM
728
QDebug operator<<(QDebug debug,
const
QPointingDevice *device)
729
{
730
QDebugStateSaver saver(debug);
731
debug.nospace();
732
debug.noquote();
733
debug <<
"QPointingDevice("
;
734
if
(device) {
735
debug <<
'"'
<< device->name() <<
"\" "
;
736
QtDebugUtils::formatQEnum(debug, device->type());
737
debug <<
" id="
<< device->systemId();
738
if
(!device->seatName().isEmpty())
739
debug <<
" seat="
<< device->seatName();
740
if
(device->pointerType() != QPointingDevice::PointerType::Generic) {
741
debug <<
" ptrType="
;
742
QtDebugUtils::formatQEnum(debug, device->pointerType());
743
}
744
if
(
int
(device->capabilities()) !=
int
(QInputDevice::Capability::Position)) {
745
debug <<
" caps="
;
746
QtDebugUtils::formatQFlags(debug, device->capabilities());
747
}
748
if
(device->buttonCount() > 0)
749
debug <<
" buttonCount="
<< device->buttonCount();
750
if
(device->maximumPoints() > 1)
751
debug <<
" maxPts="
<< device->maximumPoints();
752
if
(device->uniqueId().isValid())
753
debug <<
" uniqueId="
<< Qt::hex << device->uniqueId().numericId() << Qt::dec;
754
}
else
{
755
debug <<
"0x0"
;
756
}
757
debug <<
')'
;
758
return
debug;
759
}
760
#
endif
// !QT_NO_DEBUG_STREAM
761
762
/*!
763
\class QPointingDeviceUniqueId
764
\since 5.8
765
\ingroup events
766
\inmodule QtGui
767
768
\brief QPointingDeviceUniqueId identifies a unique object, such as a tagged token
769
or stylus, which is used with a pointing device.
770
771
QPointingDeviceUniqueIds can be compared for equality, and can be used as keys in a QHash.
772
You get access to the numerical ID via numericId(), if the device supports such IDs.
773
For future extensions, though, you should not use that function, but compare objects
774
of this type using the equality operator.
775
776
This class is a thin wrapper around an integer ID. You pass it into and out of
777
functions by value.
778
779
\sa QEventPoint
780
*/
781
782
/*!
783
\fn QPointingDeviceUniqueId::QPointingDeviceUniqueId()
784
Constructs an invalid unique pointer ID.
785
*/
786
787
/*!
788
Constructs a unique pointer ID from numeric ID \a id.
789
*/
790
QPointingDeviceUniqueId QPointingDeviceUniqueId::fromNumericId(qint64 id)
791
{
792
QPointingDeviceUniqueId result;
793
result.m_numericId = id;
794
return
result;
795
}
796
797
/*!
798
\fn bool QPointingDeviceUniqueId::isValid() const
799
800
Returns whether this unique pointer ID is valid, that is, it represents an actual
801
pointer.
802
*/
803
804
/*!
805
\property QPointingDeviceUniqueId::numericId
806
\brief the numeric unique ID of the token represented by a touchpoint
807
808
If the device provides a numeric ID, isValid() returns true, and this
809
property provides the numeric ID;
810
otherwise it is -1.
811
812
You should not use the value of this property in portable code, but
813
instead rely on equality to identify pointers.
814
815
\sa isValid()
816
*/
817
qint64 QPointingDeviceUniqueId::numericId()
const
noexcept
818
{
819
return
m_numericId;
820
}
821
822
/*!
823
\fn bool QPointingDeviceUniqueId::operator==(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs)
824
\since 5.8
825
826
Returns whether the two unique pointer IDs \a lhs and \a rhs identify the same pointer
827
(\c true) or not (\c false).
828
*/
829
830
/*!
831
\fn bool QPointingDeviceUniqueId::operator!=(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs)
832
\since 5.8
833
834
Returns whether the two unique pointer IDs \a lhs and \a rhs identify different pointers
835
(\c true) or not (\c false).
836
*/
837
838
/*!
839
\qhashold{QPointingDeviceUniqueId}
840
\since 5.8
841
*/
842
size_t
qHash
(QPointingDeviceUniqueId key, size_t seed)
noexcept
843
{
844
return
qHash(key.numericId(), seed);
845
}
846
847
QT_END_NAMESPACE
848
849
#
include
"moc_qpointingdevice.cpp"
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
Q_LOGGING_CATEGORY
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
qHash
size_t qHash(QByteArrayView key, size_t seed) noexcept
Definition
qhash.cpp:876
qtbase
src
gui
kernel
qpointingdevice.cpp
Generated on
for Qt by
1.18.0