Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qeventpoint.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 "qeventpoint.h"
6#include "private/qeventpoint_p.h"
7#include "private/qpointingdevice_p.h"
8
9QT_BEGIN_NAMESPACE
10
11Q_LOGGING_CATEGORY(lcPointerVel, "qt.pointer.velocity")
12Q_LOGGING_CATEGORY(lcEPDetach, "qt.pointer.eventpoint.detach")
13
14QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QEventPointPrivate)
15
16/*! \class QEventPoint
17 \brief The QEventPoint class provides information about a point in a QPointerEvent.
18 \since 6.0
19 \inmodule QtGui
20*/
21
22/*!
23 \enum QEventPoint::State
24
25 Specifies the state of this event point.
26
27 \value Unknown
28 Unknown state.
29
30 \value Stationary
31 The event point did not move.
32
33 \value Pressed
34 The touch point or button is pressed.
35
36 \value Updated
37 The event point was updated.
38
39 \value Released
40 The touch point or button was released.
41*/
42
43/*!
44 \internal
45 Constructs an invalid event point with the given \a id and the \a device
46 from which it originated.
47
48 This acts as a default constructor in usages like QMap<int, QEventPoint>,
49 as in qgraphicsscene_p.h.
50*/
51QEventPoint::QEventPoint(int id, const QPointingDevice *device)
52 : d(new QEventPointPrivate(id, device)) {}
53
54/*!
55 Constructs an event point with the given \a pointId, \a state,
56 \a scenePosition and \a globalPosition.
57*/
58QEventPoint::QEventPoint(int pointId, State state, const QPointF &scenePosition, const QPointF &globalPosition)
59 : d(new QEventPointPrivate(pointId, state, scenePosition, globalPosition)) {}
60
61/*!
62 Constructs an event point by making a shallow copy of \a other.
63*/
64QEventPoint::QEventPoint(const QEventPoint &other) noexcept = default;
65
66/*!
67 Assigns \a other to this event point and returns a reference to this
68 event point.
69*/
70QEventPoint &QEventPoint::operator=(const QEventPoint &other) noexcept = default;
71
72/*!
73 \fn QEventPoint::QEventPoint(QEventPoint &&other) noexcept
74
75 Constructs an event point by moving \a other.
76*/
77
78/*!
79 \fn QEventPoint &QEventPoint::operator=(QEventPoint &&other) noexcept
80
81 Move-assigns \a other to this event point instance.
82*/
83
84/*!
85 Returns \c true if this event point is equal to \a other, otherwise
86 return \c false.
87*/
88bool QEventPoint::operator==(const QEventPoint &other) const noexcept
89{
90 if (d == other.d)
91 return true;
92 if (!d || !other.d)
93 return false;
94 return *d == *other.d;
95}
96
97/*!
98 \fn bool QEventPoint::operator!=(const QEventPoint &other) const noexcept
99
100 Returns \c true if this event point is not equal to \a other, otherwise
101 return \c false.
102*/
103
104/*!
105 Destroys the event point.
106*/
107QEventPoint::~QEventPoint() = default;
108
109/*! \fn QPointF QEventPoint::pos() const
110 \deprecated [6.0] Use position() instead.
111
112 Returns the position of this point, relative to the widget
113 or item that received the event.
114*/
115
116/*!
117 \property QEventPoint::position
118 \brief the position of this point.
119
120 The position is relative to the widget or item that received the event.
121*/
122QPointF QEventPoint::position() const
123{ return d ? d->pos : QPointF(); }
124
125/*!
126 \property QEventPoint::pressPosition
127 \brief the position at which this point was pressed.
128
129 The position is relative to the widget or item that received the event.
130
131 \sa position
132*/
133QPointF QEventPoint::pressPosition() const
134{ return d ? d->globalPressPos - d->globalPos + d->pos : QPointF(); }
135
136/*!
137 \property QEventPoint::grabPosition
138 \brief the position at which this point was grabbed.
139
140 The position is relative to the widget or item that received the event.
141
142 \sa position
143*/
144QPointF QEventPoint::grabPosition() const
145{ return d ? d->globalGrabPos - d->globalPos + d->pos : QPointF(); }
146
147/*!
148 \property QEventPoint::lastPosition
149 \brief the position of this point from the previous press or move event.
150
151 The position is relative to the widget or item that received the event.
152
153 \sa position, pressPosition
154*/
155QPointF QEventPoint::lastPosition() const
156{ return d ? d->globalLastPos - d->globalPos + d->pos : QPointF(); }
157
158/*!
159 \property QEventPoint::scenePosition
160 \brief the scene position of this point.
161
162 The scene position is the position relative to QQuickWindow if handled in QQuickItem::event(),
163 in QGraphicsScene coordinates if handled by an override of QGraphicsItem::touchEvent(),
164 or the window position in widget applications.
165
166 \sa scenePressPosition, position, globalPosition
167*/
168QPointF QEventPoint::scenePosition() const
169{ return d ? d->scenePos : QPointF(); }
170
171/*!
172 \property QEventPoint::scenePressPosition
173 \brief the scene position at which this point was pressed.
174
175 The scene position is the position relative to QQuickWindow if handled in QQuickItem::event(),
176 in QGraphicsScene coordinates if handled by an override of QGraphicsItem::touchEvent(),
177 or the window position in widget applications.
178
179 \sa scenePosition, pressPosition, globalPressPosition
180*/
181QPointF QEventPoint::scenePressPosition() const
182{ return d ? d->globalPressPos - d->globalPos + d->scenePos : QPointF(); }
183
184/*!
185 \property QEventPoint::sceneGrabPosition
186 \brief the scene position at which this point was grabbed.
187
188 The scene position is the position relative to QQuickWindow if handled in QQuickItem::event(),
189 in QGraphicsScene coordinates if handled by an override of QGraphicsItem::touchEvent(),
190 or the window position in widget applications.
191
192 \sa scenePosition, grabPosition, globalGrabPosition
193*/
194QPointF QEventPoint::sceneGrabPosition() const
195{ return d ? d->globalGrabPos - d->globalPos + d->scenePos : QPointF(); }
196
197/*!
198 \property QEventPoint::sceneLastPosition
199 \brief the scene position of this point from the previous press or move event.
200
201 The scene position is the position relative to QQuickWindow if handled in QQuickItem::event(),
202 in QGraphicsScene coordinates if handled by an override of QGraphicsItem::touchEvent(),
203 or the window position in widget applications.
204
205 \sa scenePosition, scenePressPosition
206*/
207QPointF QEventPoint::sceneLastPosition() const
208{ return d ? d->globalLastPos - d->globalPos + d->scenePos : QPointF(); }
209
210/*!
211 \property QEventPoint::globalPosition
212 \brief the global position of this point.
213
214 The global position is relative to the screen or virtual desktop.
215
216 \sa globalPressPosition, position, scenePosition
217*/
218QPointF QEventPoint::globalPosition() const
219{ return d ? d->globalPos : QPointF(); }
220
221/*!
222 \property QEventPoint::globalPressPosition
223 \brief the global position at which this point was pressed.
224
225 The global position is relative to the screen or virtual desktop.
226
227 \sa globalPosition, pressPosition, scenePressPosition
228*/
229QPointF QEventPoint::globalPressPosition() const
230{ return d ? d->globalPressPos : QPointF(); }
231
232/*!
233 \property QEventPoint::globalGrabPosition
234 \brief the global position at which this point was grabbed.
235
236 The global position is relative to the screen or virtual desktop.
237
238 \sa globalPosition, grabPosition, sceneGrabPosition
239*/
240QPointF QEventPoint::globalGrabPosition() const
241{ return d ? d->globalGrabPos : QPointF(); }
242
243/*!
244 \property QEventPoint::globalLastPosition
245 \brief the global position of this point from the previous press or move event.
246
247 The global position is relative to the screen or virtual desktop.
248
249 \sa globalPosition, lastPosition, sceneLastPosition
250*/
251QPointF QEventPoint::globalLastPosition() const
252{ return d ? d->globalLastPos : QPointF(); }
253
254/*!
255 \property QEventPoint::velocity
256 \brief a velocity vector, in units of pixels per second, in the coordinate.
257 system of the screen or desktop.
258
259 \note If the device's capabilities include QInputDevice::Velocity, it means
260 velocity comes from the operating system (perhaps the touch hardware or
261 driver provides it). But usually the \c Velocity capability is not set,
262 indicating that the velocity is calculated by Qt, using a simple Kalman
263 filter to provide a smoothed average velocity rather than an instantaneous
264 value. Effectively it tells how fast and in what direction the user has
265 been dragging this point over the last few events, with the most recent
266 event having the strongest influence.
267
268 \sa QInputDevice::capabilities(), QInputEvent::device()
269*/
270QVector2D QEventPoint::velocity() const
271{ return d ? d->velocity : QVector2D(); }
272
273/*!
274 \property QEventPoint::state
275 \brief the current state of the event point.
276*/
277QEventPoint::State QEventPoint::state() const
278{ return d ? d->state : QEventPoint::State::Unknown; }
279
280/*!
281 \property QEventPoint::device
282 \brief the pointing device from which this event point originates.
283*/
284const QPointingDevice *QEventPoint::device() const
285{ return d ? d->device : nullptr; }
286
287/*!
288 \property QEventPoint::id
289 \brief the ID number of this event point.
290
291 \note Do not assume that ID numbers start at zero or that they are
292 sequential. Such an assumption is often false due to the way
293 the underlying drivers work.
294*/
295int QEventPoint::id() const
296{ return d ? d->pointId : -1; }
297
298/*!
299 \property QEventPoint::uniqueId
300 \brief the unique ID of this point or token, if any.
301
302 It is often invalid (see \l {QPointingDeviceUniqueId::isValid()} {isValid()}),
303 because touchscreens cannot uniquely identify fingers.
304
305 When it comes from a QTabletEvent, it identifies the serial number of the
306 stylus in use.
307
308 It may identify a specific token (fiducial object) when the TUIO driver is
309 in use with a touchscreen that supports them.
310*/
311QPointingDeviceUniqueId QEventPoint::uniqueId() const
312{ return d ? d->uniqueId : QPointingDeviceUniqueId(); }
313
314/*!
315 \property QEventPoint::timestamp
316 \brief the most recent time at which this point was included in a QPointerEvent.
317
318 \sa QPointerEvent::timestamp()
319*/
320ulong QEventPoint::timestamp() const
321{ return d ? d->timestamp : 0; }
322
323/*!
324 \property QEventPoint::lastTimestamp
325 \brief the time from the previous QPointerEvent that contained this point.
326
327 \sa globalLastPosition
328*/
329ulong QEventPoint::lastTimestamp() const
330{ return d ? d->lastTimestamp : 0; }
331
332/*!
333 \property QEventPoint::pressTimestamp
334 \brief the most recent time at which this point was pressed.
335
336 \sa timestamp
337*/
338ulong QEventPoint::pressTimestamp() const
339{ return d ? d->pressTimestamp : 0; }
340
341/*!
342 \property QEventPoint::timeHeld
343 \brief the duration, in seconds, since this point was pressed and not released.
344
345 \sa pressTimestamp, timestamp
346*/
347qreal QEventPoint::timeHeld() const
348{ return d ? (d->timestamp - d->pressTimestamp) / qreal(1000) : 0.0; }
349
350/*!
351 \property QEventPoint::pressure
352 \brief the pressure of this point.
353
354 The return value is in the range \c 0.0 to \c 1.0.
355*/
356qreal QEventPoint::pressure() const
357{ return d ? d->pressure : 0.0; }
358
359/*!
360 \property QEventPoint::rotation
361 \brief the angular orientation of this point.
362
363 The return value is in degrees, where zero (the default) indicates the finger,
364 token or stylus is pointing upwards, a negative angle means it's rotated to the
365 left, and a positive angle means it's rotated to the right.
366 Most touchscreens do not detect rotation, so zero is the most common value.
367*/
368qreal QEventPoint::rotation() const
369{ return d ? d->rotation : 0.0; }
370
371/*!
372 \property QEventPoint::ellipseDiameters
373 \brief the width and height of the bounding ellipse of the touch point.
374
375 The return value is in logical pixels. Most touchscreens do not detect the
376 shape of the contact point, and no mice or tablet devices can detect it,
377 so a null size is the most common value. On some touchscreens the diameters
378 may be nonzero and always equal (the ellipse is approximated as a circle).
379*/
380QSizeF QEventPoint::ellipseDiameters() const
381{ return d ? d->ellipseDiameters : QSizeF(); }
382
383/*!
384 \property QEventPoint::accepted
385 \brief the accepted state of the event point.
386
387 In widget-based applications, this property is not used, as it's only meaningful
388 for a widget to accept or reject a complete QInputEvent.
389
390 In Qt Quick however, it's normal for an Item or Event Handler to accept
391 only the individual points in a QTouchEvent that are actually participating
392 in a gesture, while other points can be delivered to other items or
393 handlers. For the sake of consistency, that applies to any QPointerEvent;
394 and delivery is done only when all points in a QPointerEvent have been
395 accepted.
396
397 \sa QEvent::accepted
398*/
399void QEventPoint::setAccepted(bool accepted)
400{
401 if (d)
402 d->accept = accepted;
403}
404
405bool QEventPoint::isAccepted() const
406{ return d ? d->accept : false; }
407
408
409/*!
410 \fn QPointF QEventPoint::normalizedPos() const
411 \deprecated [6.0] Use normalizedPosition() instead.
412*/
413
414/*!
415 Returns the normalized position of this point.
416
417 The coordinates are calculated by transforming globalPosition() into the
418 space of QInputDevice::availableVirtualGeometry(), i.e. \c (0, 0) is the
419 top-left corner and \c (1, 1) is the bottom-right corner.
420
421 \sa globalPosition
422*/
423QPointF QEventPoint::normalizedPosition() const
424{
425 if (!d)
426 return {};
427
428 auto geom = d->device->availableVirtualGeometry();
429 if (geom.isNull())
430 return QPointF();
431 return (globalPosition() - geom.topLeft()) / geom.width();
432}
433
434#if QT_DEPRECATED_SINCE(6, 0)
435/*!
436 \deprecated [6.0] Use globalPressPosition() instead.
437
438 Returns the normalized press position of this point.
439*/
440QPointF QEventPoint::startNormalizedPos() const
441{
442 if (!d)
443 return {};
444
445 auto geom = d->device->availableVirtualGeometry();
446 if (geom.isNull())
447 return QPointF();
448 return (globalPressPosition() - geom.topLeft()) / geom.width();
449}
450
451/*!
452 \deprecated [6.0] Use globalLastPosition() instead.
453
454 Returns the normalized position of this point from the previous press or
455 move event.
456
457 The coordinates are normalized to QInputDevice::availableVirtualGeometry(),
458 i.e. \c (0, 0) is the top-left corner and \c (1, 1) is the bottom-right corner.
459
460 \sa normalizedPosition(), globalPressPosition()
461*/
462QPointF QEventPoint::lastNormalizedPos() const
463{
464 if (!d)
465 return {};
466
467 auto geom = d->device->availableVirtualGeometry();
468 if (geom.isNull())
469 return QPointF();
470 return (globalLastPosition() - geom.topLeft()) / geom.width();
471}
472#endif // QT_DEPRECATED_SINCE(6, 0)
473
474/*! \internal
475 This class is explicitly shared, which means if you construct an event and
476 then the point(s) that it holds are modified before the event is delivered,
477 the event will be seen to hold the modified points. The workaround is that
478 any code which modifies an eventpoint that could already be included in an
479 event, or code that wants to save an eventpoint for later, has
480 responsibility to detach before calling any setters, so as to hold and
481 modify an independent copy. (The independent copy can then be used in a
482 subsequent event.)
483*/
484void QMutableEventPoint::detach(QEventPoint &p)
485{
486 if (p.d)
487 p.d.detach();
488 else
489 p.d.reset(new QEventPointPrivate(-1, nullptr));
490}
491
492/*! \internal
493 Update \a target state from the \a other point, assuming that \a target
494 contains state from the previous event and \a other contains new
495 values that came in from a device.
496
497 That is: global position and other valuators will be updated, but
498 the following properties will not be updated:
499
500 \list
501 \li properties that are not likely to be set after a fresh touchpoint
502 has been received from a device
503 \li properties that should be persistent between events (such as grabbers)
504 \endlist
505*/
506void QMutableEventPoint::update(const QEventPoint &other, QEventPoint &target)
507{
508 detach(target);
509 setPressure(target, other.pressure());
510
511 switch (other.state()) {
512 case QEventPoint::State::Pressed:
513 setGlobalPressPosition(target, other.globalPosition());
514 setGlobalLastPosition(target, other.globalPosition());
515 if (target.pressure() < 0)
516 setPressure(target, 1);
517 break;
518
519 case QEventPoint::State::Released:
520 if (target.globalPosition() != other.globalPosition())
521 setGlobalLastPosition(target, target.globalPosition());
522 setPressure(target, 0);
523 break;
524
525 default: // update or stationary
526 if (target.globalPosition() != other.globalPosition())
527 setGlobalLastPosition(target, target.globalPosition());
528 if (target.pressure() < 0)
529 setPressure(target, 1);
530 break;
531 }
532
533 setState(target, other.state());
534 setPosition(target, other.position());
535 setScenePosition(target, other.scenePosition());
536 setGlobalPosition(target, other.globalPosition());
537 setEllipseDiameters(target, other.ellipseDiameters());
538 setRotation(target, other.rotation());
539 setVelocity(target, other.velocity());
540 setUniqueId(target, other.uniqueId()); // for TUIO
541}
542
543/*! \internal
544 Set the timestamp from the event that updated this point's positions,
545 and calculate a new value for velocity().
546
547 The velocity calculation is done here because none of the QPointerEvent
548 subclass constructors take the timestamp directly, and because
549 QGuiApplication traditionally constructs an event first and then sets its
550 timestamp (see for example QGuiApplicationPrivate::processMouseEvent()).
551
552 This function looks up the corresponding instance in QPointingDevicePrivate::activePoints,
553 and assumes that its timestamp() still holds the previous time when this point
554 was updated, its velocity() holds this point's last-known velocity, and
555 its globalPosition() and globalLastPosition() hold this point's current
556 and previous positions, respectively. We assume timestamps are in milliseconds.
557
558 The velocity calculation is skipped if the platform has promised to
559 provide velocities already by setting the QInputDevice::Velocity capability.
560*/
561void QMutableEventPoint::setTimestamp(QEventPoint &p, ulong t)
562{
563 // On mouse press, if the mouse has moved from its last-known location,
564 // QGuiApplicationPrivate::processMouseEvent() sends first a mouse move and
565 // then a press. Both events will get the same timestamp. So we need to set
566 // the press timestamp and position even when the timestamp isn't advancing,
567 // but skip setting lastTimestamp and velocity because those need a time delta.
568 if (p.d) {
569 if (p.state() == QEventPoint::State::Pressed) {
570 p.d->pressTimestamp = t;
571 p.d->globalPressPos = p.d->globalPos;
572 }
573 if (p.d->timestamp == t)
574 return;
575 }
576 detach(p);
577 if (p.device()) {
578 // get the persistent instance out of QPointingDevicePrivate::activePoints
579 // (which sometimes might be the same as this instance)
580 QEventPointPrivate *pd = QPointingDevicePrivate::get(
581 const_cast<QPointingDevice *>(p.d->device))->pointById(p.id())->eventPoint.d.get();
582 if (t > pd->timestamp) {
583 pd->lastTimestamp = pd->timestamp;
584 pd->timestamp = t;
585 if (p.state() == QEventPoint::State::Pressed)
586 pd->pressTimestamp = t;
587 if (pd->lastTimestamp > 0 && !p.device()->capabilities().testFlag(QInputDevice::Capability::Velocity)) {
588 // calculate instantaneous velocity according to time and distance moved since the previous point
589 QVector2D newVelocity = QVector2D(pd->globalPos - pd->globalLastPos) / (t - pd->lastTimestamp) * 1000;
590 // VERY simple kalman filter: does a weighted average
591 // where the older velocities get less and less significant
592 static const float KalmanGain = 0.7f;
593 pd->velocity = newVelocity * KalmanGain + pd->velocity * (1.0f - KalmanGain);
594 qCDebug(lcPointerVel) << "velocity" << newVelocity << "filtered" << pd->velocity <<
595 "based on movement" << pd->globalLastPos << "->" << pd->globalPos <<
596 "over time" << pd->lastTimestamp << "->" << pd->timestamp;
597 }
598 if (p.d != pd) {
599 p.d->lastTimestamp = pd->lastTimestamp;
600 p.d->velocity = pd->velocity;
601 }
602 }
603 }
604 p.d->timestamp = t;
605}
606
607/*!
608 \fn void QMutableEventPoint::setPosition(QPointF pos)
609 \internal
610
611 Sets the localized position.
612 Often events need to be localized before delivery to specific widgets or
613 items. This can be done directly, or in a copy (for which we have a copy
614 constructor), depending on whether the original point needs to be retained.
615 Usually it's calculated by mapping scenePosition() to the target anyway.
616*/
617
618QT_END_NAMESPACE
619
620#include "moc_qeventpoint.cpp"