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