xref: /aosp_15_r20/external/libchrome-gestures/src/fling_stop_filter_interpreter.cc (revision aed3e5085e770be5b69ce25295ecf6ddf906af95)
1 // Copyright 2012 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "include/fling_stop_filter_interpreter.h"
6 
7 #include "include/util.h"
8 
9 namespace gestures {
10 
FlingStopFilterInterpreter(PropRegistry * prop_reg,Interpreter * next,Tracer * tracer,GestureInterpreterDeviceClass devclass)11 FlingStopFilterInterpreter::FlingStopFilterInterpreter(
12     PropRegistry* prop_reg, Interpreter* next, Tracer* tracer,
13     GestureInterpreterDeviceClass devclass)
14     : FilterInterpreter(nullptr, next, tracer, false),
15       already_extended_(false),
16       prev_touch_cnt_(0),
17       prev_gesture_type_(kGestureTypeNull),
18       fling_stop_already_sent_(false),
19       fling_stop_deadline_(NO_DEADLINE),
20       devclass_(devclass),
21       fling_stop_timeout_(prop_reg, "Fling Stop Timeout", 0.03),
22       fling_stop_extra_delay_(prop_reg, "Fling Stop Extra Delay", 0.055) {
23   InitName();
24 }
25 
SyncInterpretImpl(HardwareState & hwstate,stime_t * timeout)26 void FlingStopFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate,
27                                                    stime_t* timeout) {
28   const char name[] = "FlingStopFilterInterpreter::SyncInterpretImpl";
29   LogHardwareStatePre(name, hwstate);
30 
31   fingers_of_last_hwstate_.clear();
32   for (int i = 0; i < hwstate.finger_cnt; i++)
33     fingers_of_last_hwstate_.insert(hwstate.fingers[i].tracking_id);
34 
35   UpdateFlingStopDeadline(hwstate);
36   if (fling_stop_deadline_ != NO_DEADLINE) {
37     if (!already_extended_ && NeedsExtraTime(hwstate)) {
38       fling_stop_deadline_ += fling_stop_extra_delay_.val_;
39       already_extended_ = true;
40     }
41     if (hwstate.timestamp > fling_stop_deadline_) {
42       // sub in a fling before processing other interpreters
43       auto fling_tap_down = Gesture(kGestureFling, prev_timestamp_,
44                                     hwstate.timestamp, 0.0, 0.0,
45                                     GESTURES_FLING_TAP_DOWN);
46       LogGestureProduce(name, fling_tap_down);
47       ProduceGesture(fling_tap_down);
48 
49       fling_stop_already_sent_ = true;
50       fling_stop_deadline_ = NO_DEADLINE;
51     }
52   }
53 
54   stime_t next_timeout = NO_DEADLINE;
55   LogHardwareStatePost(name, hwstate);
56   next_->SyncInterpret(hwstate, &next_timeout);
57 
58   *timeout = SetNextDeadlineAndReturnTimeoutVal(hwstate.timestamp,
59                                                 fling_stop_deadline_,
60                                                 next_timeout);
61 }
62 
NeedsExtraTime(const HardwareState & hwstate) const63 bool FlingStopFilterInterpreter::NeedsExtraTime(
64     const HardwareState& hwstate) const {
65   int num_new_fingers = 0;
66   for (int i = 0; i < hwstate.finger_cnt; i++) {
67     const short id = hwstate.fingers[i].tracking_id;
68     if (!SetContainsValue(fingers_present_for_last_fling_, id)) {
69       num_new_fingers++;
70     }
71   }
72   return (num_new_fingers >= 2);
73 }
74 
FlingStopNeeded(const Gesture & gesture) const75 bool FlingStopFilterInterpreter::FlingStopNeeded(const Gesture& gesture) const {
76   if (fling_stop_already_sent_ || gesture.type == prev_gesture_type_)
77     return false;
78 
79   if (devclass_ == GESTURES_DEVCLASS_MULTITOUCH_MOUSE &&
80       gesture.type == kGestureTypeMove)
81     return false;
82 
83   return (gesture.type != kGestureTypeFling &&
84           gesture.type != kGestureTypeSwipeLift &&
85           gesture.type != kGestureTypeFourFingerSwipeLift);
86 }
87 
ConsumeGesture(const Gesture & gesture)88 void FlingStopFilterInterpreter::ConsumeGesture(const Gesture& gesture) {
89   const char name[] = "FlingStopFilterInterpreter::ConsumeGesture";
90   LogGestureConsume(name, gesture);
91 
92   if (gesture.type == kGestureTypeFling) {
93     fingers_present_for_last_fling_ = fingers_of_last_hwstate_;
94     already_extended_ = false;
95   }
96 
97   if (FlingStopNeeded(gesture)) {
98     // sub in a fling before a new gesture
99     auto fling_tap_down = Gesture(kGestureFling, gesture.start_time,
100                                   gesture.start_time, 0.0, 0.0,
101                                   GESTURES_FLING_TAP_DOWN);
102     LogGestureProduce(name, fling_tap_down);
103     ProduceGesture(fling_tap_down);
104   }
105   LogGestureProduce(name, gesture);
106   ProduceGesture(gesture);
107 
108   fling_stop_deadline_ = NO_DEADLINE;
109   prev_gesture_type_ = gesture.type;
110   fling_stop_already_sent_ = false;
111 }
112 
UpdateFlingStopDeadline(const HardwareState & hwstate)113 void FlingStopFilterInterpreter::UpdateFlingStopDeadline(
114     const HardwareState& hwstate) {
115   if (fling_stop_timeout_.val_ <= 0.0)
116     return;
117 
118   stime_t now = hwstate.timestamp;
119   bool finger_added = hwstate.touch_cnt > prev_touch_cnt_;
120 
121   if (finger_added && fling_stop_deadline_ == NO_DEADLINE) {
122     // first finger added in a while. Note it.
123     fling_stop_deadline_ = now + fling_stop_timeout_.val_;
124     return;
125   }
126 
127   prev_timestamp_ = now;
128   prev_touch_cnt_ = hwstate.touch_cnt;
129 }
130 
HandleTimerImpl(stime_t now,stime_t * timeout)131 void FlingStopFilterInterpreter::HandleTimerImpl(stime_t now,
132                                                  stime_t* timeout) {
133   const char name[] = "FlingStopFilterInterpreter::HandleTimerImpl";
134   LogHandleTimerPre(name, now, timeout);
135 
136   stime_t next_timeout;
137   if (ShouldCallNextTimer(fling_stop_deadline_)) {
138     if (next_timer_deadline_ > now) {
139       Err("Spurious callback. now: %f, fs deadline: %f, next deadline: %f",
140           now, fling_stop_deadline_, next_timer_deadline_);
141       return;
142     }
143     next_timeout = NO_DEADLINE;
144     next_->HandleTimer(now, &next_timeout);
145   } else {
146     if (fling_stop_deadline_ > now) {
147       Err("Spurious callback. now: %f, fs deadline: %f, next deadline: %f",
148           now, fling_stop_deadline_, next_timer_deadline_);
149       return;
150     }
151     fling_stop_deadline_ = NO_DEADLINE;
152     auto fling_tap_down = Gesture(kGestureFling, prev_timestamp_,
153                                   now, 0.0, 0.0,
154                                   GESTURES_FLING_TAP_DOWN);
155     LogGestureProduce(name, fling_tap_down);
156     ProduceGesture(fling_tap_down);
157 
158     fling_stop_already_sent_ = true;
159     next_timeout = next_timer_deadline_ == NO_DEADLINE ||
160                    next_timer_deadline_ <= now
161                       ? NO_DEADLINE
162                       : next_timer_deadline_ - now;
163   }
164   *timeout = SetNextDeadlineAndReturnTimeoutVal(now, fling_stop_deadline_,
165                                                 next_timeout);
166   LogHandleTimerPost(name, now, timeout);
167 }
168 
169 }  // namespace gestures
170