2828#include < libinputactions/input/Delta.h>
2929#include < libinputactions/input/devices/InputDevice.h>
3030#include < libinputactions/triggers/StrokeTrigger.h>
31+ #include < libinputactions/triggers/SwipeTrigger.h>
3132
3233Q_LOGGING_CATEGORY (INPUTACTIONS_HANDLER_MOTION, " inputactions.handler.motion" , QtWarningMsg)
3334
3435namespace InputActions
3536{
3637
37- /* *
38- * Minimum amount of deltas required to accurately detect axis changes.
39- */
40- static const size_t AXIS_CHANGE_MIN_DELTA_COUNT = 10 ;
41-
4238static const qreal CIRCLE_COASTING_FRICTION = 0.02 ;
4339static const std::chrono::milliseconds CIRCLE_COASTING_TIMER_INTERVAL{30L };
4440static const qreal PI_2 = M_PI * 2 ;
@@ -81,8 +77,15 @@ bool MotionTriggerHandler::handleMotion(const InputDevice *device, const PointDe
8177
8278 qCDebug (INPUTACTIONS_HANDLER_MOTION).nospace () << " Event (type: Motion, delta: " << delta.unaccelerated () << " )" ;
8379
84- m_deltas.push_back (delta.unaccelerated ());
85- m_totalSwipeDelta += delta.unaccelerated ();
80+ const auto hasStroke = hasActiveTriggers (TriggerType::Stroke);
81+ const auto hasSwipe = hasActiveTriggers (TriggerType::Swipe);
82+
83+ if (hasStroke) {
84+ m_deltas.push_back (delta.unaccelerated ());
85+ }
86+ if (hasSwipe) {
87+ m_swipeDeltas.insert (m_swipeDeltas.begin (), delta.unaccelerated ());
88+ }
8689
8790 TriggerSpeed speed{};
8891 if (!determineSpeed (TriggerType::Swipe, delta.unacceleratedHypot (), speed)) {
@@ -91,9 +94,8 @@ bool MotionTriggerHandler::handleMotion(const InputDevice *device, const PointDe
9194
9295 std::map<TriggerType, const TriggerUpdateEvent *> events;
9396 DirectionalMotionTriggerUpdateEvent circleEvent;
94- DirectionalMotionTriggerUpdateEvent swipeEvent;
97+ SwipeTriggerUpdateEvent swipeEvent;
9598 MotionTriggerUpdateEvent strokeEvent;
96- bool axisChanged{};
9799
98100 // Block the event even if the result says not to do so.
99101 bool block{};
@@ -161,57 +163,50 @@ bool MotionTriggerHandler::handleMotion(const InputDevice *device, const PointDe
161163 // TODO: Cancel if motion is a straight line
162164 }
163165
164- if (hasActiveTriggers (TriggerType::Swipe)) {
165- if (m_deltas.size () < 2 ) {
166- // One delta may not be enough to determine the direction
167- return true ;
168- }
166+ if (hasSwipe) {
167+ const auto motionThreshold = currentMotionThreshold (device);
168+ bool motionThresholdReached{};
169169
170- if (m_currentSwipeAxis == Axis::None) {
171- m_currentSwipeAxis = std::abs (m_totalSwipeDelta.x ()) >= std::abs (m_totalSwipeDelta.y ()) ? Axis::Horizontal : Axis::Vertical;
172- } else if (m_deltas.size () >= AXIS_CHANGE_MIN_DELTA_COUNT) { // Make sure we have enough data to detect axis change
173- const std::vector<QPointF> lastDeltas (m_deltas.end () - AXIS_CHANGE_MIN_DELTA_COUNT, m_deltas.end ());
174- QPointF sum;
175- for (const auto &delta : lastDeltas) {
176- sum += {std::abs (delta.x ()), std::abs (delta.y ())};
170+ QPointF totalDelta;
171+ auto it = m_swipeDeltas.begin ();
172+ for (; it != m_swipeDeltas.end (); ++it) {
173+ totalDelta += *it;
174+ if (Math::hypot (totalDelta) < motionThreshold) {
175+ continue ;
177176 }
178177
179- if (std::min (sum.x (), sum.y ()) / std::max (sum.x (), sum.y ()) <= 0.2 // Must be a sharp turn
180- && ((m_currentSwipeAxis == Axis::Horizontal && sum.y () > sum.x ()) || (m_currentSwipeAxis == Axis::Vertical && sum.x () > sum.y ()))) {
181- m_currentSwipeAxis = m_currentSwipeAxis == Axis::Horizontal ? Axis::Vertical : Axis::Horizontal;
182- axisChanged = true ;
183- qCDebug (INPUTACTIONS_HANDLER_MOTION, " Swipe axis changed" );
184- }
178+ motionThresholdReached = true ;
179+ break ;
185180 }
186181
187- SwipeDirection direction{};
188- switch (m_currentSwipeAxis) {
189- case Axis::Vertical:
190- direction = m_totalSwipeDelta.y () < 0 ? SwipeDirection::Up : SwipeDirection::Down;
191- break ;
192- case Axis::Horizontal:
193- direction = m_totalSwipeDelta.x () < 0 ? SwipeDirection::Left : SwipeDirection::Right;
194- break ;
195- default :
196- Q_UNREACHABLE ();
182+ if (!motionThresholdReached) {
183+ return hasActiveBlockingTriggers (TriggerType::Swipe);
197184 }
185+ m_swipeDeltas.erase (++it, m_swipeDeltas.end ());
186+
187+ // Up should be 90°, not 270°
188+ auto currentDelta = delta.unaccelerated ();
189+ currentDelta.setY (-currentDelta.y ());
190+ totalDelta.setY (-totalDelta.y ());
198191
199- swipeEvent.setDelta (m_currentSwipeAxis == Axis::Vertical ? Delta (delta. accelerated (). y (), delta. unaccelerated (). y ())
200- : Delta (delta. accelerated (). x (), delta. unaccelerated (). x ()));
201- swipeEvent.setDirection ( static_cast <TriggerDirection>(direction ));
192+ swipeEvent.setAngle ( Math::atan2deg360 (currentDelta));
193+ swipeEvent. setAverageAngle ( Math::atan2deg360 (totalDelta / m_swipeDeltas. size ()));
194+ swipeEvent.setDelta ( Delta (delta. acceleratedHypot (), delta. unacceleratedHypot () ));
202195 swipeEvent.setPointDelta ({delta.accelerated () * m_swipeDeltaMultiplier, delta.unaccelerated () * m_swipeDeltaMultiplier});
203196 swipeEvent.setSpeed (speed);
204197 events[TriggerType::Swipe] = &swipeEvent;
205198 }
206199
207- if (hasActiveTriggers (TriggerType::Stroke) ) {
200+ if (hasStroke ) {
208201 strokeEvent.setDelta (device->type () == InputDeviceType::Mouse ? delta.acceleratedHypot () : delta.unacceleratedHypot ()); // backwards compatibility
209202 strokeEvent.setSpeed (speed);
210203 events[TriggerType::Stroke] = &strokeEvent;
211204 }
212205
213206 const auto result = updateTriggers (events);
214- if (axisChanged && !result.success ) {
207+ if (result.success ) {
208+ m_swipeUpdates++;
209+ } else if (hasSwipe && m_swipeUpdates > 0 ) {
215210 activateTriggers (TriggerType::Swipe);
216211 return handleMotion (device, delta);
217212 }
@@ -256,18 +251,23 @@ bool MotionTriggerHandler::determineSpeed(TriggerType type, qreal delta, Trigger
256251 return true ;
257252}
258253
254+ qreal MotionTriggerHandler::currentMotionThreshold (const InputDevice *device) const
255+ {
256+ return device->properties ().motionThreshold ();
257+ }
258+
259259void MotionTriggerHandler::reset ()
260260{
261261 TriggerHandler::reset ();
262- m_currentSwipeAxis = Axis::None;
263- m_totalSwipeDelta = {};
264262 m_speed = {};
265263 m_isDeterminingSpeed = false ;
266264 m_circleIsFirstEvent = true ;
267265 m_deltas.clear ();
268266 m_sampledInputEvents = m_accumulatedAbsoluteSampledDelta = m_circlePreviousAngle = m_circlePreviousDistance = m_circleFilterDelta = m_circleAdaptiveDelta
269267 = m_circleTotalDelta = 0 ;
270268 m_circleCoastingTimer.stop ();
269+ m_swipeDeltas.clear ();
270+ m_swipeUpdates = 0 ;
271271}
272272
273273void MotionTriggerHandler::onCircleCoastingTimerTick ()
0 commit comments