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(NULL, 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 fingers_of_last_hwstate_.clear();
29 for (int i = 0; i < hwstate->finger_cnt; i++)
30 fingers_of_last_hwstate_.insert(hwstate->fingers[i].tracking_id);
31
32 UpdateFlingStopDeadline(*hwstate);
33
34 stime_t next_timeout = NO_DEADLINE;
35 if (fling_stop_deadline_ != NO_DEADLINE) {
36 if (!already_extended_ && NeedsExtraTime(*hwstate)) {
37 fling_stop_deadline_ += fling_stop_extra_delay_.val_;
38 already_extended_ = true;
39 }
40 if (hwstate->timestamp > fling_stop_deadline_) {
41 // sub in a fling before processing other interpreters
42 ProduceGesture(Gesture(kGestureFling, prev_timestamp_,
43 hwstate->timestamp, 0.0, 0.0,
44 GESTURES_FLING_TAP_DOWN));
45 fling_stop_already_sent_ = true;
46 fling_stop_deadline_ = NO_DEADLINE;
47 }
48 }
49 next_->SyncInterpret(hwstate, &next_timeout);
50 *timeout = SetNextDeadlineAndReturnTimeoutVal(hwstate->timestamp,
51 fling_stop_deadline_,
52 next_timeout);
53 }
54
NeedsExtraTime(const HardwareState & hwstate) const55 bool FlingStopFilterInterpreter::NeedsExtraTime(
56 const HardwareState& hwstate) const {
57 int num_new_fingers = 0;
58 for (int i = 0; i < hwstate.finger_cnt; i++) {
59 const short id = hwstate.fingers[i].tracking_id;
60 if (!SetContainsValue(fingers_present_for_last_fling_, id)) {
61 num_new_fingers++;
62 }
63 }
64
65 return (num_new_fingers >= 2);
66 }
67
FlingStopNeeded(const Gesture & gesture) const68 bool FlingStopFilterInterpreter::FlingStopNeeded(const Gesture& gesture) const {
69 if (fling_stop_already_sent_ || gesture.type == prev_gesture_type_)
70 return false;
71
72 if (devclass_ == GESTURES_DEVCLASS_MULTITOUCH_MOUSE &&
73 gesture.type == kGestureTypeMove)
74 return false;
75
76 return (gesture.type != kGestureTypeFling &&
77 gesture.type != kGestureTypeSwipeLift &&
78 gesture.type != kGestureTypeFourFingerSwipeLift);
79 }
80
ConsumeGesture(const Gesture & gesture)81 void FlingStopFilterInterpreter::ConsumeGesture(const Gesture& gesture) {
82 if (gesture.type == kGestureTypeFling) {
83 fingers_present_for_last_fling_ = fingers_of_last_hwstate_;
84 already_extended_ = false;
85 }
86
87 if (FlingStopNeeded(gesture)) {
88 // sub in a fling before a new gesture
89 ProduceGesture(Gesture(kGestureFling, gesture.start_time,
90 gesture.start_time, 0.0, 0.0,
91 GESTURES_FLING_TAP_DOWN));
92 }
93 ProduceGesture(gesture);
94 fling_stop_deadline_ = NO_DEADLINE;
95 prev_gesture_type_ = gesture.type;
96 fling_stop_already_sent_ = false;
97 }
98
UpdateFlingStopDeadline(const HardwareState & hwstate)99 void FlingStopFilterInterpreter::UpdateFlingStopDeadline(
100 const HardwareState& hwstate) {
101 if (fling_stop_timeout_.val_ <= 0.0)
102 return;
103
104 stime_t now = hwstate.timestamp;
105 bool finger_added = hwstate.touch_cnt > prev_touch_cnt_;
106
107 if (finger_added && fling_stop_deadline_ == NO_DEADLINE) {
108 // first finger added in a while. Note it.
109 fling_stop_deadline_ = now + fling_stop_timeout_.val_;
110 return;
111 }
112
113 prev_timestamp_ = now;
114 prev_touch_cnt_ = hwstate.touch_cnt;
115 }
116
HandleTimerImpl(stime_t now,stime_t * timeout)117 void FlingStopFilterInterpreter::HandleTimerImpl(stime_t now,
118 stime_t* timeout) {
119 if (!ShouldCallNextTimer(fling_stop_deadline_)) {
120 if (fling_stop_deadline_ > now) {
121 Err("Spurious callback. now: %f, fs deadline: %f, next deadline: %f",
122 now, fling_stop_deadline_, next_timer_deadline_);
123 return;
124 }
125 fling_stop_deadline_ = NO_DEADLINE;
126 ProduceGesture(Gesture(kGestureFling, prev_timestamp_,
127 now, 0.0, 0.0,
128 GESTURES_FLING_TAP_DOWN));
129 fling_stop_already_sent_ = true;
130 stime_t next_timeout =
131 next_timer_deadline_ == NO_DEADLINE || next_timer_deadline_ <= now ?
132 NO_DEADLINE : next_timer_deadline_ - now;
133 *timeout = SetNextDeadlineAndReturnTimeoutVal(now, fling_stop_deadline_,
134 next_timeout);
135 return;
136 }
137 // Call next_
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 stime_t next_timeout = NO_DEADLINE;
144 next_->HandleTimer(now, &next_timeout);
145 *timeout = SetNextDeadlineAndReturnTimeoutVal(now, fling_stop_deadline_,
146 next_timeout);
147 }
148
149 } // namespace gestures
150