diff options
Diffstat (limited to 'src/gui/kernel/qevent.cpp')
-rw-r--r-- | src/gui/kernel/qevent.cpp | 71 |
1 files changed, 65 insertions, 6 deletions
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 069aec4513..811d2d1f20 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -62,6 +62,7 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcPointerGrab, "qt.pointer.grab") +Q_LOGGING_CATEGORY(lcPointerVel, "qt.pointer.velocity") Q_LOGGING_CATEGORY(lcEPDetach, "qt.pointer.eventpoint.detach") /*! @@ -336,6 +337,14 @@ bool QEventPoint::isAccepted() const { return d->accept; } /*! + Returns the time from the previous QPointerEvent that contained this point. + + \sa globalLastPosition() +*/ +ulong QEventPoint::lastTimestamp() const +{ return d->lastTimestamp; } + +/*! Sets the accepted state of the point. In widget-based applications, this function is not used so far, because @@ -487,14 +496,30 @@ void QMutableEventPoint::updateFrom(const QEventPoint &other) } /*! \internal - Set the timestamp from the event that updated this point's positions. + Set the timestamp from the event that updated this point's positions, + and calculate a new value for velocity(). + + The velocity calculation is done here because none of the QPointerEvent + subclass constructors take the timestamp directly, and because + QGuiApplication traditionally constructs an event first and then sets its + timestamp (see for example QGuiApplicationPrivate::processMouseEvent()). + + This function looks up the corresponding instance in QPointingDevicePrivate::activePoints, + and assumes that its timestamp() still holds the previous time when this point + was updated, its velocity() holds this point's last-known velocity, and + its globalPosition() and globalLastPosition() hold this point's current + and previous positions, respectively. We assume timestamps are in milliseconds. + + The velocity calculation is skipped if the platform has promised to + provide velocities already by setting the QInputDevice::Velocity capability. */ void QMutableEventPoint::setTimestamp(const ulong t) { // On mouse press, if the mouse has moved from its last-known location, // QGuiApplicationPrivate::processMouseEvent() sends first a mouse move and // then a press. Both events will get the same timestamp. So we need to set - // the press timestamp and position even when the timestamp isn't advancing. + // the press timestamp and position even when the timestamp isn't advancing, + // but skip setting lastTimestamp and velocity because those need a time delta. if (state() == QEventPoint::State::Pressed) { d->pressTimestamp = t; d->globalPressPos = d->globalPos; @@ -502,6 +527,33 @@ void QMutableEventPoint::setTimestamp(const ulong t) if (d->timestamp == t) return; detach(); + if (device()) { + // get the persistent instance out of QPointingDevicePrivate::activePoints + // (which sometimes might be the same as this instance) + QEventPointPrivate *pd = QPointingDevicePrivate::get( + const_cast<QPointingDevice *>(d->device))->pointById(id())->eventPoint.d; + if (t > pd->timestamp) { + pd->lastTimestamp = pd->timestamp; + pd->timestamp = t; + if (state() == QEventPoint::State::Pressed) + pd->pressTimestamp = t; + if (pd->lastTimestamp > 0 && !device()->capabilities().testFlag(QInputDevice::Capability::Velocity)) { + // calculate instantaneous velocity according to time and distance moved since the previous point + QVector2D newVelocity = QVector2D(pd->globalPos - pd->globalLastPos) / (t - pd->lastTimestamp) * 1000; + // VERY simple kalman filter: does a weighted average + // where the older velocities get less and less significant + static const float KalmanGain = 0.7f; + pd->velocity = newVelocity * KalmanGain + pd->velocity * (1.0f - KalmanGain); + qCDebug(lcPointerVel) << "velocity" << newVelocity << "filtered" << pd->velocity << + "based on movement" << pd->globalLastPos << "->" << pd->globalPos << + "over time" << pd->lastTimestamp << "->" << pd->timestamp; + } + if (d != pd) { + d->lastTimestamp = pd->lastTimestamp; + d->velocity = pd->velocity; + } + } + } d->timestamp = t; } @@ -4820,10 +4872,17 @@ bool QTouchEvent::isReleaseEvent() const /*! \fn QVector2D QEventPoint::velocity() const - Returns a velocity vector for this point. - The vector is in the screen's coordinate system, using pixels per seconds for the magnitude. - - \note The returned vector is only valid if the device's capabilities include QInputDevice::Velocity. + Returns a velocity vector, in units of pixels per second, in the coordinate + system of the screen or desktop. + + \note If the device's capabilities include QInputDevice::Velocity, it means + velocity comes from the operating system (perhaps the touch hardware or + driver provides it). But usually the \c Velocity capability is not set, + indicating that the velocity is calculated by Qt, using a simple Kalman + filter to provide a smoothed average velocity rather than an instantaneous + value. Effectively it tells how fast and in what direction the user has + been dragging this point over the last few events, with the most recent + event having the strongest influence. \sa QInputDevice::capabilities(), QInputEvent::device() */ |