• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/immediate_interpreter.h"
6 
7 #include <algorithm>
8 #include <cmath>
9 #include <cstdlib>
10 #include <cstring>
11 #include <functional>
12 #include <limits>
13 #include <tuple>
14 
15 #include "include/gestures.h"
16 #include "include/logging.h"
17 #include "include/util.h"
18 
19 using std::bind;
20 using std::for_each;
21 using std::make_pair;
22 using std::make_tuple;
23 using std::max;
24 using std::min;
25 using std::tuple;
26 
27 namespace gestures {
28 
29 namespace {
30 
MaxMag(float a,float b)31 float MaxMag(float a, float b) {
32   if (fabsf(a) > fabsf(b))
33     return a;
34   return b;
35 }
MinMag(float a,float b)36 float MinMag(float a, float b) {
37   if (fabsf(a) < fabsf(b))
38     return a;
39   return b;
40 }
41 
42 // A comparator class for use with STL algorithms that sorts FingerStates
43 // by their origin timestamp.
44 class FingerOriginCompare {
45  public:
FingerOriginCompare(const ImmediateInterpreter * interpreter)46   explicit FingerOriginCompare(const ImmediateInterpreter* interpreter)
47       : interpreter_(interpreter) {
48   }
operator ()(const FingerState * a,const FingerState * b) const49   bool operator() (const FingerState* a, const FingerState* b) const {
50     return interpreter_->finger_origin_timestamp(a->tracking_id) <
51            interpreter_->finger_origin_timestamp(b->tracking_id);
52   }
53 
54  private:
55   const ImmediateInterpreter* interpreter_;
56 };
57 
58 }  // namespace {}
59 
NoteTouch(short the_id,const FingerState & fs)60 void TapRecord::NoteTouch(short the_id, const FingerState& fs) {
61   // New finger must be close enough to an existing finger
62   if (!touched_.empty()) {
63     bool reject_new_finger = true;
64     for (std::map<short, FingerState>::const_iterator it =
65              touched_.begin(), e = touched_.end(); it != e; ++it) {
66       const FingerState& existing_fs = (*it).second;
67       if (immediate_interpreter_->metrics_->CloseEnoughToGesture(
68               Vector2(existing_fs),
69               Vector2(fs))) {
70         reject_new_finger = false;
71         break;
72       }
73     }
74     if (reject_new_finger)
75       return;
76   }
77   touched_[the_id] = fs;
78 }
79 
NoteRelease(short the_id)80 void TapRecord::NoteRelease(short the_id) {
81   if (touched_.find(the_id) != touched_.end())
82     released_.insert(the_id);
83 }
84 
Remove(short the_id)85 void TapRecord::Remove(short the_id) {
86   min_tap_pressure_met_.erase(the_id);
87   min_cotap_pressure_met_.erase(the_id);
88   touched_.erase(the_id);
89   released_.erase(the_id);
90 }
91 
CotapMinPressure() const92 float TapRecord::CotapMinPressure() const {
93   return immediate_interpreter_->tap_min_pressure() * 0.5;
94 }
95 
Update(const HardwareState & hwstate,const HardwareState & prev_hwstate,const std::set<short> & added,const std::set<short> & removed,const std::set<short> & dead)96 void TapRecord::Update(const HardwareState& hwstate,
97                        const HardwareState& prev_hwstate,
98                        const std::set<short>& added,
99                        const std::set<short>& removed,
100                        const std::set<short>& dead) {
101   if (!t5r2_ && (hwstate.finger_cnt != hwstate.touch_cnt ||
102                  prev_hwstate.finger_cnt != prev_hwstate.touch_cnt)) {
103     // switch to T5R2 mode
104     t5r2_ = true;
105     t5r2_touched_size_ = touched_.size();
106     t5r2_released_size_ = released_.size();
107   }
108   if (t5r2_) {
109     short diff = static_cast<short>(hwstate.touch_cnt) -
110         static_cast<short>(prev_hwstate.touch_cnt);
111     if (diff > 0)
112       t5r2_touched_size_ += diff;
113     else if (diff < 0)
114       t5r2_released_size_ += -diff;
115   }
116   for (std::set<short>::const_iterator it = added.begin(),
117            e = added.end(); it != e; ++it)
118     Log("TapRecord::Update: Added: %d", *it);
119   for (std::set<short>::const_iterator it = removed.begin(),
120            e = removed.end(); it != e; ++it)
121     Log("TapRecord::Update: Removed: %d", *it);
122   for (std::set<short>::const_iterator it = dead.begin(),
123            e = dead.end(); it != e; ++it)
124     Log("TapRecord::Update: Dead: %d", *it);
125   for_each(dead.begin(), dead.end(),
126            bind(&TapRecord::Remove, this, std::placeholders::_1));
127   for (std::set<short>::const_iterator it = added.begin(),
128            e = added.end(); it != e; ++it)
129     NoteTouch(*it, *hwstate.GetFingerState(*it));
130   for_each(removed.begin(), removed.end(),
131            bind(&TapRecord::NoteRelease, this, std::placeholders::_1));
132   // Check if min tap/cotap pressure met yet
133   const float cotap_min_pressure = CotapMinPressure();
134   for (std::map<short, FingerState>::iterator it =
135            touched_.begin(), e = touched_.end();
136        it != e; ++it) {
137     const FingerState* fs = hwstate.GetFingerState((*it).first);
138     if (fs) {
139       if (fs->pressure >= immediate_interpreter_->tap_min_pressure())
140         min_tap_pressure_met_.insert(fs->tracking_id);
141       if (fs->pressure >= cotap_min_pressure) {
142         min_cotap_pressure_met_.insert(fs->tracking_id);
143         if ((*it).second.pressure < cotap_min_pressure) {
144           // Update existing record, since the old one hadn't met the cotap
145           // pressure
146           (*it).second = *fs;
147         }
148       }
149       stime_t finger_age = hwstate.timestamp -
150           immediate_interpreter_->finger_origin_timestamp(fs->tracking_id);
151       if (finger_age > immediate_interpreter_->tap_max_finger_age())
152         fingers_below_max_age_ = false;
153     }
154   }
155 }
156 
Clear()157 void TapRecord::Clear() {
158   min_tap_pressure_met_.clear();
159   min_cotap_pressure_met_.clear();
160   t5r2_ = false;
161   t5r2_touched_size_ = 0;
162   t5r2_released_size_ = 0;
163   fingers_below_max_age_ = true;
164   touched_.clear();
165   released_.clear();
166 }
167 
Moving(const HardwareState & hwstate,const float dist_max) const168 bool TapRecord::Moving(const HardwareState& hwstate,
169                        const float dist_max) const {
170   const float cotap_min_pressure = CotapMinPressure();
171   for (std::map<short, FingerState>::const_iterator it =
172            touched_.begin(), e = touched_.end(); it != e; ++it) {
173     const FingerState* fs = hwstate.GetFingerState((*it).first);
174     if (!fs)
175       continue;
176     // Only look for moving when current frame meets cotap pressure and
177     // our history contains a contact that's met cotap pressure.
178     if (fs->pressure < cotap_min_pressure ||
179         (*it).second.pressure < cotap_min_pressure)
180       continue;
181     // Compute distance moved
182     float dist_x = fs->position_x - (*it).second.position_x;
183     float dist_y = fs->position_y - (*it).second.position_y;
184     // Respect WARP flags
185     if (fs->flags & GESTURES_FINGER_WARP_X_TAP_MOVE)
186       dist_x = 0.0;
187     if (fs->flags & GESTURES_FINGER_WARP_X_TAP_MOVE)
188       dist_y = 0.0;
189 
190     bool moving =
191         dist_x * dist_x + dist_y * dist_y > dist_max * dist_max;
192     if (moving)
193       return true;
194   }
195   return false;
196 }
197 
Motionless(const HardwareState & hwstate,const HardwareState & prev_hwstate,const float max_speed) const198 bool TapRecord::Motionless(const HardwareState& hwstate, const HardwareState&
199                            prev_hwstate, const float max_speed) const {
200   const float cotap_min_pressure = CotapMinPressure();
201   for (std::map<short, FingerState>::const_iterator it =
202            touched_.begin(), e = touched_.end(); it != e; ++it) {
203     const FingerState* fs = hwstate.GetFingerState((*it).first);
204     const FingerState* prev_fs = prev_hwstate.GetFingerState((*it).first);
205     if (!fs || !prev_fs)
206       continue;
207     // Only look for moving when current frame meets cotap pressure and
208     // our history contains a contact that's met cotap pressure.
209     if (fs->pressure < cotap_min_pressure ||
210         prev_fs->pressure < cotap_min_pressure)
211       continue;
212     // Compute distance moved
213     if (DistSq(*fs, *prev_fs) > max_speed * max_speed)
214       return false;
215   }
216   return true;
217 }
218 
TapBegan() const219 bool TapRecord::TapBegan() const {
220   if (t5r2_)
221     return t5r2_touched_size_ > 0;
222   return !touched_.empty();
223 }
224 
TapComplete() const225 bool TapRecord::TapComplete() const {
226   bool ret = false;
227   if (t5r2_)
228     ret = t5r2_touched_size_ && t5r2_touched_size_ == t5r2_released_size_;
229   else
230     ret = !touched_.empty() && (touched_.size() == released_.size());
231   for (std::map<short, FingerState>::const_iterator
232            it = touched_.begin(), e = touched_.end(); it != e; ++it)
233     Log("TapRecord::TapComplete: touched_: %d", (*it).first);
234   for (std::set<short>::const_iterator it = released_.begin(),
235            e = released_.end(); it != e; ++it)
236     Log("TapRecord::TapComplete: released_: %d", *it);
237   return ret;
238 }
239 
MinTapPressureMet() const240 bool TapRecord::MinTapPressureMet() const {
241   // True if any touching finger met minimum pressure
242   return t5r2_ || !min_tap_pressure_met_.empty();
243 }
244 
FingersBelowMaxAge() const245 bool TapRecord::FingersBelowMaxAge() const {
246   return fingers_below_max_age_;
247 }
248 
TapType() const249 int TapRecord::TapType() const {
250   size_t touched_size =
251       t5r2_ ? t5r2_touched_size_ : min_cotap_pressure_met_.size();
252   int ret = GESTURES_BUTTON_LEFT;
253   if (touched_size > 1)
254     ret = GESTURES_BUTTON_RIGHT;
255   if (touched_size == 3 &&
256       immediate_interpreter_->three_finger_click_enable_.val_ &&
257       (!t5r2_ || immediate_interpreter_->t5r2_three_finger_click_enable_.val_))
258     ret = GESTURES_BUTTON_MIDDLE;
259   return ret;
260 }
261 
262 // static
Add(const ScrollEvent & evt_a,const ScrollEvent & evt_b)263 ScrollEvent ScrollEvent::Add(const ScrollEvent& evt_a,
264                              const ScrollEvent& evt_b) {
265   ScrollEvent ret = { evt_a.dx + evt_b.dx,
266                       evt_a.dy + evt_b.dy,
267                       evt_a.dt + evt_b.dt };
268   return ret;
269 }
270 
Insert(float dx,float dy,float dt)271 void ScrollEventBuffer::Insert(float dx, float dy, float dt) {
272   head_ = (head_ + max_size_ - 1) % max_size_;
273   buf_[head_].dx = dx;
274   buf_[head_].dy = dy;
275   buf_[head_].dt = dt;
276   size_ = std::min(size_ + 1, max_size_);
277 }
278 
Clear()279 void ScrollEventBuffer::Clear() {
280   size_ = 0;
281 }
282 
Get(size_t offset) const283 const ScrollEvent& ScrollEventBuffer::Get(size_t offset) const {
284   if (offset >= size_) {
285     Err("Out of bounds access!");
286     // avoid returning null pointer
287     static ScrollEvent dummy_event = { 0.0, 0.0, 0.0 };
288     return dummy_event;
289   }
290   return buf_[(head_ + offset) % max_size_];
291 }
292 
GetSpeedSq(size_t num_events,float * dist_sq,float * dt) const293 void ScrollEventBuffer::GetSpeedSq(size_t num_events, float* dist_sq,
294                                    float* dt) const {
295   float dx = 0.0;
296   float dy = 0.0;
297   *dt = 0.0;
298   for (size_t i = 0; i < Size() && i < num_events; i++) {
299     const ScrollEvent& evt = Get(i);
300     dx += evt.dx;
301     dy += evt.dy;
302     *dt += evt.dt;
303   }
304   *dist_sq = dx * dx + dy * dy;
305 }
306 
HardwareStateBuffer(size_t size)307 HardwareStateBuffer::HardwareStateBuffer(size_t size)
308     : states_(new HardwareState[size]),
309       newest_index_(0), size_(size), max_finger_cnt_(0) {
310   for (size_t i = 0; i < size_; i++) {
311     memset(&states_[i], 0, sizeof(HardwareState));
312   }
313 }
314 
~HardwareStateBuffer()315 HardwareStateBuffer::~HardwareStateBuffer() {
316   for (size_t i = 0; i < size_; i++) {
317     delete[] states_[i].fingers;
318   }
319 }
320 
Reset(size_t max_finger_cnt)321 void HardwareStateBuffer::Reset(size_t max_finger_cnt) {
322   max_finger_cnt_ = max_finger_cnt;
323   for (size_t i = 0; i < size_; i++) {
324     delete[] states_[i].fingers;
325   }
326   if (max_finger_cnt_) {
327     for (size_t i = 0; i < size_; i++) {
328       states_[i].fingers = new FingerState[max_finger_cnt_];
329       memset(states_[i].fingers, 0, sizeof(FingerState) * max_finger_cnt_);
330     }
331   } else {
332     for (size_t i = 0; i < size_; i++) {
333       states_[i].fingers = NULL;
334     }
335   }
336 }
337 
PushState(const HardwareState & state)338 void HardwareStateBuffer::PushState(const HardwareState& state) {
339   newest_index_ = (newest_index_ + size_ - 1) % size_;
340   Get(0)->DeepCopy(state, max_finger_cnt_);
341 }
342 
PopState()343 void HardwareStateBuffer::PopState() {
344   newest_index_ = (newest_index_ + 1) % size_;
345 }
346 
ScrollManager(PropRegistry * prop_reg)347 ScrollManager::ScrollManager(PropRegistry* prop_reg)
348     : prev_result_suppress_finger_movement_(false),
349       did_generate_scroll_(false),
350       max_stationary_move_speed_(prop_reg, "Max Stationary Move Speed", 0.0),
351       max_stationary_move_speed_hysteresis_(
352           prop_reg, "Max Stationary Move Speed Hysteresis", 0.0),
353       max_stationary_move_suppress_distance_(
354           prop_reg, "Max Stationary Move Suppress Distance", 1.0),
355       max_pressure_change_(prop_reg, "Max Allowed Pressure Change Per Sec",
356                            800.0),
357       max_pressure_change_hysteresis_(prop_reg,
358                                       "Max Hysteresis Pressure Per Sec",
359                                       600.0),
360       max_pressure_change_duration_(prop_reg,
361                                     "Max Pressure Change Duration",
362                                     0.016),
363       max_stationary_speed_(prop_reg, "Max Finger Stationary Speed", 0.0),
364       vertical_scroll_snap_slope_(prop_reg, "Vertical Scroll Snap Slope",
365                                   tanf(DegToRad(50.0))),  // 50 deg. from horiz.
366       horizontal_scroll_snap_slope_(prop_reg, "Horizontal Scroll Snap Slope",
367                                     tanf(DegToRad(30.0))),
368 
369       fling_buffer_depth_(prop_reg, "Fling Buffer Depth", 10),
370       fling_buffer_suppress_zero_length_scrolls_(
371           prop_reg, "Fling Buffer Suppress Zero Length Scrolls", true),
372       fling_buffer_min_avg_speed_(prop_reg,
373                                   "Fling Buffer Min Avg Speed",
374                                   10.0) {
375 }
376 
StationaryFingerPressureChangingSignificantly(const HardwareStateBuffer & state_buffer,const FingerState & current) const377 bool ScrollManager::StationaryFingerPressureChangingSignificantly(
378     const HardwareStateBuffer& state_buffer,
379     const FingerState& current) const {
380   bool pressure_is_increasing = false;
381   bool pressure_direction_established = false;
382   const FingerState* prev = &current;
383   stime_t now = state_buffer.Get(0)->timestamp;
384   stime_t duration = 0.0;
385 
386   if (max_pressure_change_duration_.val_ > 0.0) {
387     for (size_t i = 1; i < state_buffer.Size(); i++) {
388       const HardwareState& state = *state_buffer.Get(i);
389       stime_t local_duration = now - state.timestamp;
390       if (local_duration > max_pressure_change_duration_.val_)
391         break;
392 
393       duration = local_duration;
394       const FingerState* fs = state.GetFingerState(current.tracking_id);
395       // If the finger just appeared, skip to check pressure change then
396       if (!fs)
397         break;
398 
399       float pressure_difference = prev->pressure - fs->pressure;
400       if (pressure_difference) {
401         bool is_currently_increasing = pressure_difference > 0.0;
402         if (!pressure_direction_established) {
403           pressure_is_increasing = is_currently_increasing;
404           pressure_direction_established = true;
405         }
406 
407         // If pressure changes are unstable, it's likely just noise.
408         if (is_currently_increasing != pressure_is_increasing)
409           return false;
410       }
411       prev = fs;
412     }
413   } else {
414     // To disable this feature, max_pressure_change_duration_ can be set to a
415     // negative number. When this occurs it reverts to just checking the last
416     // event, not looking through the backlog as well.
417     prev = state_buffer.Get(1)->GetFingerState(current.tracking_id);
418     duration = now - state_buffer.Get(1)->timestamp;
419   }
420 
421   if (max_stationary_speed_.val_ != 0.0) {
422     // If finger moves too fast, we don't consider it stationary.
423     float dist_sq = (current.position_x - prev->position_x) *
424                     (current.position_x - prev->position_x) +
425                     (current.position_y - prev->position_y) *
426                     (current.position_y - prev->position_y);
427     float dist_sq_thresh = duration * duration *
428         max_stationary_speed_.val_ * max_stationary_speed_.val_;
429     if (dist_sq > dist_sq_thresh)
430       return false;
431   }
432 
433   float dp_thresh = duration *
434       (prev_result_suppress_finger_movement_ ?
435        max_pressure_change_hysteresis_.val_ :
436        max_pressure_change_.val_);
437   float dp = fabsf(current.pressure - prev->pressure);
438   return dp > dp_thresh;
439 }
440 
FillResultScroll(const HardwareStateBuffer & state_buffer,const FingerMap & prev_gs_fingers,const FingerMap & gs_fingers,GestureType prev_gesture_type,const Gesture & prev_result,Gesture * result,ScrollEventBuffer * scroll_buffer)441 bool ScrollManager::FillResultScroll(
442     const HardwareStateBuffer& state_buffer,
443     const FingerMap& prev_gs_fingers,
444     const FingerMap& gs_fingers,
445     GestureType prev_gesture_type,
446     const Gesture& prev_result,
447     Gesture* result,
448     ScrollEventBuffer* scroll_buffer) {
449   // For now, we take the movement of the biggest moving finger.
450   float max_mag_sq = 0.0;  // square of max mag
451   float dx = 0.0;
452   float dy = 0.0;
453   bool stationary = true;
454   bool pressure_changing = false;
455   for (FingerMap::const_iterator it =
456            gs_fingers.begin(), e = gs_fingers.end(); it != e; ++it) {
457     const FingerState* fs = state_buffer.Get(0)->GetFingerState(*it);
458     const FingerState* prev = state_buffer.Get(1)->GetFingerState(*it);
459     if (!prev)
460       return false;
461     const stime_t dt =
462         state_buffer.Get(0)->timestamp - state_buffer.Get(1)->timestamp;
463     pressure_changing =
464         pressure_changing ||
465         StationaryFingerPressureChangingSignificantly(state_buffer, *fs);
466     // Call SuppressStationaryFingerMovement even if stationary is already true,
467     // because it records updates.
468     stationary =
469         SuppressStationaryFingerMovement(*fs, *prev, dt) &&
470         stationary;
471     float local_dx = fs->position_x - prev->position_x;
472     if (fs->flags & GESTURES_FINGER_WARP_X_NON_MOVE)
473       local_dx = 0.0;
474     float local_dy = fs->position_y - prev->position_y;
475     if (fs->flags & GESTURES_FINGER_WARP_Y_NON_MOVE)
476       local_dy = 0.0;
477     float local_max_mag_sq = local_dx * local_dx + local_dy * local_dy;
478     if (local_max_mag_sq > max_mag_sq) {
479       max_mag_sq = local_max_mag_sq;
480       dx = local_dx;
481       dy = local_dy;
482     }
483   }
484 
485   // See if we should snap to vertical/horizontal
486   if (fabsf(dy) < horizontal_scroll_snap_slope_.val_ * fabsf(dx))
487     dy = 0.0;  // snap to horizontal
488   else if (fabsf(dy) > vertical_scroll_snap_slope_.val_ * fabsf(dx))
489     dx = 0.0;  // snap to vertical
490 
491   prev_result_suppress_finger_movement_ = pressure_changing || stationary;
492   if (pressure_changing) {
493     // If we get here, it means that the pressure of the finger causing
494     // the scroll is changing a lot, so we don't trust it. It's likely
495     // leaving the touchpad. Normally we might just do nothing, but having
496     // a frame or two of 0 length scroll before a fling looks janky. We
497     // could also just start the fling now, but we don't want to do that
498     // because the fingers may not actually be leaving. What seems to work
499     // well is sort of dead-reckoning approach where we just repeat the
500     // scroll event from the previous input frame.
501     // Since this isn't a "real" scroll event, we don't put it into
502     // scroll_buffer_.
503     // Also, only use previous gesture if it's in the same direction.
504     if (prev_result.type == kGestureTypeScroll &&
505         prev_result.details.scroll.dy * dy >= 0 &&
506         prev_result.details.scroll.dx * dx >= 0) {
507       did_generate_scroll_ = true;
508       *result = prev_result;
509     }
510     return false;
511   }
512 
513   if (stationary) {
514     scroll_buffer->Clear();
515     return false;
516   }
517 
518   if (max_mag_sq > 0) {
519     did_generate_scroll_ = true;
520     *result = Gesture(kGestureScroll,
521                       state_buffer.Get(1)->timestamp,
522                       state_buffer.Get(0)->timestamp,
523                       dx, dy);
524   }
525   if (prev_gesture_type != kGestureTypeScroll || prev_gs_fingers != gs_fingers)
526     scroll_buffer->Clear();
527   if (!fling_buffer_suppress_zero_length_scrolls_.val_ ||
528       !FloatEq(dx, 0.0) || !FloatEq(dy, 0.0))
529     scroll_buffer->Insert(
530         dx, dy,
531         state_buffer.Get(0)->timestamp - state_buffer.Get(1)->timestamp);
532   return true;
533 }
534 
UpdateScrollEventBuffer(GestureType gesture_type,ScrollEventBuffer * scroll_buffer) const535 void ScrollManager::UpdateScrollEventBuffer(
536     GestureType gesture_type, ScrollEventBuffer* scroll_buffer) const {
537   if (gesture_type != kGestureTypeScroll)
538     scroll_buffer->Clear();
539 }
540 
ScrollEventsForFlingCount(const ScrollEventBuffer & scroll_buffer) const541 size_t ScrollManager::ScrollEventsForFlingCount(
542     const ScrollEventBuffer& scroll_buffer) const {
543   if (scroll_buffer.Size() <= 1)
544     return scroll_buffer.Size();
545   enum Direction { kNone, kUp, kDown, kLeft, kRight };
546   size_t i = 0;
547   Direction prev_direction = kNone;
548   size_t fling_buffer_depth = static_cast<size_t>(fling_buffer_depth_.val_);
549   for (; i < scroll_buffer.Size() && i < fling_buffer_depth; i++) {
550     const ScrollEvent& event = scroll_buffer.Get(i);
551     if (FloatEq(event.dx, 0.0) && FloatEq(event.dy, 0.0))
552       break;
553     Direction direction;
554     if (fabsf(event.dx) > fabsf(event.dy))
555       direction = event.dx > 0 ? kRight : kLeft;
556     else
557       direction = event.dy > 0 ? kDown : kUp;
558     if (i > 0 && direction != prev_direction)
559       break;
560     prev_direction = direction;
561   }
562   return i;
563 }
564 
RegressScrollVelocity(const ScrollEventBuffer & scroll_buffer,int count,ScrollEvent * out) const565 void ScrollManager::RegressScrollVelocity(
566     const ScrollEventBuffer& scroll_buffer, int count, ScrollEvent* out) const {
567   struct RegressionSums {
568     float tt_;  // Cumulative sum of t^2.
569     float t_;   // Cumulative sum of t.
570     float tx_;  // Cumulative sum of t * x.
571     float ty_;  // Cumulative sum of t * y.
572     float x_;   // Cumulative sum of x.
573     float y_;   // Cumulative sum of y.
574   };
575 
576   out->dt = 1;
577   if (count <= 1) {
578     out->dx = 0;
579     out->dy = 0;
580     return;
581   }
582 
583   RegressionSums sums = {0, 0, 0, 0, 0, 0};
584 
585   float time = 0;
586   float x_coord = 0;
587   float y_coord = 0;
588 
589   for (int i = count - 1; i >= 0; --i) {
590     const ScrollEvent& event = scroll_buffer.Get(i);
591 
592     time += event.dt;
593     x_coord += event.dx;
594     y_coord += event.dy;
595 
596     sums.tt_ += time * time;
597     sums.t_ += time;
598     sums.tx_ += time * x_coord;
599     sums.ty_ += time * y_coord;
600     sums.x_ += x_coord;
601     sums.y_ += y_coord;
602   }
603 
604   // Note the regression determinant only depends on the values of t, and should
605   // never be zero so long as (1) count > 1, and (2) dt values are all non-zero.
606   float det = count * sums.tt_ - sums.t_ * sums.t_;
607 
608   if (det) {
609     float det_inv = 1.0 / det;
610 
611     out->dx = (count * sums.tx_ - sums.t_ * sums.x_) * det_inv;
612     out->dy = (count * sums.ty_ - sums.t_ * sums.y_) * det_inv;
613   } else {
614     out->dx = 0;
615     out->dy = 0;
616   }
617 }
618 
SuppressStationaryFingerMovement(const FingerState & fs,const FingerState & prev,stime_t dt)619 bool ScrollManager::SuppressStationaryFingerMovement(const FingerState& fs,
620                                                      const FingerState& prev,
621                                                      stime_t dt) {
622   if (max_stationary_move_speed_.val_ <= 0.0 ||
623       max_stationary_move_suppress_distance_.val_ <= 0.0)
624     return false;
625   float dist_sq = DistSq(fs, prev);
626   // If speed exceeded, allow free movement and discard history
627   if (dist_sq > dt * dt *
628       max_stationary_move_speed_.val_ * max_stationary_move_speed_.val_) {
629     stationary_start_positions_.erase(fs.tracking_id);
630     return false;
631   }
632 
633   if (dist_sq <= dt * dt *
634       max_stationary_move_speed_hysteresis_.val_ *
635       max_stationary_move_speed_hysteresis_.val_ &&
636       !MapContainsKey(stationary_start_positions_, fs.tracking_id)) {
637     // We assume that the first nearly-stationay event won't exceed the
638     // distance threshold and return from here.
639     Point point(fs.position_x, fs.position_y);
640     stationary_start_positions_[fs.tracking_id] = point;
641     return true;
642   }
643 
644   if (!MapContainsKey(stationary_start_positions_, fs.tracking_id)) {
645     return false;
646   }
647 
648   // Check if distance exceeded. If so, erase history and allow motion
649   float dx = fs.position_x - stationary_start_positions_[fs.tracking_id].x_;
650   float dy = fs.position_y - stationary_start_positions_[fs.tracking_id].y_;
651   if (dx * dx + dy * dy > max_stationary_move_suppress_distance_.val_ *
652       max_stationary_move_suppress_distance_.val_) {
653     stationary_start_positions_.erase(fs.tracking_id);
654     return false;
655   }
656 
657   return true;
658 }
659 
FillResultFling(const HardwareStateBuffer & state_buffer,const ScrollEventBuffer & scroll_buffer,Gesture * result)660 void ScrollManager::FillResultFling(const HardwareStateBuffer& state_buffer,
661                                  const ScrollEventBuffer& scroll_buffer,
662                                  Gesture* result) {
663   if (!did_generate_scroll_)
664     return;
665   ScrollEvent out = { 0.0, 0.0, 0.0 };
666   ScrollEvent zero = { 0.0, 0.0, 0.0 };
667   size_t count = 0;
668 
669   // Make sure fling buffer met the minimum average speed for a fling.
670   float buf_dist_sq = 0.0;
671   float buf_dt = 0.0;
672   scroll_buffer.GetSpeedSq(fling_buffer_depth_.val_, &buf_dist_sq, &buf_dt);
673   if (fling_buffer_min_avg_speed_.val_ * fling_buffer_min_avg_speed_.val_ *
674       buf_dt * buf_dt > buf_dist_sq) {
675     out = zero;
676     goto done;
677   }
678 
679   count = ScrollEventsForFlingCount(scroll_buffer);
680   if (count > scroll_buffer.Size()) {
681     Err("Too few events in scroll buffer");
682     out = zero;
683     goto done;
684   }
685 
686   if (count < 2) {
687     if (count == 0)
688       out = zero;
689     else if (count == 1)
690       out = scroll_buffer.Get(0);
691     goto done;
692   }
693 
694   // If we get here, count == 3 && scroll_buffer.Size() >= 3
695   RegressScrollVelocity(scroll_buffer, count, &out);
696 
697 done:
698   float vx = out.dt ? (out.dx / out.dt) : 0.0;
699   float vy = out.dt ? (out.dy / out.dt) : 0.0;
700   *result = Gesture(kGestureFling,
701                     state_buffer.Get(1)->timestamp,
702                     state_buffer.Get(0)->timestamp,
703                     vx,
704                     vy,
705                     GESTURES_FLING_START);
706   did_generate_scroll_ = false;
707 }
708 
FingerButtonClick(const ImmediateInterpreter * interpreter)709 FingerButtonClick::FingerButtonClick(const ImmediateInterpreter* interpreter)
710     : interpreter_(interpreter),
711       fingers_(),
712       fingers_status_(),
713       num_fingers_(0),
714       num_recent_(0),
715       num_cold_(0),
716       num_hot_(0) {
717 }
718 
Update(const HardwareState & hwstate,stime_t button_down_time)719 bool FingerButtonClick::Update(const HardwareState& hwstate,
720                                stime_t button_down_time) {
721   const float kMoveDistSq = interpreter_->button_move_dist_.val_ *
722                             interpreter_->button_move_dist_.val_;
723 
724   // Copy all fingers to an array, but leave out palms
725   num_fingers_ = 0;
726   for (int i = 0; i < hwstate.touch_cnt; ++i) {
727     const FingerState& fs = hwstate.fingers[i];
728     if (fs.flags & (GESTURES_FINGER_PALM | GESTURES_FINGER_POSSIBLE_PALM))
729       continue;
730     // we don't support more than 4 fingers
731     if (num_fingers_ >= 4)
732       return false;
733     fingers_[num_fingers_++] = &fs;
734   }
735 
736   // Single finger is trivial
737   if (num_fingers_ <= 1)
738     return false;
739 
740   // Sort fingers array by origin timestamp
741   FingerOriginCompare comparator(interpreter_);
742   std::sort(fingers_, fingers_ + num_fingers_, comparator);
743 
744   // The status describes if a finger is recent (touched down recently),
745   // cold (touched down a while ago, but did not move) or hot (has moved).
746   // However thumbs are always forced to be "cold".
747   for (int i = 0; i < num_fingers_; ++i) {
748     stime_t finger_age =
749         button_down_time -
750         interpreter_->finger_origin_timestamp(fingers_[i]->tracking_id);
751     bool moving_finger =
752         SetContainsValue(interpreter_->moving_, fingers_[i]->tracking_id) ||
753         (interpreter_->DistanceTravelledSq(*fingers_[i], true) > kMoveDistSq);
754     if (!SetContainsValue(interpreter_->pointing_, fingers_[i]->tracking_id))
755       fingers_status_[i] = STATUS_COLD;
756     else if (moving_finger)
757       fingers_status_[i] = STATUS_HOT;
758     else if (finger_age < interpreter_->right_click_second_finger_age_.val_)
759       fingers_status_[i] = STATUS_RECENT;
760     else
761       fingers_status_[i] = STATUS_COLD;
762   }
763 
764   num_recent_ = 0;
765   for (int i = 0; i < num_fingers_; ++i)
766     num_recent_ += (fingers_status_[i] == STATUS_RECENT);
767 
768   num_cold_ = 0;
769   for (int i = 0; i < num_fingers_; ++i)
770     num_cold_ += (fingers_status_[i] == STATUS_COLD);
771 
772   num_hot_ = num_fingers_ - num_recent_ - num_cold_;
773   return true;
774 }
775 
GetButtonTypeForTouchCount(int touch_count) const776 int FingerButtonClick::GetButtonTypeForTouchCount(int touch_count) const {
777   if (touch_count == 2)
778     return GESTURES_BUTTON_RIGHT;
779   if (touch_count == 3 && interpreter_->three_finger_click_enable_.val_)
780     return GESTURES_BUTTON_MIDDLE;
781   return GESTURES_BUTTON_LEFT;
782 }
783 
EvaluateTwoFingerButtonType()784 int FingerButtonClick::EvaluateTwoFingerButtonType() {
785   // Only one finger hot -> moving -> left click
786   if (num_hot_ == 1)
787     return GESTURES_BUTTON_LEFT;
788 
789   float start_delta =
790       fabs(interpreter_->finger_origin_timestamp(fingers_[0]->tracking_id) -
791            interpreter_->finger_origin_timestamp(fingers_[1]->tracking_id));
792 
793   // check if fingers are too close for a right click
794   const float kMin2fDistThreshSq =
795       interpreter_->tapping_finger_min_separation_.val_ *
796       interpreter_->tapping_finger_min_separation_.val_;
797   float dist_sq = DistSq(*fingers_[0], *fingers_[1]);
798   if (dist_sq < kMin2fDistThreshSq)
799     return GESTURES_BUTTON_LEFT;
800 
801   // fingers touched down at approx the same time
802   if (start_delta < interpreter_->right_click_start_time_diff_.val_) {
803     // If two fingers are both very recent, it could either be a right-click
804     // or the left-click of one click-and-drag gesture. Our heuristic is that
805     // for real right-clicks, two finger's pressure should be roughly the same
806     // and they tend not be vertically aligned.
807     const FingerState* min_fs = NULL;
808     const FingerState* fs = NULL;
809     if (fingers_[0]->pressure < fingers_[1]->pressure)
810       min_fs = fingers_[0], fs = fingers_[1];
811     else
812       min_fs = fingers_[1], fs = fingers_[0];
813     float min_pressure = min_fs->pressure;
814     // It takes higher pressure for the bottom finger to trigger the physical
815     // click and people tend to place fingers more vertically so that they have
816     // enough space to drag the content with ease.
817     bool likely_click_drag =
818         (fs->pressure >
819              min_pressure +
820                  interpreter_->click_drag_pressure_diff_thresh_.val_ &&
821          fs->pressure >
822              min_pressure *
823                  interpreter_->click_drag_pressure_diff_factor_.val_ &&
824          fs->position_y > min_fs->position_y);
825     float xdist = fabsf(fs->position_x - min_fs->position_x);
826     float ydist = fabsf(fs->position_y - min_fs->position_y);
827     if (likely_click_drag &&
828         ydist >= xdist * interpreter_->click_drag_min_slope_.val_)
829       return GESTURES_BUTTON_LEFT;
830     return GESTURES_BUTTON_RIGHT;
831   }
832 
833   // 1 finger is cold and in the dampened zone? Probably a thumb!
834   if (num_cold_ == 1 && interpreter_->FingerInDampenedZone(*fingers_[0]))
835     return GESTURES_BUTTON_LEFT;
836 
837   // Close fingers -> same hand -> right click
838   // Fingers apart -> second hand finger or thumb -> left click
839   if (interpreter_->TwoFingersGesturing(*fingers_[0], *fingers_[1], true))
840     return GESTURES_BUTTON_RIGHT;
841   else
842     return GESTURES_BUTTON_LEFT;
843 }
844 
EvaluateThreeOrMoreFingerButtonType()845 int FingerButtonClick::EvaluateThreeOrMoreFingerButtonType() {
846   // Treat recent, ambiguous fingers as thumbs if they are in the dampened
847   // zone.
848   int num_dampened_recent = 0;
849   for (int i = num_fingers_ - num_recent_; i < num_fingers_; ++i)
850     num_dampened_recent += interpreter_->FingerInDampenedZone(*fingers_[i]);
851 
852   // Re-use the 2f button type logic in case that all recent fingers are
853   // presumed thumbs because the recent fingers could be from thumb splits
854   // due to the increased pressure when doing a physical click and should be
855   // ignored.
856   if ((num_fingers_ - num_recent_ == 2) &&
857       (num_recent_ == num_dampened_recent))
858     return EvaluateTwoFingerButtonType();
859 
860   // Only one finger hot with all others cold -> moving -> left click
861   if (num_hot_ == 1 && num_cold_ == num_fingers_ - 1)
862     return GESTURES_BUTTON_LEFT;
863 
864   // A single recent touch, or a single cold touch (with all others being hot)
865   // could be a thumb or a second hand finger.
866   if (num_recent_ == 1 || (num_cold_ == 1 && num_hot_ == num_fingers_ - 1)) {
867     // The ambiguous finger is either the most recent one, or the only cold one.
868     const FingerState* ambiguous_finger = fingers_[num_fingers_ - 1];
869     if (num_recent_ != 1) {
870       for (int i = 0; i < num_fingers_; ++i) {
871         if (fingers_status_[i] == STATUS_COLD) {
872           ambiguous_finger = fingers_[i];
873           break;
874         }
875       }
876     }
877     // If it's in the dampened zone we will expect it to be a thumb.
878     // Otherwise it's a second hand finger
879     if (interpreter_->FingerInDampenedZone(*ambiguous_finger))
880       return GetButtonTypeForTouchCount(num_fingers_ - 1);
881     else
882       return GESTURES_BUTTON_LEFT;
883   }
884 
885   // If all fingers are recent we can be sure they are from the same hand.
886   if (num_recent_ == num_fingers_) {
887     // Only if all fingers are in the same zone, we can be sure that none
888     // of them is a thumb.
889     Log("EvaluateThreeOrMoreFingerButtonType: Dampened: %d",
890         num_dampened_recent);
891     if (num_dampened_recent == 0 || num_dampened_recent == num_recent_)
892       return GetButtonTypeForTouchCount(num_recent_);
893   }
894 
895   // To make a decision after this point we need to figure out if and how
896   // many of the fingers are grouped together. We do so by finding the pair
897   // of closest fingers, and then calculate where we expect the remaining
898   // fingers to be found.
899   // If they are not in the expected place, they will be called separate.
900   Log("EvaluateThreeOrMoreFingerButtonType: Falling back to location based "
901       "detection");
902   return EvaluateButtonTypeUsingFigureLocation();
903 }
904 
EvaluateButtonTypeUsingFigureLocation()905 int FingerButtonClick::EvaluateButtonTypeUsingFigureLocation() {
906   const float kMaxDistSq = interpreter_->button_max_dist_from_expected_.val_ *
907                            interpreter_->button_max_dist_from_expected_.val_;
908 
909   // Find pair with the closest distance
910   const FingerState* pair_a = NULL;
911   const FingerState* pair_b = NULL;
912   float pair_dist_sq = std::numeric_limits<float>::infinity();
913   for (int i = 0; i < num_fingers_; ++i) {
914     for (int j = 0; j < i; ++j) {
915       float dist_sq = DistSq(*fingers_[i], *fingers_[j]);
916       if (dist_sq < pair_dist_sq) {
917         pair_a = fingers_[i];
918         pair_b = fingers_[j];
919         pair_dist_sq = dist_sq;
920       }
921     }
922   }
923 
924   int num_separate = 0;
925   const FingerState* last_separate = NULL;
926 
927   if (interpreter_->metrics_->CloseEnoughToGesture(Vector2(*pair_a),
928                                                    Vector2(*pair_b))) {
929     // Expect the remaining fingers to be next to the pair, all with the same
930     // distance from each other.
931     float dx = pair_b->position_x - pair_a->position_x;
932     float dy = pair_b->position_y - pair_a->position_y;
933     float expected1_x = pair_a->position_x + 2 * dx;
934     float expected1_y = pair_a->position_y + 2 * dy;
935     float expected2_x = pair_b->position_x - 2 * dx;
936     float expected2_y = pair_b->position_y - 2 * dy;
937 
938     // Check if remaining fingers are close to the expected positions
939     for (int i = 0; i < num_fingers_; ++i) {
940       if (fingers_[i] == pair_a || fingers_[i] == pair_b)
941         continue;
942       float dist1_sq = DistSqXY(*fingers_[i], expected1_x, expected1_y);
943       float dist2_sq = DistSqXY(*fingers_[i], expected2_x, expected2_y);
944       if (dist1_sq > kMaxDistSq && dist2_sq > kMaxDistSq) {
945         num_separate++;
946         last_separate = fingers_[i];
947       }
948     }
949   } else {
950     // In case the pair is not close we have to fall back to using the
951     // dampened zone
952     Log("EvaluateButtonTypeUsingFigureLocation: Falling back to dampened zone "
953         "separation");
954     for (int i = 0; i < num_fingers_; ++i) {
955       if (interpreter_->FingerInDampenedZone(*fingers_[i])) {
956         num_separate++;
957         last_separate = fingers_[i];
958       }
959     }
960   }
961 
962   // All fingers next to each other
963   if (num_separate == 0)
964     return GetButtonTypeForTouchCount(num_fingers_);
965 
966   // The group with the last finger counts!
967   // Exception: If the separates have only one finger and it's a thumb
968   //            count the other group
969   int num_pressing;
970   if (fingers_[num_fingers_ - 1] == last_separate &&
971       !(num_separate == 1 &&
972         interpreter_->FingerInDampenedZone(*last_separate))) {
973     num_pressing = num_separate;
974   } else {
975     num_pressing = num_fingers_ - num_separate;
976   }
977   Log("EvaluateButtonTypeUsingFigureLocation: Pressing: %d", num_pressing);
978   return GetButtonTypeForTouchCount(num_pressing);
979 }
980 
ImmediateInterpreter(PropRegistry * prop_reg,Tracer * tracer)981 ImmediateInterpreter::ImmediateInterpreter(PropRegistry* prop_reg,
982                                            Tracer* tracer)
983     : Interpreter(NULL, tracer, false),
984       button_type_(0),
985       finger_button_click_(this),
986       sent_button_down_(false),
987       button_down_timeout_(0.0),
988       started_moving_time_(-1.0),
989       gs_changed_time_(-1.0),
990       finger_leave_time_(-1.0),
991       moving_finger_id_(-1),
992       tap_to_click_state_(kTtcIdle),
993       tap_to_click_state_entered_(-1.0),
994       tap_record_(this),
995       last_movement_timestamp_(-1.0),
996       swipe_is_vertical_(false),
997       current_gesture_type_(kGestureTypeNull),
998       state_buffer_(8),
999       scroll_buffer_(20),
1000       pinch_guess_start_(-1.0),
1001       pinch_locked_(false),
1002       pinch_status_(GESTURES_ZOOM_START),
1003       pinch_prev_direction_(0),
1004       pinch_prev_time_(-1.0),
1005       finger_seen_shortly_after_button_down_(false),
1006       keyboard_touched_(0.0),
1007       scroll_manager_(prop_reg),
1008       tap_enable_(prop_reg, "Tap Enable", true),
1009       tap_paused_(prop_reg, "Tap Paused", false),
1010       tap_timeout_(prop_reg, "Tap Timeout", 0.2),
1011       inter_tap_timeout_(prop_reg, "Inter-Tap Timeout", 0.15),
1012       tap_drag_delay_(prop_reg, "Tap Drag Delay", 0),
1013       tap_drag_timeout_(prop_reg, "Tap Drag Timeout", 0.3),
1014       tap_drag_enable_(prop_reg, "Tap Drag Enable", false),
1015       drag_lock_enable_(prop_reg, "Tap Drag Lock Enable", false),
1016       tap_drag_stationary_time_(prop_reg, "Tap Drag Stationary Time", 0),
1017       tap_move_dist_(prop_reg, "Tap Move Distance", 2.0),
1018       tap_min_pressure_(prop_reg, "Tap Minimum Pressure", 25.0),
1019       tap_max_movement_(prop_reg, "Tap Maximum Movement", 0.0001),
1020       tap_max_finger_age_(prop_reg, "Tap Maximum Finger Age", 1.2),
1021       three_finger_click_enable_(prop_reg, "Three Finger Click Enable", true),
1022       zero_finger_click_enable_(prop_reg, "Zero Finger Click Enable", false),
1023       t5r2_three_finger_click_enable_(prop_reg,
1024                                       "T5R2 Three Finger Click Enable",
1025                                       false),
1026       change_move_distance_(prop_reg, "Change Min Move Distance", 3.0),
1027       move_lock_speed_(prop_reg, "Move Lock Speed", 10.0),
1028       move_report_distance_(prop_reg, "Move Report Distance", 0.35),
1029       change_timeout_(prop_reg, "Change Timeout", 0.2),
1030       evaluation_timeout_(prop_reg, "Evaluation Timeout", 0.15),
1031       pinch_evaluation_timeout_(prop_reg, "Pinch Evaluation Timeout", 0.1),
1032       thumb_pinch_evaluation_timeout_(prop_reg,
1033                                       "Thumb Pinch Evaluation Timeout", 0.25),
1034       thumb_pinch_min_movement_(prop_reg,
1035                                 "Thumb Pinch Minimum Movement", 0.8),
1036       thumb_pinch_movement_ratio_(prop_reg, "Thumb Pinch Movement Ratio", 20),
1037       thumb_slow_pinch_similarity_ratio_(prop_reg,
1038                                          "Thumb Slow Pinch Similarity Ratio",
1039                                          5),
1040       thumb_pinch_delay_factor_(prop_reg, "Thumb Pinch Delay Factor", 9.0),
1041       minimum_movement_direction_detection_(prop_reg,
1042           "Minimum Movement Direction Detection", 0.003),
1043       damp_scroll_min_movement_factor_(prop_reg,
1044                                        "Damp Scroll Min Move Factor",
1045                                        0.2),
1046       two_finger_pressure_diff_thresh_(prop_reg,
1047                                        "Two Finger Pressure Diff Thresh",
1048                                        32.0),
1049       two_finger_pressure_diff_factor_(prop_reg,
1050                                        "Two Finger Pressure Diff Factor",
1051                                        1.65),
1052       click_drag_pressure_diff_thresh_(prop_reg,
1053                                        "Click Drag Pressure Diff Thresh",
1054                                        10.0),
1055       click_drag_pressure_diff_factor_(prop_reg,
1056                                        "Click Drag Pressure Diff Factor",
1057                                        1.20),
1058       click_drag_min_slope_(prop_reg, "Click Drag Min Slope", 2.22),
1059       thumb_movement_factor_(prop_reg, "Thumb Movement Factor", 0.5),
1060       thumb_speed_factor_(prop_reg, "Thumb Speed Factor", 0.5),
1061       thumb_eval_timeout_(prop_reg, "Thumb Evaluation Timeout", 0.06),
1062       thumb_pinch_threshold_ratio_(prop_reg,
1063                                    "Thumb Pinch Threshold Ratio", 0.25),
1064       thumb_click_prevention_timeout_(prop_reg,
1065                                       "Thumb Click Prevention Timeout", 0.15),
1066       two_finger_scroll_distance_thresh_(prop_reg,
1067                                          "Two Finger Scroll Distance Thresh",
1068                                          1.5),
1069       two_finger_move_distance_thresh_(prop_reg,
1070                                        "Two Finger Move Distance Thresh",
1071                                        7.0),
1072       three_finger_swipe_distance_thresh_(prop_reg,
1073                                           "Three Finger Swipe Distance Thresh",
1074                                           1.5),
1075       four_finger_swipe_distance_thresh_(prop_reg,
1076                                          "Four Finger Swipe Distance Thresh",
1077                                          1.5),
1078       three_finger_swipe_distance_ratio_(prop_reg,
1079                                           "Three Finger Swipe Distance Ratio",
1080                                           0.2),
1081       four_finger_swipe_distance_ratio_(prop_reg,
1082                                          "Four Finger Swipe Distance Ratio",
1083                                          0.2),
1084       three_finger_swipe_enable_(prop_reg, "Three Finger Swipe Enable", true),
1085       bottom_zone_size_(prop_reg, "Bottom Zone Size", 10.0),
1086       button_evaluation_timeout_(prop_reg, "Button Evaluation Timeout", 0.05),
1087       button_finger_timeout_(prop_reg, "Button Finger Timeout", 0.03),
1088       button_move_dist_(prop_reg, "Button Move Distance", 10.0),
1089       button_max_dist_from_expected_(prop_reg,
1090                                      "Button Max Distance From Expected", 20.0),
1091       button_right_click_zone_enable_(prop_reg,
1092                                       "Button Right Click Zone Enable", false),
1093       button_right_click_zone_size_(prop_reg,
1094                                     "Button Right Click Zone Size", 20.0),
1095       keyboard_touched_timeval_high_(prop_reg, "Keyboard Touched Timeval High",
1096                                      0),
1097       keyboard_touched_timeval_low_(prop_reg, "Keyboard Touched Timeval Low",
1098                                     0),
1099       keyboard_palm_prevent_timeout_(prop_reg, "Keyboard Palm Prevent Timeout",
1100                                      0.5),
1101       motion_tap_prevent_timeout_(prop_reg, "Motion Tap Prevent Timeout",
1102                                   0.05),
1103       tapping_finger_min_separation_(prop_reg, "Tap Min Separation", 10.0),
1104       pinch_noise_level_sq_(prop_reg, "Pinch Noise Level Squared", 2.0),
1105       pinch_guess_min_movement_(prop_reg, "Pinch Guess Minimum Movement", 2.0),
1106       pinch_thumb_min_movement_(prop_reg,
1107                                 "Pinch Thumb Minimum Movement", 1.41),
1108       pinch_certain_min_movement_(prop_reg,
1109                                   "Pinch Certain Minimum Movement", 8.0),
1110       inward_pinch_min_angle_(prop_reg, "Inward Pinch Minimum Angle", 0.3),
1111       pinch_zoom_max_angle_(prop_reg, "Pinch Zoom Maximum Angle", -0.4),
1112       scroll_min_angle_(prop_reg, "Scroll Minimum Angle", -0.2),
1113       pinch_guess_consistent_mov_ratio_(prop_reg,
1114           "Pinch Guess Consistent Movement Ratio", 0.4),
1115       pinch_zoom_min_events_(prop_reg, "Pinch Zoom Minimum Events", 3),
1116       pinch_initial_scale_time_inv_(prop_reg,
1117                                     "Pinch Initial Scale Time Inverse",
1118                                     3.33),
1119       pinch_res_(prop_reg, "Minimum Pinch Scale Resolution Squared", 1.005),
1120       pinch_stationary_res_(prop_reg,
1121                             "Stationary Pinch Scale Resolution Squared",
1122                             1.05),
1123       pinch_stationary_time_(prop_reg,
1124                              "Stationary Pinch Time",
1125                              0.10),
1126       pinch_hysteresis_res_(prop_reg,
1127                             "Hysteresis Pinch Scale Resolution Squared",
1128                             1.05),
1129       pinch_enable_(prop_reg, "Pinch Enable", true),
1130       right_click_start_time_diff_(prop_reg,
1131                                    "Right Click Start Time Diff Thresh",
1132                                    0.1),
1133       right_click_second_finger_age_(prop_reg,
1134                                      "Right Click Second Finger Age Thresh",
1135                                      0.5),
1136       quick_acceleration_factor_(prop_reg, "Quick Acceleration Factor", 0.0) {
1137   InitName();
1138   requires_metrics_ = true;
1139   keyboard_touched_timeval_low_.SetDelegate(this);
1140 }
1141 
SyncInterpretImpl(HardwareState * hwstate,stime_t * timeout)1142 void ImmediateInterpreter::SyncInterpretImpl(HardwareState* hwstate,
1143                                              stime_t* timeout) {
1144   if (!state_buffer_.Get(0)->fingers) {
1145     Err("Must call SetHardwareProperties() before Push().");
1146     return;
1147   }
1148 
1149   state_buffer_.PushState(*hwstate);
1150 
1151   FillOriginInfo(*hwstate);
1152   result_.type = kGestureTypeNull;
1153   const bool same_fingers = state_buffer_.Get(1)->SameFingersAs(*hwstate) &&
1154       (hwstate->buttons_down == state_buffer_.Get(1)->buttons_down);
1155   if (!same_fingers) {
1156     // Fingers changed, do nothing this time
1157     FingerMap new_gs_fingers;
1158     FingerMap gs_fingers = GetGesturingFingers(*hwstate);
1159     std::set_difference(gs_fingers.begin(), gs_fingers.end(),
1160                         non_gs_fingers_.begin(), non_gs_fingers_.end(),
1161                         std::inserter(new_gs_fingers, new_gs_fingers.begin()));
1162     ResetSameFingersState(*hwstate);
1163     FillStartPositions(*hwstate);
1164     if (pinch_enable_.val_ &&
1165         (hwstate->finger_cnt <= 2 || new_gs_fingers.size() != 2)) {
1166       // Release the zoom lock
1167       UpdatePinchState(*hwstate, true, new_gs_fingers);
1168     }
1169     moving_finger_id_ = -1;
1170   }
1171 
1172   if (hwstate->finger_cnt < state_buffer_.Get(1)->finger_cnt &&
1173       AnyGesturingFingerLeft(*hwstate, prev_active_gs_fingers_)) {
1174     finger_leave_time_ = hwstate->timestamp;
1175   }
1176 
1177   // Check if clock changed backwards
1178   if (hwstate->timestamp < state_buffer_.Get(1)->timestamp)
1179     ResetTime();
1180 
1181   UpdatePointingFingers(*hwstate);
1182   UpdateThumbState(*hwstate);
1183   FingerMap newly_moving_fingers = UpdateMovingFingers(*hwstate);
1184   UpdateNonGsFingers(*hwstate);
1185   FingerMap new_gs_fingers;
1186   FingerMap gs_fingers = GetGesturingFingers(*hwstate);
1187   std::set_difference(gs_fingers.begin(), gs_fingers.end(),
1188                       non_gs_fingers_.begin(), non_gs_fingers_.end(),
1189                       std::inserter(new_gs_fingers, new_gs_fingers.begin()));
1190   if (gs_fingers != prev_gs_fingers_)
1191     gs_changed_time_ = hwstate->timestamp;
1192   UpdateStartedMovingTime(hwstate->timestamp, gs_fingers, newly_moving_fingers);
1193 
1194   UpdateButtons(*hwstate, timeout);
1195   UpdateTapGesture(hwstate,
1196                    gs_fingers,
1197                    same_fingers,
1198                    hwstate->timestamp,
1199                    timeout);
1200 
1201   FingerMap active_gs_fingers;
1202   UpdateCurrentGestureType(*hwstate, gs_fingers, &active_gs_fingers);
1203   GenerateFingerLiftGesture();
1204   if (result_.type == kGestureTypeNull)
1205     FillResultGesture(*hwstate, active_gs_fingers);
1206 
1207   // Prevent moves while in a tap
1208   if ((tap_to_click_state_ == kTtcFirstTapBegan ||
1209        tap_to_click_state_ == kTtcSubsequentTapBegan) &&
1210       result_.type == kGestureTypeMove)
1211     result_.type = kGestureTypeNull;
1212 
1213   prev_active_gs_fingers_ = active_gs_fingers;
1214   prev_gs_fingers_ = gs_fingers;
1215   prev_result_ = result_;
1216   prev_gesture_type_ = current_gesture_type_;
1217   if (result_.type != kGestureTypeNull) {
1218     non_gs_fingers_.clear();
1219     std::set_difference(gs_fingers.begin(), gs_fingers.end(),
1220                         active_gs_fingers.begin(), active_gs_fingers.end(),
1221                         std::inserter(non_gs_fingers_,
1222                         non_gs_fingers_.begin()));
1223     ProduceGesture(result_);
1224   }
1225 }
1226 
HandleTimerImpl(stime_t now,stime_t * timeout)1227 void ImmediateInterpreter::HandleTimerImpl(stime_t now, stime_t* timeout) {
1228   result_.type = kGestureTypeNull;
1229   // Tap-to-click always aborts when real button(s) are being used, so we
1230   // don't need to worry about conflicts with these two types of callback.
1231   UpdateButtonsTimeout(now);
1232   UpdateTapGesture(NULL,
1233                    FingerMap(),
1234                    false,
1235                    now,
1236                    timeout);
1237   if (result_.type != kGestureTypeNull)
1238     ProduceGesture(result_);
1239 }
1240 
FillOriginInfo(const HardwareState & hwstate)1241 void ImmediateInterpreter::FillOriginInfo(
1242     const HardwareState& hwstate) {
1243   RemoveMissingIdsFromMap(&origin_timestamps_, hwstate);
1244   RemoveMissingIdsFromMap(&distance_walked_, hwstate);
1245   for (size_t i = 0; i < hwstate.finger_cnt; i++) {
1246     const FingerState& fs = hwstate.fingers[i];
1247     if (MapContainsKey(origin_timestamps_, fs.tracking_id) &&
1248         state_buffer_.Size() > 1 &&
1249         state_buffer_.Get(1)->GetFingerState(fs.tracking_id)) {
1250       float delta_x = hwstate.GetFingerState(fs.tracking_id)->position_x -
1251           state_buffer_.Get(1)->GetFingerState(fs.tracking_id)->position_x;
1252       float delta_y = hwstate.GetFingerState(fs.tracking_id)->position_y -
1253           state_buffer_.Get(1)->GetFingerState(fs.tracking_id)->position_y;
1254       distance_walked_[fs.tracking_id] += sqrtf(delta_x * delta_x +
1255                                                 delta_y * delta_y);
1256       continue;
1257     }
1258     origin_timestamps_[fs.tracking_id] = hwstate.timestamp;
1259     distance_walked_[fs.tracking_id] = 0.0;
1260   }
1261 }
1262 
ResetSameFingersState(const HardwareState & hwstate)1263 void ImmediateInterpreter::ResetSameFingersState(const HardwareState& hwstate) {
1264   pointing_.clear();
1265   fingers_.clear();
1266   start_positions_.clear();
1267   three_finger_swipe_start_positions_.clear();
1268   four_finger_swipe_start_positions_.clear();
1269   scroll_manager_.ResetSameFingerState();
1270   RemoveMissingIdsFromSet(&moving_, hwstate);
1271   changed_time_ = hwstate.timestamp;
1272 }
1273 
ResetTime()1274 void ImmediateInterpreter::ResetTime() {
1275   started_moving_time_ = -1.0;
1276   gs_changed_time_ = -1.0;
1277   finger_leave_time_ = -1.0;
1278   tap_to_click_state_entered_ = -1.0;
1279   last_movement_timestamp_ = -1.0;
1280   pinch_guess_start_ = -1.0;
1281   pinch_prev_time_ = -1.0;
1282 }
1283 
UpdatePointingFingers(const HardwareState & hwstate)1284 void ImmediateInterpreter::UpdatePointingFingers(const HardwareState& hwstate) {
1285   for (size_t i = 0; i < hwstate.finger_cnt; i++) {
1286     if (hwstate.fingers[i].flags & GESTURES_FINGER_PALM)
1287       pointing_.erase(hwstate.fingers[i].tracking_id);
1288     else
1289       pointing_.insert(hwstate.fingers[i].tracking_id);
1290   }
1291   fingers_ = pointing_;
1292 }
1293 
DistanceTravelledSq(const FingerState & fs,bool origin,bool permit_warp) const1294 float ImmediateInterpreter::DistanceTravelledSq(const FingerState& fs,
1295                                                 bool origin,
1296                                                 bool permit_warp) const {
1297   Point delta = FingerTraveledVector(fs, origin, permit_warp);
1298   return delta.x_ * delta.x_ + delta.y_ * delta.y_;
1299 }
1300 
FingerTraveledVector(const FingerState & fs,bool origin,bool permit_warp) const1301 Point ImmediateInterpreter::FingerTraveledVector(
1302     const FingerState& fs, bool origin, bool permit_warp) const {
1303   const std::map<short, Point>* positions;
1304   if (origin)
1305     positions = &origin_positions_;
1306   else
1307     positions = &start_positions_;
1308 
1309   if (!MapContainsKey(*positions, fs.tracking_id))
1310     return Point(0.0f, 0.0f);
1311 
1312   const Point& start = positions->at(fs.tracking_id);
1313   float dx = fs.position_x - start.x_;
1314   float dy = fs.position_y - start.y_;
1315   bool suppress_move =
1316       (!permit_warp || (fs.flags & GESTURES_FINGER_WARP_TELEPORTATION));
1317   if ((fs.flags & GESTURES_FINGER_WARP_X) && suppress_move)
1318     dx = 0;
1319   if ((fs.flags & GESTURES_FINGER_WARP_Y) && suppress_move)
1320     dy = 0;
1321   return Point(dx, dy);
1322 }
1323 
EarlyZoomPotential(const HardwareState & hwstate) const1324 bool ImmediateInterpreter::EarlyZoomPotential(const HardwareState& hwstate)
1325     const {
1326   if (fingers_.size() != 2)
1327     return false;
1328   int id1 = *(fingers_.begin());
1329   int id2 = *(++fingers_.begin());
1330   const FingerState* finger1 = hwstate.GetFingerState(id1);
1331   const FingerState* finger2 = hwstate.GetFingerState(id2);
1332   float pinch_eval_timeout = pinch_evaluation_timeout_.val_;
1333   if (finger1 == NULL || finger2 == NULL)
1334     return false;
1335   // Wait for a longer time if fingers arrived together
1336   stime_t t1 = origin_timestamps_.at(id1);
1337   stime_t t2 = origin_timestamps_.at(id2);
1338   if (fabs(t1 - t2) < evaluation_timeout_.val_ &&
1339       hwstate.timestamp - max(t1, t2) <
1340           thumb_pinch_evaluation_timeout_.val_ * thumb_pinch_delay_factor_.val_)
1341     pinch_eval_timeout *= thumb_pinch_delay_factor_.val_;
1342   bool early_decision = hwstate.timestamp - min(t1, t2) < pinch_eval_timeout;
1343   // Avoid extra computation if it's too late for a pinch zoom
1344   if (!early_decision &&
1345       hwstate.timestamp - t1 > thumb_pinch_evaluation_timeout_.val_)
1346     return false;
1347 
1348   float walked_distance1 = distance_walked_.at(finger1->tracking_id);
1349   float walked_distance2 = distance_walked_.at(finger2->tracking_id);
1350   if (walked_distance1 > walked_distance2)
1351     std::swap(walked_distance1,walked_distance2);
1352   if ((walked_distance1 > thumb_pinch_min_movement_.val_ ||
1353            hwstate.timestamp - t1 > thumb_pinch_evaluation_timeout_.val_) &&
1354       walked_distance1 > 0 &&
1355       walked_distance2 / walked_distance1 > thumb_pinch_movement_ratio_.val_)
1356     return false;
1357 
1358   bool motionless_cycles = false;
1359   for (int i = 1;
1360        i < min<int>(state_buffer_.Size(), pinch_zoom_min_events_.val_); i++) {
1361     const FingerState* curr1 = state_buffer_.Get(i - 1)->GetFingerState(id1);
1362     const FingerState* curr2 = state_buffer_.Get(i - 1)->GetFingerState(id2);
1363     const FingerState* prev1 = state_buffer_.Get(i)->GetFingerState(id1);
1364     const FingerState* prev2 = state_buffer_.Get(i)->GetFingerState(id2);
1365     if (!curr1 || !curr2 || !prev1 || !prev2) {
1366        motionless_cycles = true;
1367        break;
1368     }
1369     bool finger1_moved = (curr1->position_x - prev1->position_x) != 0 ||
1370                          (curr1->position_y - prev1->position_y) != 0;
1371     bool finger2_moved = (curr2->position_x - prev2->position_x) != 0 ||
1372                          (curr2->position_y - prev2->position_y) != 0;
1373     if (!finger1_moved && !finger2_moved) {
1374        motionless_cycles = true;
1375        break;
1376     }
1377   }
1378   if (motionless_cycles > 0 && early_decision)
1379     return true;
1380 
1381   Point delta1 = FingerTraveledVector(*finger1, true, true);
1382   Point delta2 = FingerTraveledVector(*finger2, true, true);
1383   float dot = delta1.x_ * delta2.x_ + delta1.y_ * delta2.y_;
1384   if ((pinch_guess_start_ > 0 || dot < 0) && early_decision)
1385     return true;
1386 
1387   if (t1 - t2 < evaluation_timeout_.val_ &&
1388       t2 - t1 < evaluation_timeout_.val_ &&
1389       hwstate.timestamp - t1 < thumb_pinch_evaluation_timeout_.val_)
1390     return true;
1391 
1392   return false;
1393 }
1394 
ZoomFingersAreConsistent(const HardwareStateBuffer & state_buffer) const1395 bool ImmediateInterpreter::ZoomFingersAreConsistent(
1396     const HardwareStateBuffer& state_buffer) const {
1397   if (fingers_.size() != 2)
1398     return false;
1399 
1400   int id1 = *(fingers_.begin());
1401   int id2 = *(++fingers_.begin());
1402 
1403   const FingerState* curr1 = state_buffer.Get(min<int>(state_buffer.Size() - 1,
1404       pinch_zoom_min_events_.val_))->GetFingerState(id1);
1405   const FingerState* curr2 = state_buffer.Get(min<int>(state_buffer.Size() - 1,
1406       pinch_zoom_min_events_.val_))->GetFingerState(id2);
1407   if (!curr1 || !curr2)
1408     return false;
1409   for (int i = 0;
1410        i < min<int>(state_buffer.Size(), pinch_zoom_min_events_.val_); i++) {
1411     const FingerState* prev1 = state_buffer.Get(i)->GetFingerState(id1);
1412     const FingerState* prev2 = state_buffer.Get(i)->GetFingerState(id2);
1413     if (!prev1 || !prev2)
1414       return false;
1415     float dot = FingersAngle(prev1, prev2, curr1, curr2);
1416     if (dot >= 0)
1417       return false;
1418   }
1419   const FingerState* last1 = state_buffer.Get(0)->GetFingerState(id1);
1420   const FingerState* last2 = state_buffer.Get(0)->GetFingerState(id2);
1421   float angle = FingersAngle(last1, last2, curr1, curr2);
1422   if (angle > pinch_zoom_max_angle_.val_)
1423     return false;
1424   return true;
1425 }
1426 
InwardPinch(const HardwareStateBuffer & state_buffer,const FingerState & fs) const1427 bool ImmediateInterpreter::InwardPinch(
1428     const HardwareStateBuffer& state_buffer, const FingerState& fs) const {
1429   if (fingers_.size() != 2)
1430     return false;
1431 
1432   int id = fs.tracking_id;
1433 
1434   const FingerState* curr =
1435       state_buffer.Get(min<int>(state_buffer.Size(),
1436           pinch_zoom_min_events_.val_))->GetFingerState(id);
1437   if (!curr)
1438     return false;
1439   for (int i = 0;
1440        i < min<int>(state_buffer.Size(), pinch_zoom_min_events_.val_); i++) {
1441     const FingerState* prev = state_buffer.Get(i)->GetFingerState(id);
1442     if (!prev)
1443       return false;
1444     float dot = (curr->position_y - prev->position_y);
1445     if (dot <= 0)
1446       return false;
1447   }
1448   const FingerState* last = state_buffer.Get(0)->GetFingerState(id);
1449   float dot_last = (curr->position_y - last->position_y);
1450   float size_last = sqrt((curr->position_x - last->position_x) *
1451                          (curr->position_x - last->position_x) +
1452                          (curr->position_y - last->position_y) *
1453                          (curr->position_y - last->position_y));
1454 
1455   float angle = dot_last / size_last;
1456   if (angle < inward_pinch_min_angle_.val_)
1457     return false;
1458   return true;
1459 }
1460 
FingersAngle(const FingerState * prev1,const FingerState * prev2,const FingerState * curr1,const FingerState * curr2) const1461 float ImmediateInterpreter::FingersAngle(const FingerState* prev1,
1462                                          const FingerState* prev2,
1463                                          const FingerState* curr1,
1464                                          const FingerState* curr2) const {
1465   float dot_last = (curr1->position_x - prev1->position_x) *
1466                    (curr2->position_x - prev2->position_x) +
1467                    (curr1->position_y - prev1->position_y) *
1468                    (curr2->position_y - prev2->position_y);
1469   float size_last1_sq = (curr1->position_x - prev1->position_x) *
1470                         (curr1->position_x - prev1->position_x) +
1471                         (curr1->position_y - prev1->position_y) *
1472                         (curr1->position_y - prev1->position_y);
1473   float size_last2_sq = (curr2->position_x - prev2->position_x) *
1474                         (curr2->position_x - prev2->position_x) +
1475                         (curr2->position_y - prev2->position_y) *
1476                         (curr2->position_y - prev2->position_y);
1477   float overall_size = sqrt(size_last1_sq * size_last2_sq);
1478   // If one of the two vectors is too small, return 0.
1479   if (overall_size < minimum_movement_direction_detection_.val_ *
1480                      minimum_movement_direction_detection_.val_)
1481     return 0.0;
1482   return dot_last / overall_size;
1483 }
1484 
ScrollAngle(const FingerState & finger1,const FingerState & finger2)1485 bool ImmediateInterpreter::ScrollAngle(const FingerState& finger1,
1486                                        const FingerState& finger2) {
1487     const FingerState* curr1 = state_buffer_.Get(
1488         min<int>(state_buffer_.Size() - 1, 3))->
1489             GetFingerState(finger1.tracking_id);
1490     const FingerState* curr2 = state_buffer_.Get(
1491         min<int>(state_buffer_.Size() - 1, 3))->
1492             GetFingerState(finger2.tracking_id);
1493     const FingerState* last1 =
1494         state_buffer_.Get(0)->GetFingerState(finger1.tracking_id);
1495     const FingerState* last2 =
1496         state_buffer_.Get(0)->GetFingerState(finger2.tracking_id);
1497     if (last1 && last2 && curr1 && curr2) {
1498       if (FingersAngle(last1, last2, curr1, curr2) < scroll_min_angle_.val_)
1499         return false;
1500     }
1501     return true;
1502 }
1503 
TwoFingerDistanceSq(const HardwareState & hwstate) const1504 float ImmediateInterpreter::TwoFingerDistanceSq(
1505     const HardwareState& hwstate) const {
1506   if (fingers_.size() == 2) {
1507     return TwoSpecificFingerDistanceSq(hwstate, fingers_);
1508   } else {
1509     return -1;
1510   }
1511 }
1512 
TwoSpecificFingerDistanceSq(const HardwareState & hwstate,const FingerMap & fingers) const1513 float ImmediateInterpreter::TwoSpecificFingerDistanceSq(
1514     const HardwareState& hwstate, const FingerMap& fingers) const {
1515   if (fingers.size() == 2) {
1516     const FingerState* finger_a = hwstate.GetFingerState(*fingers.begin());
1517     const FingerState* finger_b = hwstate.GetFingerState(*(++fingers.begin()));
1518     if (finger_a == NULL || finger_b == NULL) {
1519       Err("Finger unexpectedly NULL");
1520       return -1;
1521     }
1522     return DistSq(*finger_a, *finger_b);
1523   } else if (hwstate.finger_cnt == 2) {
1524     return DistSq(hwstate.fingers[0], hwstate.fingers[1]);
1525   } else {
1526     return -1;
1527   }
1528 }
1529 
1530 // Updates thumb_ below.
UpdateThumbState(const HardwareState & hwstate)1531 void ImmediateInterpreter::UpdateThumbState(const HardwareState& hwstate) {
1532   // Remove old ids from thumb_
1533   RemoveMissingIdsFromMap(&thumb_, hwstate);
1534   RemoveMissingIdsFromMap(&thumb_eval_timer_, hwstate);
1535   float min_pressure = INFINITY;
1536   const FingerState* min_fs = NULL;
1537   for (size_t i = 0; i < hwstate.finger_cnt; i++) {
1538     const FingerState& fs = hwstate.fingers[i];
1539     if (fs.flags & GESTURES_FINGER_PALM)
1540       continue;
1541     if (fs.pressure < min_pressure) {
1542       min_pressure = fs.pressure;
1543       min_fs = &fs;
1544     }
1545   }
1546   if (!min_fs) {
1547     // Only palms on the touchpad
1548     return;
1549   }
1550   // We respect warp flags only if we really have little information of the
1551   // finger positions and not just because we want to suppress unintentional
1552   // cursor moves. See the definition of GESTURES_FINGER_WARP_TELEPORTATION
1553   // for more detail.
1554   bool min_warp_move = (min_fs->flags & GESTURES_FINGER_WARP_TELEPORTATION) &&
1555                        ((min_fs->flags & GESTURES_FINGER_WARP_X_MOVE) ||
1556                         (min_fs->flags & GESTURES_FINGER_WARP_Y_MOVE));
1557   float min_dist_sq = DistanceTravelledSq(*min_fs, false, true);
1558   float min_dt = hwstate.timestamp -
1559       origin_timestamps_[min_fs->tracking_id];
1560   float thumb_dist_sq_thresh = min_dist_sq *
1561       thumb_movement_factor_.val_ * thumb_movement_factor_.val_;
1562   float thumb_speed_sq_thresh = min_dist_sq *
1563       thumb_speed_factor_.val_ * thumb_speed_factor_.val_;
1564   // Make all large-pressure, less moving contacts located below the
1565   // min-pressure contact as thumbs.
1566   bool similar_movement = false;
1567 
1568   if (pinch_enable_.val_ && hwstate.finger_cnt == 2) {
1569     float dt1 = hwstate.timestamp -
1570                 origin_timestamps_[hwstate.fingers[0].tracking_id];
1571     float dist_sq1 = DistanceTravelledSq(hwstate.fingers[0], true, true);
1572     float dt2 = hwstate.timestamp -
1573                 origin_timestamps_[hwstate.fingers[1].tracking_id];
1574     float dist_sq2 = DistanceTravelledSq(hwstate.fingers[1], true, true);
1575     if (dist_sq1 * dt1 && dist_sq2 * dt2)
1576       similar_movement = max((dist_sq1 * dt1 * dt1) / (dist_sq2 * dt2 * dt2),
1577                              (dist_sq2 * dt2 * dt2) / (dist_sq1 * dt1 * dt1)) <
1578                          thumb_slow_pinch_similarity_ratio_.val_;
1579     else
1580       similar_movement = false;
1581   }
1582   for (size_t i = 0; i < hwstate.finger_cnt; i++) {
1583     const FingerState& fs = hwstate.fingers[i];
1584     if (fs.flags & GESTURES_FINGER_PALM)
1585       continue;
1586     if (pinch_enable_.val_ && InwardPinch(state_buffer_, fs)) {
1587       thumb_speed_sq_thresh *= thumb_pinch_threshold_ratio_.val_;
1588       thumb_dist_sq_thresh *= thumb_pinch_threshold_ratio_.val_;
1589     }
1590     float dist_sq = DistanceTravelledSq(fs, false, true);
1591     float dt = hwstate.timestamp - origin_timestamps_[fs.tracking_id];
1592     bool closer_to_origin = dist_sq <= thumb_dist_sq_thresh;
1593     bool slower_moved = (dist_sq * min_dt &&
1594                          dist_sq * min_dt * min_dt <
1595                          thumb_speed_sq_thresh * dt * dt);
1596     bool relatively_motionless = closer_to_origin || slower_moved;
1597     bool likely_thumb =
1598         (fs.pressure > min_pressure + two_finger_pressure_diff_thresh_.val_ &&
1599          fs.pressure > min_pressure * two_finger_pressure_diff_factor_.val_ &&
1600          fs.position_y > min_fs->position_y);
1601     bool non_gs = (hwstate.timestamp > changed_time_ &&
1602                    (prev_active_gs_fingers_.find(fs.tracking_id) ==
1603                     prev_active_gs_fingers_.end()) &&
1604                    prev_result_.type != kGestureTypeNull);
1605     non_gs |= moving_finger_id_ >= 0 && moving_finger_id_ != fs.tracking_id;
1606     likely_thumb |= non_gs;
1607     // We sometimes can't decide the thumb state if some fingers are undergoing
1608     // warp moves as the decision could be off (DistanceTravelledSq may
1609     // under-estimate the real distance). The cases that we need to re-evaluate
1610     // the thumb in the next frame are:
1611     // 1. Both fingers warp.
1612     // 2. Min-pressure finger warps and relatively_motionless is false.
1613     // 3. Thumb warps and relatively_motionless is true.
1614     bool warp_move = (fs.flags & GESTURES_FINGER_WARP_TELEPORTATION) &&
1615                      ((fs.flags & GESTURES_FINGER_WARP_X_MOVE) ||
1616                       (fs.flags & GESTURES_FINGER_WARP_Y_MOVE));
1617     if (likely_thumb &&
1618         ((warp_move && min_warp_move) ||
1619          (!warp_move && min_warp_move && !relatively_motionless) ||
1620          (warp_move && !min_warp_move && relatively_motionless))) {
1621       continue;
1622     }
1623     likely_thumb &= relatively_motionless;
1624     if (MapContainsKey(thumb_, fs.tracking_id)) {
1625       // Beyond the evaluation period. Stick to being thumbs.
1626       if (thumb_eval_timer_[fs.tracking_id] <= 0.0) {
1627         if (!pinch_enable_.val_ || hwstate.finger_cnt == 1)
1628           continue;
1629         bool slow_pinch_guess =
1630             dist_sq * min_dt * min_dt / (thumb_speed_sq_thresh * dt * dt) >
1631                 thumb_pinch_min_movement_.val_ &&
1632             similar_movement;
1633         bool might_be_pinch = (slow_pinch_guess &&
1634                                hwstate.timestamp -
1635                                    origin_timestamps_[fs.tracking_id] < 2 *
1636                                    thumb_pinch_evaluation_timeout_.val_ &&
1637                                ZoomFingersAreConsistent(state_buffer_));
1638         if (relatively_motionless ||
1639             hwstate.timestamp - origin_timestamps_[fs.tracking_id] >
1640                 thumb_pinch_evaluation_timeout_.val_) {
1641           if (!might_be_pinch)
1642             continue;
1643           else
1644             likely_thumb = false;
1645         }
1646       }
1647 
1648       // Finger is still under evaluation.
1649       if (likely_thumb) {
1650         // Decrease the timer as the finger is thumb-like in the previous
1651         // frame.
1652         const FingerState* prev =
1653             state_buffer_.Get(1)->GetFingerState(fs.tracking_id);
1654         if (!prev)
1655           continue;
1656         thumb_eval_timer_[fs.tracking_id] -=
1657             hwstate.timestamp - state_buffer_.Get(1)->timestamp;
1658       } else {
1659         // The finger wasn't thumb-like in the frame. Remove it from the thumb
1660         // list.
1661         thumb_.erase(fs.tracking_id);
1662         thumb_eval_timer_.erase(fs.tracking_id);
1663       }
1664     } else if (likely_thumb) {
1665       // Finger is thumb-like, so we add it to the list.
1666       thumb_[fs.tracking_id] = hwstate.timestamp;
1667       thumb_eval_timer_[fs.tracking_id] = thumb_eval_timeout_.val_;
1668     }
1669   }
1670   for (std::map<short, stime_t>::const_iterator it = thumb_.begin();
1671        it != thumb_.end(); ++it)
1672     pointing_.erase((*it).first);
1673 }
1674 
UpdateNonGsFingers(const HardwareState & hwstate)1675 void ImmediateInterpreter::UpdateNonGsFingers(const HardwareState& hwstate) {
1676   RemoveMissingIdsFromSet(&non_gs_fingers_, hwstate);
1677   // moving fingers may be gesturing, so take them out from the set.
1678   FingerMap temp;
1679   std::set_difference(non_gs_fingers_.begin(), non_gs_fingers_.end(),
1680                       moving_.begin(), moving_.end(),
1681                       std::inserter(temp, temp.begin()));
1682   non_gs_fingers_ = temp;
1683 }
1684 
KeyboardRecentlyUsed(stime_t now) const1685 bool ImmediateInterpreter::KeyboardRecentlyUsed(stime_t now) const {
1686   // For tests, values of 0 mean keyboard not used recently.
1687   if (keyboard_touched_ == 0.0)
1688     return false;
1689   // Sanity check. If keyboard_touched_ is more than 10 seconds away from now,
1690   // ignore it.
1691   if (fabs(now - keyboard_touched_) > 10)
1692     return false;
1693 
1694   return keyboard_touched_ + keyboard_palm_prevent_timeout_.val_ > now;
1695 }
1696 
1697 namespace {
1698 struct GetGesturingFingersCompare {
1699   // Returns true if finger_a is strictly closer to keyboard than finger_b
operator ()gestures::__anone3fa56260211::GetGesturingFingersCompare1700   bool operator()(const FingerState* finger_a, const FingerState* finger_b) {
1701     return finger_a->position_y < finger_b->position_y;
1702   }
1703 };
1704 }  // namespace {}
1705 
GetGesturingFingers(const HardwareState & hwstate) const1706 FingerMap ImmediateInterpreter::GetGesturingFingers(
1707     const HardwareState& hwstate) const {
1708   // We support up to kMaxGesturingFingers finger gestures
1709   if (pointing_.size() <= kMaxGesturingFingers)
1710     return pointing_;
1711 
1712   const FingerState* fs[hwstate.finger_cnt];
1713   for (size_t i = 0; i < hwstate.finger_cnt; ++i)
1714     fs[i] = &hwstate.fingers[i];
1715 
1716   // Pull the kMaxSize FingerStates w/ the lowest position_y to the
1717   // front of fs[].
1718   GetGesturingFingersCompare compare;
1719   FingerMap ret;
1720   size_t sorted_cnt;
1721   if (hwstate.finger_cnt > kMaxGesturingFingers) {
1722     std::partial_sort(fs, fs + kMaxGesturingFingers, fs + hwstate.finger_cnt,
1723                       compare);
1724     sorted_cnt = kMaxGesturingFingers;
1725   } else {
1726     std::sort(fs, fs + hwstate.finger_cnt, compare);
1727     sorted_cnt = hwstate.finger_cnt;
1728   }
1729   for (size_t i = 0; i < sorted_cnt; i++)
1730     ret.insert(fs[i]->tracking_id);
1731   return ret;
1732 }
1733 
UpdateCurrentGestureType(const HardwareState & hwstate,const FingerMap & gs_fingers,FingerMap * active_gs_fingers)1734 void ImmediateInterpreter::UpdateCurrentGestureType(
1735     const HardwareState& hwstate,
1736     const FingerMap& gs_fingers,
1737     FingerMap* active_gs_fingers) {
1738   *active_gs_fingers = gs_fingers;
1739 
1740   size_t num_gesturing = gs_fingers.size();
1741 
1742   // Physical button or tap overrides current gesture state
1743   if (sent_button_down_ || tap_to_click_state_ == kTtcDrag) {
1744     current_gesture_type_ = kGestureTypeMove;
1745     return;
1746   }
1747 
1748   // current gesture state machine
1749   switch (current_gesture_type_) {
1750     case kGestureTypeContactInitiated:
1751     case kGestureTypeButtonsChange:
1752     case kGestureTypeMouseWheel:
1753       break;
1754 
1755     case kGestureTypeScroll:
1756     case kGestureTypeSwipe:
1757     case kGestureTypeFourFingerSwipe:
1758     case kGestureTypeSwipeLift:
1759     case kGestureTypeFourFingerSwipeLift:
1760     case kGestureTypeFling:
1761     case kGestureTypeMove:
1762     case kGestureTypeNull:
1763       // When a finger leaves, we hold the gesture processing for
1764       // change_timeout_ time.
1765       if (hwstate.timestamp < finger_leave_time_ + change_timeout_.val_) {
1766         current_gesture_type_ = kGestureTypeNull;
1767         return;
1768       }
1769 
1770       // Scrolling detection for T5R2 devices
1771       if ((hwprops_->supports_t5r2 || hwprops_->support_semi_mt) &&
1772           (hwstate.touch_cnt > 2)) {
1773         current_gesture_type_ = kGestureTypeScroll;
1774         return;
1775       }
1776 
1777       // Finger gesture decision process
1778       if (num_gesturing == 0) {
1779         current_gesture_type_ = kGestureTypeNull;
1780       } else if (num_gesturing == 1) {
1781         const FingerState* finger =
1782             hwstate.GetFingerState(*gs_fingers.begin());
1783         if (PalmIsArrivingOrDeparting(*finger))
1784           current_gesture_type_ = kGestureTypeNull;
1785         else
1786           current_gesture_type_ = kGestureTypeMove;
1787       } else {
1788         if (changed_time_ > started_moving_time_ ||
1789             hwstate.timestamp - max(started_moving_time_, gs_changed_time_) <
1790             evaluation_timeout_.val_ ||
1791             current_gesture_type_ == kGestureTypeNull) {
1792           // Try to recognize gestures, starting from many-finger gestures
1793           // first. We choose this order b/c 3-finger gestures are very strict
1794           // in their interpretation.
1795           vector<short, kMaxGesturingFingers> sorted_ids;
1796           SortFingersByProximity(gs_fingers, hwstate, &sorted_ids);
1797           for (; sorted_ids.size() >= 2;
1798                sorted_ids.erase(sorted_ids.end() - 1)) {
1799             if (sorted_ids.size() == 2) {
1800               GestureType new_gs_type = kGestureTypeNull;
1801               const FingerState* fingers[] = {
1802                 hwstate.GetFingerState(*sorted_ids.begin()),
1803                 hwstate.GetFingerState(*(sorted_ids.begin() + 1))
1804               };
1805               if (!fingers[0] || !fingers[1]) {
1806                 Err("Unable to find gesturing fingers!");
1807                 return;
1808               }
1809               // See if two pointers are close together
1810               bool potential_two_finger_gesture =
1811                   TwoFingersGesturing(*fingers[0], *fingers[1], false);
1812               if (!potential_two_finger_gesture) {
1813                 new_gs_type = kGestureTypeMove;
1814               } else {
1815                 new_gs_type =
1816                     GetTwoFingerGestureType(*fingers[0], *fingers[1]);
1817                 // Two fingers that don't end up causing scroll may be
1818                 // ambiguous. Only move if they've been down long enough.
1819                 if (new_gs_type == kGestureTypeMove &&
1820                     hwstate.timestamp -
1821                         min(origin_timestamps_[fingers[0]->tracking_id],
1822                             origin_timestamps_[fingers[1]->tracking_id]) <
1823                     evaluation_timeout_.val_)
1824                   new_gs_type = kGestureTypeNull;
1825               }
1826               if (new_gs_type != kGestureTypeMove ||
1827                   gs_fingers.size() == 2) {
1828                 // We only allow this path to set a move gesture if there
1829                 // are two fingers gesturing
1830                 current_gesture_type_ = new_gs_type;
1831               }
1832             } else if (sorted_ids.size() == 3) {
1833               const FingerState* fingers[] = {
1834                 hwstate.GetFingerState(*sorted_ids.begin()),
1835                 hwstate.GetFingerState(*(sorted_ids.begin() + 1)),
1836                 hwstate.GetFingerState(*(sorted_ids.begin() + 2))
1837               };
1838               if (!fingers[0] || !fingers[1] || !fingers[2]) {
1839                 Err("Unable to find gesturing fingers!");
1840                 return;
1841               }
1842               current_gesture_type_ = GetMultiFingerGestureType(fingers, 3);
1843             } else if (sorted_ids.size() == 4) {
1844               const FingerState* fingers[] = {
1845                 hwstate.GetFingerState(*sorted_ids.begin()),
1846                 hwstate.GetFingerState(*(sorted_ids.begin() + 1)),
1847                 hwstate.GetFingerState(*(sorted_ids.begin() + 2)),
1848                 hwstate.GetFingerState(*(sorted_ids.begin() + 3))
1849               };
1850               if (!fingers[0] || !fingers[1] || !fingers[2] || !fingers[3]) {
1851                 Err("Unable to find gesturing fingers!");
1852                 return;
1853               }
1854               current_gesture_type_ = GetMultiFingerGestureType(fingers, 4);
1855               if (current_gesture_type_ == kGestureTypeFourFingerSwipe)
1856                 current_gesture_type_ = kGestureTypeFourFingerSwipe;
1857             }
1858             if (current_gesture_type_ != kGestureTypeNull) {
1859               active_gs_fingers->clear();
1860               for (vector<short, kMaxGesturingFingers>::const_iterator it =
1861                    sorted_ids.begin(), e = sorted_ids.end(); it != e; ++it)
1862                 active_gs_fingers->insert(*it);
1863               break;
1864             }
1865           }
1866         }
1867       }
1868 
1869       if ((current_gesture_type_ == kGestureTypeMove ||
1870            current_gesture_type_ == kGestureTypeNull) &&
1871           (pinch_enable_.val_ && !hwprops_->support_semi_mt) &&
1872           !IsScrollOrSwipe(prev_gesture_type_)) {
1873         bool do_pinch = UpdatePinchState(hwstate, false, gs_fingers);
1874         if (do_pinch) {
1875           current_gesture_type_ = kGestureTypePinch;
1876         } else if (EarlyZoomPotential(hwstate)) {
1877           current_gesture_type_ = kGestureTypeNull;
1878         }
1879       }
1880       break;
1881 
1882     case kGestureTypePinch:
1883       if (fingers_.size() == 2 ||
1884           (pinch_status_ == GESTURES_ZOOM_END &&
1885            prev_gesture_type_ == kGestureTypePinch) ||
1886           (prev_gesture_type_ == kGestureTypePinch &&
1887            pinch_locked_ == true)) {
1888         return;
1889       } else {
1890         current_gesture_type_ = kGestureTypeNull;
1891       }
1892       break;
1893 
1894     case kGestureTypeMetrics:
1895       // One shouldn't reach here
1896       Err("Metrics gestures reached ImmediateInterpreter");
1897       break;
1898   }
1899   return;
1900 }
1901 
IsScrollOrSwipe(GestureType gesture_type)1902 bool ImmediateInterpreter::IsScrollOrSwipe(GestureType gesture_type) {
1903   switch(gesture_type) {
1904     case kGestureTypeScroll:
1905     case kGestureTypeSwipe:
1906     case kGestureTypeFourFingerSwipe:
1907       return true;
1908     default:
1909       return false;
1910   }
1911 }
1912 
GenerateFingerLiftGesture()1913 void ImmediateInterpreter::GenerateFingerLiftGesture() {
1914   // If we have just finished scrolling, we set current_gesture_type_ to the
1915   // appropriate lift gesture.
1916   if (IsScrollOrSwipe(prev_gesture_type_) &&
1917       current_gesture_type_ != prev_gesture_type_) {
1918     current_gesture_type_ = GetFingerLiftGesture(prev_gesture_type_);
1919   }
1920 }
1921 
1922 namespace {
1923 // Can't use tuple<float, short, short> b/c we want to make a variable
1924 // sized array of them on the stack
1925 struct DistSqElt {
1926   float dist_sq;
1927   short tracking_id[2];
1928 };
1929 
1930 struct DistSqCompare {
1931   // Returns true if finger_a is strictly closer to keyboard than finger_b
operator ()gestures::__anone3fa56260311::DistSqCompare1932   bool operator()(const DistSqElt& finger_a, const DistSqElt& finger_b) {
1933     return finger_a.dist_sq < finger_b.dist_sq;
1934   }
1935 };
1936 
1937 }  // namespace {}
1938 
SortFingersByProximity(const FingerMap & finger_ids,const HardwareState & hwstate,vector<short,kMaxGesturingFingers> * out_sorted_ids)1939 void ImmediateInterpreter::SortFingersByProximity(
1940     const FingerMap& finger_ids,
1941     const HardwareState& hwstate,
1942     vector<short, kMaxGesturingFingers>* out_sorted_ids) {
1943   if (finger_ids.size() <= 2) {
1944     for (short finger_id : finger_ids)
1945       out_sorted_ids->push_back(finger_id);
1946     return;
1947   }
1948   // To do the sort, we sort all inter-point distances^2, then scan through
1949   // that until we have enough points
1950   size_t dist_sq_capacity =
1951       (finger_ids.size() * (finger_ids.size() - 1)) / 2;
1952   DistSqElt dist_sq[dist_sq_capacity];
1953   size_t dist_sq_len = 0;
1954   for (size_t i = 0; i < hwstate.finger_cnt; i++) {
1955     const FingerState& fs1 = hwstate.fingers[i];
1956     if (!SetContainsValue(finger_ids, fs1.tracking_id))
1957       continue;
1958     for (size_t j = i + 1; j < hwstate.finger_cnt; j++) {
1959       const FingerState& fs2 = hwstate.fingers[j];
1960       if (!SetContainsValue(finger_ids, fs2.tracking_id))
1961         continue;
1962       DistSqElt elt = {
1963         DistSq(fs1, fs2),
1964         { fs1.tracking_id, fs2.tracking_id }
1965       };
1966       if (dist_sq_len >= dist_sq_capacity) {
1967         Err("%s: Array overrun", __func__);
1968         break;
1969       }
1970       dist_sq[dist_sq_len++] = elt;
1971     }
1972   }
1973 
1974   DistSqCompare distSqCompare;
1975   std::sort(dist_sq, dist_sq + dist_sq_len, distSqCompare);
1976 
1977   if (out_sorted_ids == NULL) {
1978     Err("out_sorted_ids became NULL");
1979     return;
1980   }
1981   for (size_t i = 0; i < dist_sq_len; i++) {
1982     short id1 = dist_sq[i].tracking_id[0];
1983     short id2 = dist_sq[i].tracking_id[1];
1984     bool contains1 = out_sorted_ids->find(id1) != out_sorted_ids->end();
1985     bool contains2 = out_sorted_ids->find(id2) != out_sorted_ids->end();
1986     if (contains1 == contains2 && !out_sorted_ids->empty()) {
1987       // Assuming we have some ids in the out vector, then either we have both
1988       // of these new ids, we have neither. Either way, we can't use this edge.
1989       continue;
1990     }
1991     if (!contains1)
1992       out_sorted_ids->push_back(id1);
1993     if (!contains2)
1994       out_sorted_ids->push_back(id2);
1995     if (out_sorted_ids->size() == finger_ids.size())
1996       break;  // We've got all the IDs
1997   }
1998 }
1999 
2000 
UpdatePinchState(const HardwareState & hwstate,bool reset,const FingerMap & gs_fingers)2001 bool ImmediateInterpreter::UpdatePinchState(
2002     const HardwareState& hwstate, bool reset, const FingerMap& gs_fingers) {
2003 
2004   if (reset) {
2005     if (pinch_locked_ && prev_gesture_type_ == kGestureTypePinch) {
2006       current_gesture_type_ = kGestureTypePinch;
2007       pinch_status_ = GESTURES_ZOOM_END;
2008     }
2009     // perform reset to "don't know" state
2010     pinch_guess_start_ = -1.0f;
2011     pinch_locked_ = false;
2012     pinch_prev_distance_sq_ = -1.0f;
2013     return false;
2014   }
2015 
2016   // once locked stay locked until reset.
2017   if (pinch_locked_) {
2018     pinch_status_ = GESTURES_ZOOM_UPDATE;
2019     return false;
2020   }
2021 
2022   // check if we have two valid fingers
2023   if (gs_fingers.size() != 2) {
2024     return false;
2025   }
2026   const FingerState* finger1 = hwstate.GetFingerState(*(gs_fingers.begin()));
2027   const FingerState* finger2 =
2028       hwstate.GetFingerState(*(++gs_fingers.begin()));
2029   if (finger1 == NULL || finger2 == NULL) {
2030     Err("Finger unexpectedly NULL");
2031     return false;
2032   }
2033 
2034   // don't allow pinching with possible palms
2035   if ((finger1->flags & GESTURES_FINGER_POSSIBLE_PALM) ||
2036       (finger2->flags & GESTURES_FINGER_POSSIBLE_PALM)) {
2037     return false;
2038   }
2039 
2040   // assign the bottom finger to finger2
2041   if (finger1->position_y > finger2->position_y) {
2042     std::swap(finger1, finger2);
2043   }
2044 
2045   // Check if the two fingers have start positions
2046   if (!MapContainsKey(start_positions_, finger1->tracking_id) ||
2047       !MapContainsKey(start_positions_, finger2->tracking_id)) {
2048     return false;
2049   }
2050 
2051   if (pinch_prev_distance_sq_ < 0)
2052     pinch_prev_distance_sq_ = TwoFingerDistanceSq(hwstate);
2053 
2054   // Pinch gesture detection
2055   //
2056   // The pinch gesture detection will try to make a guess about whether a pinch
2057   // or not-a-pinch is performed. If the guess stays valid for a specific time
2058   // (slow but consistent movement) or we get a certain decision (fast
2059   // gesturing) the decision is locked until the state is reset.
2060   // * A high ratio of the traveled distances between fingers indicates
2061   //   that a pinch is NOT performed.
2062   // * Strong movement of both fingers in opposite directions indicates
2063   //   that a pinch IS performed.
2064 
2065   Point delta1 = FingerTraveledVector(*finger1, false, true);
2066   Point delta2 = FingerTraveledVector(*finger2, false, true);
2067 
2068   // dot product. dot < 0 if fingers move away from each other.
2069   float dot = delta1.x_ * delta2.x_ + delta1.y_ * delta2.y_;
2070   // squared distances both finger have been traveled.
2071   float d1sq = delta1.x_ * delta1.x_ + delta1.y_ * delta1.y_;
2072   float d2sq = delta2.x_ * delta2.x_ + delta2.y_ * delta2.y_;
2073 
2074   // True if movement is not strong enough to be distinguished from noise.
2075   // This is not equivalent to a comparison of unsquared values, but seems to
2076   // work well in practice.
2077   bool movement_below_noise = (d1sq + d2sq < pinch_noise_level_sq_.val_);
2078 
2079   // guesses if a pinch is being performed or not.
2080   double guess_min_mov_sq = pinch_guess_min_movement_.val_;
2081   guess_min_mov_sq *= guess_min_mov_sq;
2082   bool guess_no = (d1sq > guess_min_mov_sq) ^ (d2sq > guess_min_mov_sq) ||
2083                   dot > 0;
2084   bool guess_yes = ((d1sq > guess_min_mov_sq || d2sq > guess_min_mov_sq) &&
2085                     dot < 0);
2086   bool pinch_certain = false;
2087 
2088   // true if the lower finger is in the dampened zone
2089   bool in_dampened_zone = origin_positions_[finger2->tracking_id].y_ >
2090                           hwprops_->bottom - bottom_zone_size_.val_;
2091 
2092   float lo_dsq;
2093   float hi_dsq;
2094   if (d1sq < d2sq) {
2095     lo_dsq = d1sq;
2096     hi_dsq = d2sq;
2097   } else {
2098     lo_dsq = d2sq;
2099     hi_dsq = d1sq;
2100   }
2101   bool bad_mov_ratio = lo_dsq <= hi_dsq *
2102                                  pinch_guess_consistent_mov_ratio_.val_ *
2103                                  pinch_guess_consistent_mov_ratio_.val_;
2104 
2105   if (!bad_mov_ratio &&
2106       !in_dampened_zone &&
2107       guess_yes &&
2108       !guess_no &&
2109       ZoomFingersAreConsistent(state_buffer_)) {
2110     pinch_certain = true;
2111   }
2112 
2113   // Thumb is in dampened zone: Only allow inward pinch
2114   if (in_dampened_zone &&
2115       (d2sq < pinch_thumb_min_movement_.val_ * pinch_thumb_min_movement_.val_ ||
2116        !InwardPinch(state_buffer_, *finger2))) {
2117     guess_yes = false;
2118     guess_no = true;
2119     pinch_certain = false;
2120   }
2121 
2122   // do state transitions and final decision
2123   if (pinch_guess_start_ < 0) {
2124     // "Don't Know"-state
2125 
2126     // Determine guess.
2127     if (!movement_below_noise) {
2128       if (guess_no && !guess_yes) {
2129         pinch_guess_ = false;
2130         pinch_guess_start_ = hwstate.timestamp;
2131       }
2132       if (guess_yes && !guess_no) {
2133         pinch_guess_ = true;
2134         pinch_guess_start_ = hwstate.timestamp;
2135       }
2136     }
2137   }
2138   if (pinch_guess_start_ >= 0) {
2139     // "Guessed"-state
2140 
2141     // suppress cursor movement when we guess a pinch gesture
2142     if (pinch_guess_) {
2143       for (size_t i = 0; i < hwstate.finger_cnt; ++i) {
2144         FingerState* finger_state = &hwstate.fingers[i];
2145         finger_state->flags |= GESTURES_FINGER_WARP_X;
2146         finger_state->flags |= GESTURES_FINGER_WARP_Y;
2147       }
2148     }
2149 
2150     // Go back to "Don't Know"-state if guess is no longer valid
2151     if (pinch_guess_ != guess_yes ||
2152         pinch_guess_ == guess_no ||
2153         movement_below_noise) {
2154       pinch_guess_start_ = -1.0f;
2155       return false;
2156     }
2157 
2158     // certain decisions if pinch is being performed or not
2159     double cert_min_mov_sq = pinch_certain_min_movement_.val_;
2160     cert_min_mov_sq *= cert_min_mov_sq;
2161     pinch_certain |= (d1sq > cert_min_mov_sq &&
2162                       d2sq > cert_min_mov_sq) &&
2163                      dot < 0;
2164     bool no_pinch_certain = (d1sq > cert_min_mov_sq ||
2165                              d2sq > cert_min_mov_sq) &&
2166                             dot > 0;
2167     pinch_guess_ |= pinch_certain;
2168     pinch_guess_ &= !no_pinch_certain;
2169 
2170     // guessed for long enough or certain decision was made: lock
2171     if ((hwstate.timestamp - pinch_guess_start_ >
2172          pinch_evaluation_timeout_.val_) ||
2173         pinch_certain ||
2174         no_pinch_certain) {
2175       pinch_status_ = GESTURES_ZOOM_START;
2176       pinch_locked_ = true;
2177       return pinch_guess_;
2178     }
2179   }
2180 
2181   return false;
2182 }
2183 
PalmIsArrivingOrDeparting(const FingerState & finger) const2184 bool ImmediateInterpreter::PalmIsArrivingOrDeparting(
2185     const FingerState& finger) const {
2186   if (((finger.flags & GESTURES_FINGER_POSSIBLE_PALM) ||
2187        (finger.flags & GESTURES_FINGER_PALM)) &&
2188       ((finger.flags & GESTURES_FINGER_TREND_INC_TOUCH_MAJOR) ||
2189        (finger.flags & GESTURES_FINGER_TREND_DEC_TOUCH_MAJOR)) &&
2190       ((finger.flags & GESTURES_FINGER_TREND_INC_PRESSURE) ||
2191        (finger.flags & GESTURES_FINGER_TREND_DEC_PRESSURE)))
2192     return true;
2193   return false;
2194 }
2195 
IsTooCloseToThumb(const FingerState & finger) const2196 bool ImmediateInterpreter::IsTooCloseToThumb(const FingerState& finger) const {
2197   const float kMin2fDistThreshSq = tapping_finger_min_separation_.val_ *
2198       tapping_finger_min_separation_.val_;
2199   for (std::map<short, stime_t>::const_iterator it = thumb_.begin();
2200        it != thumb_.end(); ++it) {
2201     const FingerState* thumb = state_buffer_.Get(0)->GetFingerState(it->first);
2202     float xdist = fabsf(finger.position_x - thumb->position_x);
2203     float ydist = fabsf(finger.position_y - thumb->position_y);
2204     if (xdist * xdist + ydist * ydist < kMin2fDistThreshSq)
2205       return true;
2206   }
2207   return false;
2208 }
2209 
TwoFingersGesturing(const FingerState & finger1,const FingerState & finger2,bool check_button_type) const2210 bool ImmediateInterpreter::TwoFingersGesturing(
2211     const FingerState& finger1,
2212     const FingerState& finger2,
2213     bool check_button_type) const {
2214   // Make sure distance between fingers isn't too great
2215   if (!metrics_->CloseEnoughToGesture(Vector2(finger1), Vector2(finger2)))
2216     return false;
2217 
2218   // Next, if two fingers are moving a lot, they are gesturing together.
2219   if (started_moving_time_ > changed_time_) {
2220     // Fingers are moving
2221     float dist1_sq = DistanceTravelledSq(finger1, false);
2222     float dist2_sq = DistanceTravelledSq(finger2, false);
2223     if (thumb_movement_factor_.val_ * thumb_movement_factor_.val_ *
2224         max(dist1_sq, dist2_sq) < min(dist1_sq, dist2_sq)) {
2225       return true;
2226     }
2227   }
2228 
2229   // Make sure the pressure difference isn't too great for vertically
2230   // aligned contacts
2231   float pdiff = fabsf(finger1.pressure - finger2.pressure);
2232   float xdist = fabsf(finger1.position_x - finger2.position_x);
2233   float ydist = fabsf(finger1.position_y - finger2.position_y);
2234   if (pdiff > two_finger_pressure_diff_thresh_.val_ && ydist > xdist &&
2235       ((finger1.pressure > finger2.pressure) ==
2236        (finger1.position_y > finger2.position_y)))
2237     return false;
2238 
2239   const float kMin2fDistThreshSq = tapping_finger_min_separation_.val_ *
2240       tapping_finger_min_separation_.val_;
2241   float dist_sq = xdist * xdist + ydist * ydist;
2242   // Make sure distance between fingers isn't too small
2243   if ((dist_sq < kMin2fDistThreshSq) &&
2244       !(finger1.flags & GESTURES_FINGER_MERGE))
2245     return false;
2246 
2247   // If both fingers have a tendency of moving at the same direction, they
2248   // are gesturing together. This check is disabled if we are using the
2249   // function to distinguish left/right clicks.
2250   if (!check_button_type) {
2251     unsigned and_flags = finger1.flags & finger2.flags;
2252     if ((and_flags & GESTURES_FINGER_TREND_INC_X) ||
2253         (and_flags & GESTURES_FINGER_TREND_DEC_X) ||
2254         (and_flags & GESTURES_FINGER_TREND_INC_Y) ||
2255         (and_flags & GESTURES_FINGER_TREND_DEC_Y))
2256       return true;
2257   }
2258 
2259   // Next, if fingers are vertically aligned and one is in the bottom zone,
2260   // consider that one a resting thumb (thus, do not scroll/right click)
2261   // if it has greater pressure. For clicking, we relax the pressure requirement
2262   // because we may not have enough time to determine.
2263   if (xdist < ydist && (FingerInDampenedZone(finger1) ||
2264                         FingerInDampenedZone(finger2)) &&
2265       (FingerInDampenedZone(finger1) == (finger1.pressure > finger2.pressure) ||
2266        check_button_type))
2267     return false;
2268   return true;
2269 }
2270 
GetTwoFingerGestureType(const FingerState & finger1,const FingerState & finger2)2271 GestureType ImmediateInterpreter::GetTwoFingerGestureType(
2272     const FingerState& finger1,
2273     const FingerState& finger2) {
2274   if (!MapContainsKey(start_positions_, finger1.tracking_id) ||
2275       !MapContainsKey(start_positions_, finger2.tracking_id))
2276     return kGestureTypeNull;
2277 
2278   // If a finger is close to any thumb, we believe it to be due to thumb-splits
2279   // and ignore it.
2280   int num_close_to_thumb = 0;
2281   num_close_to_thumb += static_cast<int>(IsTooCloseToThumb(finger1));
2282   num_close_to_thumb += static_cast<int>(IsTooCloseToThumb(finger2));
2283   if (num_close_to_thumb == 1)
2284     return kGestureTypeMove;
2285   else if (num_close_to_thumb == 2)
2286     return kGestureTypeNull;
2287 
2288   // Compute distance traveled since fingers changed for each finger
2289   float dx1 = finger1.position_x - start_positions_[finger1.tracking_id].x_;
2290   float dy1 = finger1.position_y - start_positions_[finger1.tracking_id].y_;
2291   float dx2 = finger2.position_x - start_positions_[finger2.tracking_id].x_;
2292   float dy2 = finger2.position_y - start_positions_[finger2.tracking_id].y_;
2293 
2294   float large_dx = MaxMag(dx1, dx2);
2295   float large_dy = MaxMag(dy1, dy2);
2296   // These compares are okay if d{x,y}1 == d{x,y}2:
2297   short large_dx_id =
2298       (large_dx == dx1) ? finger1.tracking_id : finger2.tracking_id;
2299   short large_dy_id =
2300       (large_dy == dy1) ? finger1.tracking_id : finger2.tracking_id;
2301   float small_dx = MinMag(dx1, dx2);
2302   float small_dy = MinMag(dy1, dy2);
2303 
2304   short small_dx_id =
2305       (small_dx == dx1) ? finger1.tracking_id : finger2.tracking_id;
2306   short small_dy_id =
2307       (small_dy == dy1) ? finger1.tracking_id : finger2.tracking_id;
2308 
2309   bool dampened_zone_occupied = false;
2310   // movements of the finger in the dampened zone. If there are multiple
2311   // fingers in the dampened zone, dx is min(dx_1, dx_2), dy is min(dy_1, dy_2).
2312   float damp_dx = INFINITY;
2313   float damp_dy = INFINITY;
2314   float non_damp_dx = 0.0;
2315   float non_damp_dy = 0.0;
2316   if (FingerInDampenedZone(finger1) ||
2317       (finger1.flags & GESTURES_FINGER_POSSIBLE_PALM)) {
2318     dampened_zone_occupied = true;
2319     damp_dx = dx1;
2320     damp_dy = dy1;
2321     non_damp_dx = dx2;
2322     non_damp_dy = dy2;
2323   }
2324   if (FingerInDampenedZone(finger2) ||
2325       (finger2.flags & GESTURES_FINGER_POSSIBLE_PALM)) {
2326     dampened_zone_occupied = true;
2327     damp_dx = MinMag(damp_dx, dx2);
2328     damp_dy = MinMag(damp_dy, dy2);
2329     non_damp_dx = MaxMag(non_damp_dx, dx1);
2330     non_damp_dy = MaxMag(non_damp_dy, dy1);
2331   }
2332 
2333   // Trending in the same direction?
2334   const unsigned kTrendX =
2335       GESTURES_FINGER_TREND_INC_X | GESTURES_FINGER_TREND_DEC_X;
2336   const unsigned kTrendY =
2337       GESTURES_FINGER_TREND_INC_Y | GESTURES_FINGER_TREND_DEC_Y;
2338   unsigned common_trend_flags = finger1.flags & finger2.flags &
2339       (kTrendX | kTrendY);
2340 
2341   bool large_dx_moving =
2342       fabsf(large_dx) >= two_finger_scroll_distance_thresh_.val_ ||
2343       SetContainsValue(moving_, large_dx_id);
2344   bool large_dy_moving =
2345       fabsf(large_dy) >= two_finger_scroll_distance_thresh_.val_ ||
2346       SetContainsValue(moving_, large_dy_id);
2347   bool small_dx_moving =
2348       fabsf(small_dx) >= two_finger_scroll_distance_thresh_.val_ ||
2349       SetContainsValue(moving_, small_dx_id);
2350   bool small_dy_moving =
2351       fabsf(small_dy) >= two_finger_scroll_distance_thresh_.val_ ||
2352       SetContainsValue(moving_, small_dy_id);
2353   bool trend_scrolling_x = (common_trend_flags & kTrendX) &&
2354        large_dx_moving && small_dx_moving;
2355   bool trend_scrolling_y = (common_trend_flags & kTrendY) &&
2356        large_dy_moving && small_dy_moving;
2357 
2358   if (pointing_.size() == 2 && (trend_scrolling_x || trend_scrolling_y)) {
2359     if (pinch_enable_.val_ && !ScrollAngle(finger1, finger2))
2360          return kGestureTypeNull;
2361     return kGestureTypeScroll;
2362   }
2363 
2364   if (fabsf(large_dx) > fabsf(large_dy)) {
2365     // consider horizontal scroll
2366     if (fabsf(small_dx) < two_finger_scroll_distance_thresh_.val_)
2367       small_dx = 0.0;
2368     if (large_dx * small_dx <= 0.0) {
2369       // not same direction
2370       if (fabsf(large_dx) < two_finger_move_distance_thresh_.val_)
2371         return kGestureTypeNull;
2372       else
2373         return kGestureTypeMove;
2374     }
2375     if (fabsf(large_dx) < two_finger_scroll_distance_thresh_.val_)
2376       return kGestureTypeNull;
2377     if (dampened_zone_occupied) {
2378       // Require damp to move at least some amount with the other finger
2379       if (fabsf(damp_dx) <
2380           damp_scroll_min_movement_factor_.val_ * fabsf(non_damp_dx)) {
2381         return kGestureTypeNull;
2382       }
2383     }
2384     if (pinch_enable_.val_ && !ScrollAngle(finger1, finger2))
2385          return kGestureTypeNull;
2386     return kGestureTypeScroll;
2387   } else {
2388     // consider vertical scroll
2389     if (fabsf(small_dy) < two_finger_scroll_distance_thresh_.val_)
2390       small_dy = 0.0;
2391     if (large_dy * small_dy <= 0.0) {
2392       if (fabsf(large_dy) < two_finger_move_distance_thresh_.val_)
2393         return kGestureTypeNull;
2394       else
2395         return kGestureTypeMove;
2396     }
2397     if (dampened_zone_occupied) {
2398       // Require damp to move at least some amount with the other finger
2399       if (fabsf(damp_dy) <
2400           damp_scroll_min_movement_factor_.val_ * fabsf(non_damp_dy)) {
2401         return kGestureTypeNull;
2402       }
2403     }
2404     if (pinch_enable_.val_ && !ScrollAngle(finger1, finger2))
2405          return kGestureTypeNull;
2406     return kGestureTypeScroll;
2407   }
2408 }
2409 
GetFingerLiftGesture(GestureType current_gesture_type)2410 GestureType ImmediateInterpreter::GetFingerLiftGesture(
2411     GestureType current_gesture_type) {
2412   switch(current_gesture_type) {
2413     case kGestureTypeScroll: return kGestureTypeFling;
2414     case kGestureTypeSwipe: return kGestureTypeSwipeLift;
2415     case kGestureTypeFourFingerSwipe: return kGestureTypeFourFingerSwipeLift;
2416     default: return kGestureTypeNull;
2417   }
2418 }
2419 
GetMultiFingerGestureType(const FingerState * const fingers[],const int num_fingers)2420 GestureType ImmediateInterpreter::GetMultiFingerGestureType(
2421     const FingerState* const fingers[], const int num_fingers) {
2422   float swipe_distance_thresh;
2423   float swipe_distance_ratio;
2424   std::map<short, Point> *swipe_start_positions;
2425   GestureType gesture_type;
2426   if (num_fingers == 4) {
2427     swipe_distance_thresh = four_finger_swipe_distance_thresh_.val_;
2428     swipe_distance_ratio = four_finger_swipe_distance_ratio_.val_;
2429     swipe_start_positions = &four_finger_swipe_start_positions_;
2430     gesture_type = kGestureTypeFourFingerSwipe;
2431   } else if (num_fingers == 3) {
2432     swipe_distance_thresh = three_finger_swipe_distance_thresh_.val_;
2433     swipe_distance_ratio = three_finger_swipe_distance_ratio_.val_;
2434     swipe_start_positions = &three_finger_swipe_start_positions_;
2435     gesture_type = kGestureTypeSwipe;
2436   } else {
2437     return kGestureTypeNull;
2438   }
2439 
2440   const FingerState* x_fingers[num_fingers];
2441   const FingerState* y_fingers[num_fingers];
2442   for (int i = 0; i < num_fingers; i++) {
2443     x_fingers[i] = fingers[i];
2444     y_fingers[i] = fingers[i];
2445   }
2446   std::sort(x_fingers, x_fingers + num_fingers,
2447             [] (const FingerState* a, const FingerState* b) ->
2448                 bool { return a->position_x < b->position_x; });
2449   std::sort(y_fingers, y_fingers + num_fingers,
2450             [] (const FingerState* a, const FingerState* b) ->
2451                 bool { return a->position_y < b->position_y; });
2452   bool horizontal =
2453       (x_fingers[num_fingers - 1]->position_x - x_fingers[0]->position_x) >=
2454       (y_fingers[num_fingers -1]->position_y - y_fingers[0]->position_y);
2455   const FingerState* sorted_fingers[num_fingers];
2456   for (int i = 0; i < num_fingers; i++) {
2457     sorted_fingers[i] = horizontal ? x_fingers[i] : y_fingers[i];
2458   }
2459 
2460   float dx[num_fingers];
2461   float dy[num_fingers];
2462   float dy_sum = 0;
2463   float dx_sum = 0;
2464   for (int i = 0; i < num_fingers; i++) {
2465     dx[i] = sorted_fingers[i]->position_x -
2466             (*swipe_start_positions)[sorted_fingers[i]->tracking_id].x_;
2467     dy[i] = sorted_fingers[i]->position_y -
2468             (*swipe_start_positions)[sorted_fingers[i]->tracking_id].y_;
2469     dx_sum += dx[i];
2470     dy_sum += dy[i];
2471   }
2472   // pick horizontal or vertical
2473   float *deltas = fabsf(dx_sum) > fabsf(dy_sum) ? dx : dy;
2474   swipe_is_vertical_ = deltas == dy;
2475 
2476   // All fingers must move in the same direction.
2477   for (int i = 1; i < num_fingers; i++) {
2478     if (deltas[i] * deltas[0] <= 0.0) {
2479       for (int i = 0; i < num_fingers; i++) {
2480         Point point(sorted_fingers[i]->position_x,
2481                     sorted_fingers[i]->position_y);
2482         (*swipe_start_positions)[sorted_fingers[i]->tracking_id] =
2483             point;
2484       }
2485       return kGestureTypeNull;
2486     }
2487   }
2488 
2489   // All fingers must have traveled far enough.
2490   float max_delta = fabsf(deltas[0]);
2491   float min_delta = fabsf(deltas[0]);
2492   for (int i = 1; i < num_fingers; i++) {
2493     max_delta = max(max_delta, fabsf(deltas[i]));
2494     min_delta = min(min_delta, fabsf(deltas[i]));
2495   }
2496   if (max_delta >= swipe_distance_thresh &&
2497       min_delta >= swipe_distance_ratio * max_delta)
2498     return gesture_type;
2499   return kGestureTypeNull;
2500 }
2501 
TapToClickStateName(TapToClickState state)2502 const char* ImmediateInterpreter::TapToClickStateName(TapToClickState state) {
2503   switch (state) {
2504     case kTtcIdle: return "Idle";
2505     case kTtcFirstTapBegan: return "FirstTapBegan";
2506     case kTtcTapComplete: return "TapComplete";
2507     case kTtcSubsequentTapBegan: return "SubsequentTapBegan";
2508     case kTtcDrag: return "Drag";
2509     case kTtcDragRelease: return "DragRelease";
2510     case kTtcDragRetouch: return "DragRetouch";
2511     default: return "<unknown>";
2512   }
2513 }
2514 
TimeoutForTtcState(TapToClickState state)2515 stime_t ImmediateInterpreter::TimeoutForTtcState(TapToClickState state) {
2516   switch (state) {
2517     case kTtcIdle: return tap_timeout_.val_;
2518     case kTtcFirstTapBegan: return tap_timeout_.val_;
2519     case kTtcTapComplete: return inter_tap_timeout_.val_;
2520     case kTtcSubsequentTapBegan: return tap_timeout_.val_;
2521     case kTtcDrag: return tap_timeout_.val_;
2522     case kTtcDragRelease: return tap_drag_timeout_.val_;
2523     case kTtcDragRetouch: return tap_timeout_.val_;
2524     default:
2525       Log("Unknown state!");
2526       return 0.0;
2527   }
2528 }
2529 
SetTapToClickState(TapToClickState state,stime_t now)2530 void ImmediateInterpreter::SetTapToClickState(TapToClickState state,
2531                                               stime_t now) {
2532   if (tap_to_click_state_ != state) {
2533     tap_to_click_state_ = state;
2534     tap_to_click_state_entered_ = now;
2535   }
2536 }
2537 
UpdateTapGesture(const HardwareState * hwstate,const FingerMap & gs_fingers,const bool same_fingers,stime_t now,stime_t * timeout)2538 void ImmediateInterpreter::UpdateTapGesture(
2539     const HardwareState* hwstate,
2540     const FingerMap& gs_fingers,
2541     const bool same_fingers,
2542     stime_t now,
2543     stime_t* timeout) {
2544   unsigned down = 0;
2545   unsigned up = 0;
2546   UpdateTapState(hwstate, gs_fingers, same_fingers, now, &down, &up, timeout);
2547   if (down == 0 && up == 0) {
2548     return;
2549   }
2550   Log("UpdateTapGesture: Tap Generated");
2551   result_ = Gesture(kGestureButtonsChange,
2552                     state_buffer_.Get(1)->timestamp,
2553                     now,
2554                     down,
2555                     up,
2556                     true); // is_tap
2557 }
2558 
UpdateTapState(const HardwareState * hwstate,const FingerMap & gs_fingers,const bool same_fingers,stime_t now,unsigned * buttons_down,unsigned * buttons_up,stime_t * timeout)2559 void ImmediateInterpreter::UpdateTapState(
2560     const HardwareState* hwstate,
2561     const FingerMap& gs_fingers,
2562     const bool same_fingers,
2563     stime_t now,
2564     unsigned* buttons_down,
2565     unsigned* buttons_up,
2566     stime_t* timeout) {
2567   if (tap_to_click_state_ == kTtcIdle && (!tap_enable_.val_ ||
2568                                           tap_paused_.val_))
2569     return;
2570 
2571   FingerMap tap_gs_fingers;
2572 
2573   if (hwstate)
2574     RemoveMissingIdsFromSet(&tap_dead_fingers_, *hwstate);
2575 
2576   bool cancel_tapping = false;
2577   if (hwstate) {
2578     for (int i = 0; i < hwstate->finger_cnt; ++i) {
2579       if (hwstate->fingers[i].flags &
2580           (GESTURES_FINGER_NO_TAP | GESTURES_FINGER_MERGE))
2581         cancel_tapping = true;
2582     }
2583     for (FingerMap::const_iterator it =
2584              gs_fingers.begin(), e = gs_fingers.end(); it != e; ++it) {
2585       const FingerState* fs = hwstate->GetFingerState(*it);
2586       if (!fs) {
2587         Err("Missing finger state?!");
2588         continue;
2589       }
2590       tap_gs_fingers.insert(*it);
2591     }
2592   }
2593   std::set<short> added_fingers;
2594 
2595   // Fingers removed from the pad entirely
2596   std::set<short> removed_fingers;
2597 
2598   // Fingers that were gesturing, but now aren't
2599   std::set<short> dead_fingers;
2600 
2601   const bool phys_click_in_progress = hwstate && hwstate->buttons_down != 0 &&
2602     (zero_finger_click_enable_.val_ || finger_seen_shortly_after_button_down_);
2603 
2604   bool is_timeout = (now - tap_to_click_state_entered_ >
2605                      TimeoutForTtcState(tap_to_click_state_));
2606 
2607   if (phys_click_in_progress) {
2608     // Don't allow any current fingers to tap ever
2609     for (size_t i = 0; i < hwstate->finger_cnt; i++)
2610       tap_dead_fingers_.insert(hwstate->fingers[i].tracking_id);
2611   }
2612 
2613   if (hwstate && (!same_fingers || prev_tap_gs_fingers_ != tap_gs_fingers)) {
2614     // See if fingers were added
2615     for (FingerMap::const_iterator it =
2616              tap_gs_fingers.begin(), e = tap_gs_fingers.end(); it != e; ++it) {
2617       // If the finger was marked as a thumb before, it is not new.
2618       if (hwstate->timestamp - finger_origin_timestamp(*it) >
2619                thumb_click_prevention_timeout_.val_)
2620         continue;
2621 
2622       if (!SetContainsValue(prev_tap_gs_fingers_, *it)) {
2623         // Gesturing finger wasn't in prev state. It's new.
2624         const FingerState* fs = hwstate->GetFingerState(*it);
2625         if (FingerTooCloseToTap(*hwstate, *fs) ||
2626             FingerTooCloseToTap(*state_buffer_.Get(1), *fs) ||
2627             SetContainsValue(tap_dead_fingers_, fs->tracking_id))
2628           continue;
2629         added_fingers.insert(*it);
2630         Log("TTC: Added %d", *it);
2631       }
2632     }
2633 
2634     // See if fingers were removed or are now non-gesturing (dead)
2635     for (FingerMap::const_iterator it =
2636              prev_tap_gs_fingers_.begin(), e = prev_tap_gs_fingers_.end();
2637          it != e; ++it) {
2638       if (tap_gs_fingers.find(*it) != tap_gs_fingers.end())
2639         // still gesturing; neither removed nor dead
2640         continue;
2641       if (!hwstate->GetFingerState(*it)) {
2642         // Previously gesturing finger isn't in current state. It's gone.
2643         removed_fingers.insert(*it);
2644         Log("TTC: Removed %d", *it);
2645       } else {
2646         // Previously gesturing finger is in current state. It's dead.
2647         dead_fingers.insert(*it);
2648         Log("TTC: Dead %d", *it);
2649       }
2650     }
2651   }
2652 
2653   prev_tap_gs_fingers_ = tap_gs_fingers;
2654 
2655   // The state machine:
2656 
2657   // If you are updating the code, keep this diagram correct.
2658   // We have a TapRecord which stores current tap state.
2659   // Also, if the physical button is down or previous gesture type is scroll,
2660   // we go to (or stay in) Idle state.
2661 
2662   //     Start
2663   //       ↓
2664   //    [Idle**] <----------------------------------------------------------,
2665   //       ↓ added finger(s)                                                ^
2666   //  ,>[FirstTapBegan] -<right click: send right click, timeout/movement>->|
2667   //  |    ↓ released all fingers                                           |
2668   // ,->[TapComplete*] --<timeout: send click>----------------------------->|
2669   // ||    | | two finger touching: send left click.                        |
2670   // |'<---+-'                                                              ^
2671   // |     ↓ add finger(s)                                                  |
2672   // ^  [SubsequentTapBegan] --<timeout/move w/o delay: send click>-------->|
2673   // |     | | | release all fingers: send left click                       |
2674   // |<----+-+-'                                                            ^
2675   // |     | `-> start non-left click: send left click; goto FirstTapBegan  |
2676   // |     ↓ timeout/movement with delay: send button down                  |
2677   // | ,->[Drag] --<detect 2 finger gesture: send button up>--------------->|
2678   // | |   ↓ release all fingers                                            ^
2679   // | |  [DragRelease*]  --<timeout: send button up>---------------------->|
2680   // ^ ^   ↓ add finger(s)                                                  ^
2681   // | |  [DragRetouch]  --<remove fingers (left tap): send button up>----->'
2682   // | |   | | timeout/movement
2683   // | '-<-+-'
2684   // |     |  remove all fingers (non-left tap): send button up
2685   // '<----'
2686   //
2687   // * When entering TapComplete or DragRelease, we set a timer, since
2688   //   we will have no fingers on the pad and want to run possibly before
2689   //   fingers are put on the pad. Note that we use different timeouts
2690   //   based on which state we're in (tap_timeout_ or tap_drag_timeout_).
2691   // ** When entering idle, we reset the TapRecord.
2692 
2693   if (tap_to_click_state_ != kTtcIdle)
2694     Log("TTC State: %s", TapToClickStateName(tap_to_click_state_));
2695   if (!hwstate)
2696     Log("TTC: This is a timer callback");
2697   if (phys_click_in_progress || KeyboardRecentlyUsed(now) ||
2698       prev_result_.type == kGestureTypeScroll ||
2699       cancel_tapping) {
2700     Log("TTC: Forced to idle");
2701     SetTapToClickState(kTtcIdle, now);
2702     return;
2703   }
2704 
2705   switch (tap_to_click_state_) {
2706     case kTtcIdle:
2707       tap_record_.Clear();
2708       if (hwstate &&
2709           hwstate->timestamp - last_movement_timestamp_ >=
2710           motion_tap_prevent_timeout_.val_) {
2711         tap_record_.Update(
2712             *hwstate, *state_buffer_.Get(1), added_fingers, removed_fingers,
2713             dead_fingers);
2714         if (tap_record_.TapBegan())
2715           SetTapToClickState(kTtcFirstTapBegan, now);
2716       }
2717       break;
2718     case kTtcFirstTapBegan:
2719       if (is_timeout) {
2720         SetTapToClickState(kTtcIdle, now);
2721         break;
2722       }
2723       if (!hwstate) {
2724         Log("hwstate NULL but no timeout?!");
2725         break;
2726       }
2727       tap_record_.Update(
2728           *hwstate, *state_buffer_.Get(1), added_fingers,
2729           removed_fingers, dead_fingers);
2730       Log("TTC: Is tap? %d Is moving? %d",
2731           tap_record_.TapComplete(),
2732           tap_record_.Moving(*hwstate, tap_move_dist_.val_));
2733       if (tap_record_.TapComplete()) {
2734         if (!tap_record_.MinTapPressureMet() ||
2735             !tap_record_.FingersBelowMaxAge()) {
2736           SetTapToClickState(kTtcIdle, now);
2737         } else if (tap_record_.TapType() == GESTURES_BUTTON_LEFT &&
2738                    tap_drag_enable_.val_) {
2739           SetTapToClickState(kTtcTapComplete, now);
2740         } else {
2741           *buttons_down = *buttons_up = tap_record_.TapType();
2742           SetTapToClickState(kTtcIdle, now);
2743         }
2744       } else if (tap_record_.Moving(*hwstate, tap_move_dist_.val_)) {
2745         SetTapToClickState(kTtcIdle, now);
2746       }
2747       break;
2748     case kTtcTapComplete:
2749       if (!added_fingers.empty()) {
2750 
2751         tap_record_.Clear();
2752         tap_record_.Update(
2753             *hwstate, *state_buffer_.Get(1), added_fingers, removed_fingers,
2754             dead_fingers);
2755 
2756         // If more than one finger is touching: Send click
2757         // and return to FirstTapBegan state.
2758         if (tap_record_.TapType() != GESTURES_BUTTON_LEFT) {
2759           *buttons_down = *buttons_up = GESTURES_BUTTON_LEFT;
2760           SetTapToClickState(kTtcFirstTapBegan, now);
2761         } else {
2762           tap_drag_last_motion_time_ = now;
2763           tap_drag_finger_was_stationary_ = false;
2764           SetTapToClickState(kTtcSubsequentTapBegan, now);
2765         }
2766       } else if (is_timeout) {
2767         *buttons_down = *buttons_up =
2768             tap_record_.MinTapPressureMet() ? tap_record_.TapType() : 0;
2769         SetTapToClickState(kTtcIdle, now);
2770       }
2771       break;
2772     case kTtcSubsequentTapBegan:
2773       if (!is_timeout && !hwstate) {
2774         Log("hwstate NULL but not a timeout?!");
2775         break;
2776       }
2777       if (hwstate)
2778         tap_record_.Update(*hwstate, *state_buffer_.Get(1), added_fingers,
2779                            removed_fingers, dead_fingers);
2780 
2781       if (!tap_record_.Motionless(*hwstate, *state_buffer_.Get(1),
2782                                   tap_max_movement_.val_)) {
2783         tap_drag_last_motion_time_ = now;
2784       }
2785       if (tap_record_.TapType() == GESTURES_BUTTON_LEFT &&
2786           now - tap_drag_last_motion_time_ >= tap_drag_stationary_time_.val_) {
2787         tap_drag_finger_was_stationary_ = true;
2788       }
2789 
2790       if (is_timeout || tap_record_.Moving(*hwstate, tap_move_dist_.val_)) {
2791         if (tap_record_.TapType() == GESTURES_BUTTON_LEFT) {
2792           if (is_timeout) {
2793             // moving with just one finger. Start dragging.
2794             *buttons_down = GESTURES_BUTTON_LEFT;
2795             SetTapToClickState(kTtcDrag, now);
2796           } else {
2797             bool drag_delay_met = (now - tap_to_click_state_entered_
2798                                    >= tap_drag_delay_.val_);
2799             if (drag_delay_met && tap_drag_finger_was_stationary_) {
2800               *buttons_down = GESTURES_BUTTON_LEFT;
2801               SetTapToClickState(kTtcDrag, now);
2802             } else {
2803               *buttons_down = GESTURES_BUTTON_LEFT;
2804               *buttons_up = GESTURES_BUTTON_LEFT;
2805               SetTapToClickState(kTtcIdle, now);
2806             }
2807           }
2808         } else if (!tap_record_.TapComplete()) {
2809           // not just one finger. Send button click and go to idle.
2810           *buttons_down = *buttons_up = GESTURES_BUTTON_LEFT;
2811           SetTapToClickState(kTtcIdle, now);
2812         }
2813         break;
2814       }
2815       if (tap_record_.TapType() != GESTURES_BUTTON_LEFT) {
2816         // We aren't going to drag, so send left click now and handle current
2817         // tap afterwards.
2818         *buttons_down = *buttons_up = GESTURES_BUTTON_LEFT;
2819         SetTapToClickState(kTtcFirstTapBegan, now);
2820       }
2821       if (tap_record_.TapComplete()) {
2822         *buttons_down = *buttons_up = GESTURES_BUTTON_LEFT;
2823         SetTapToClickState(kTtcTapComplete, now);
2824         Log("TTC: Subsequent left tap complete");
2825       }
2826       break;
2827     case kTtcDrag:
2828       if (hwstate)
2829         tap_record_.Update(
2830             *hwstate, *state_buffer_.Get(1), added_fingers, removed_fingers,
2831             dead_fingers);
2832       if (tap_record_.TapComplete()) {
2833         tap_record_.Clear();
2834         if (drag_lock_enable_.val_) {
2835           SetTapToClickState(kTtcDragRelease, now);
2836         } else {
2837           *buttons_up = GESTURES_BUTTON_LEFT;
2838           SetTapToClickState(kTtcIdle, now);
2839         }
2840       }
2841       if (tap_record_.TapType() != GESTURES_BUTTON_LEFT &&
2842           now - tap_to_click_state_entered_ <= evaluation_timeout_.val_) {
2843         // We thought we were dragging, but actually we're doing a
2844         // non-tap-to-click multitouch gesture.
2845         *buttons_up = GESTURES_BUTTON_LEFT;
2846         SetTapToClickState(kTtcIdle, now);
2847       }
2848       break;
2849     case kTtcDragRelease:
2850       if (!added_fingers.empty()) {
2851         tap_record_.Update(
2852             *hwstate, *state_buffer_.Get(1), added_fingers, removed_fingers,
2853             dead_fingers);
2854         SetTapToClickState(kTtcDragRetouch, now);
2855       } else if (is_timeout) {
2856         *buttons_up = GESTURES_BUTTON_LEFT;
2857         SetTapToClickState(kTtcIdle, now);
2858       }
2859       break;
2860     case kTtcDragRetouch:
2861       if (hwstate)
2862         tap_record_.Update(
2863             *hwstate, *state_buffer_.Get(1), added_fingers, removed_fingers,
2864             dead_fingers);
2865       if (tap_record_.TapComplete()) {
2866         *buttons_up = GESTURES_BUTTON_LEFT;
2867         if (tap_record_.TapType() == GESTURES_BUTTON_LEFT)
2868           SetTapToClickState(kTtcIdle, now);
2869         else
2870           SetTapToClickState(kTtcTapComplete, now);
2871         break;
2872       }
2873       if (is_timeout) {
2874         SetTapToClickState(kTtcDrag, now);
2875         break;
2876       }
2877       if (!hwstate) {
2878         Log("not timeout but hwstate is NULL?!");
2879         break;
2880       }
2881       if (tap_record_.Moving(*hwstate, tap_move_dist_.val_))
2882         SetTapToClickState(kTtcDrag, now);
2883       break;
2884   }
2885   if (tap_to_click_state_ != kTtcIdle)
2886     Log("TTC: New state: %s", TapToClickStateName(tap_to_click_state_));
2887   // Take action based on new state:
2888   switch (tap_to_click_state_) {
2889     case kTtcTapComplete:
2890       *timeout = TimeoutForTtcState(tap_to_click_state_);
2891       break;
2892     case kTtcDragRelease:
2893       *timeout = TimeoutForTtcState(tap_to_click_state_);
2894       break;
2895     default:  // so gcc doesn't complain about missing enums
2896       break;
2897   }
2898 }
2899 
FingerTooCloseToTap(const HardwareState & hwstate,const FingerState & fs)2900 bool ImmediateInterpreter::FingerTooCloseToTap(const HardwareState& hwstate,
2901                                                const FingerState& fs) {
2902   const float kMinAllowableSq =
2903       tapping_finger_min_separation_.val_ * tapping_finger_min_separation_.val_;
2904   for (size_t i = 0; i < hwstate.finger_cnt; i++) {
2905     const FingerState* iter_fs = &hwstate.fingers[i];
2906     if (iter_fs->tracking_id == fs.tracking_id)
2907       continue;
2908     float dist_sq = DistSq(fs, *iter_fs);
2909     if (dist_sq < kMinAllowableSq)
2910       return true;
2911   }
2912   return false;
2913 }
2914 
FingerInDampenedZone(const FingerState & finger) const2915 bool ImmediateInterpreter::FingerInDampenedZone(
2916     const FingerState& finger) const {
2917   // TODO(adlr): cache thresh
2918   float thresh = hwprops_->bottom - bottom_zone_size_.val_;
2919   return finger.position_y > thresh;
2920 }
2921 
FillStartPositions(const HardwareState & hwstate)2922 void ImmediateInterpreter::FillStartPositions(const HardwareState& hwstate) {
2923   RemoveMissingIdsFromMap(&origin_positions_, hwstate);
2924 
2925   for (short i = 0; i < hwstate.finger_cnt; i++) {
2926     Point point(hwstate.fingers[i].position_x,
2927                 hwstate.fingers[i].position_y);
2928     start_positions_[hwstate.fingers[i].tracking_id] = point;
2929     three_finger_swipe_start_positions_[hwstate.fingers[i].tracking_id] = point;
2930     four_finger_swipe_start_positions_[hwstate.fingers[i].tracking_id] = point;
2931     if (!MapContainsKey(origin_positions_, hwstate.fingers[i].tracking_id))
2932       origin_positions_[hwstate.fingers[i].tracking_id] = point;
2933   }
2934 }
2935 
GetButtonTypeFromPosition(const HardwareState & hwstate)2936 int ImmediateInterpreter::GetButtonTypeFromPosition(
2937     const HardwareState& hwstate) {
2938   if (hwstate.finger_cnt <= 0 || hwstate.finger_cnt > 1 ||
2939       !button_right_click_zone_enable_.val_) {
2940     return GESTURES_BUTTON_LEFT;
2941   }
2942 
2943   const FingerState& fs = hwstate.fingers[0];
2944   if (fs.position_x > hwprops_->right - button_right_click_zone_size_.val_) {
2945     return GESTURES_BUTTON_RIGHT;
2946   }
2947 
2948   return GESTURES_BUTTON_LEFT;
2949 }
2950 
EvaluateButtonType(const HardwareState & hwstate,stime_t button_down_time)2951 int ImmediateInterpreter::EvaluateButtonType(
2952     const HardwareState& hwstate, stime_t button_down_time) {
2953   // Handle T5R2/SemiMT touchpads
2954   if ((hwprops_->supports_t5r2 || hwprops_->support_semi_mt) &&
2955       hwstate.touch_cnt > 2) {
2956     if (hwstate.touch_cnt - thumb_.size() == 3 &&
2957         three_finger_click_enable_.val_ && t5r2_three_finger_click_enable_.val_)
2958       return GESTURES_BUTTON_MIDDLE;
2959     return GESTURES_BUTTON_RIGHT;
2960   }
2961 
2962   // Just return the hardware state button, based on finger position,
2963   // if no further analysis is needed.
2964   bool finger_update = finger_button_click_.Update(hwstate, button_down_time);
2965   if (!finger_update && hwprops_->is_button_pad &&
2966       hwstate.buttons_down == GESTURES_BUTTON_LEFT) {
2967     return GetButtonTypeFromPosition(hwstate);
2968   } else if (!finger_update) {
2969     return hwstate.buttons_down;
2970   }
2971   Log("EvaluateButtonType: R/C/H: %d/%d/%d",
2972       finger_button_click_.num_recent(),
2973       finger_button_click_.num_cold(),
2974       finger_button_click_.num_hot());
2975 
2976   // Handle 2 finger cases:
2977   if (finger_button_click_.num_fingers() == 2)
2978     return finger_button_click_.EvaluateTwoFingerButtonType();
2979 
2980   // Handle cases with 3 or more fingers:
2981   return finger_button_click_.EvaluateThreeOrMoreFingerButtonType();
2982 }
2983 
UpdateMovingFingers(const HardwareState & hwstate)2984 FingerMap ImmediateInterpreter::UpdateMovingFingers(
2985     const HardwareState& hwstate) {
2986   FingerMap newly_moving_fingers;
2987   if (moving_.size() == hwstate.finger_cnt)
2988     return newly_moving_fingers;  // All fingers already started moving
2989   const float kMinDistSq =
2990       change_move_distance_.val_ * change_move_distance_.val_;
2991   for (size_t i = 0; i < hwstate.finger_cnt; i++) {
2992     const FingerState& fs = hwstate.fingers[i];
2993     if (!MapContainsKey(start_positions_, fs.tracking_id)) {
2994       Err("Missing start position!");
2995       continue;
2996     }
2997     if (SetContainsValue(moving_, fs.tracking_id)) {
2998       // This finger already moving
2999       continue;
3000     }
3001     float dist_sq = DistanceTravelledSq(fs, false);
3002     if (dist_sq > kMinDistSq) {
3003       moving_.insert(fs.tracking_id);
3004       newly_moving_fingers.insert(fs.tracking_id);
3005     }
3006   }
3007   return newly_moving_fingers;
3008 }
3009 
UpdateStartedMovingTime(stime_t now,const FingerMap & gs_fingers,const FingerMap & newly_moving_fingers)3010 void ImmediateInterpreter::UpdateStartedMovingTime(
3011     stime_t now,
3012     const FingerMap& gs_fingers,
3013     const FingerMap& newly_moving_fingers) {
3014   // Update started moving time if any gesturing finger is newly moving.
3015   for (auto it = gs_fingers.begin(), e = gs_fingers.end(); it != e; ++it) {
3016     if (SetContainsValue(newly_moving_fingers, *it)) {
3017       started_moving_time_ = now;
3018       // Extend the thumb evaluation period for any finger that is still under
3019       // evaluation as there is a new moving finger.
3020       for (std::map<short, stime_t>::iterator it = thumb_.begin();
3021            it != thumb_.end(); ++it)
3022         if ((*it).second < thumb_eval_timeout_.val_ && (*it).second > 0.0)
3023           (*it).second = thumb_eval_timeout_.val_;
3024       return;
3025     }
3026   }
3027 }
3028 
UpdateButtons(const HardwareState & hwstate,stime_t * timeout)3029 void ImmediateInterpreter::UpdateButtons(const HardwareState& hwstate,
3030                                          stime_t* timeout) {
3031   // TODO(miletus): To distinguish between left/right buttons down
3032   bool prev_button_down = state_buffer_.Get(1)->buttons_down;
3033   bool button_down = hwstate.buttons_down;
3034   if (!prev_button_down && !button_down)
3035     return;
3036   // For haptic touchpads, we need to minimize latency for physical button
3037   // events because they are used to signal the touchpad to perform haptic
3038   // feedback.
3039   double button_evaluation_timeout = is_haptic_pad_ ? 0.0 :
3040       button_evaluation_timeout_.val_;
3041   double button_finger_timeout = is_haptic_pad_ ? 0.0 :
3042       button_finger_timeout_.val_;
3043   bool phys_down_edge = button_down && !prev_button_down;
3044   bool phys_up_edge = !button_down && prev_button_down;
3045   if (phys_down_edge) {
3046     finger_seen_shortly_after_button_down_ = false;
3047     sent_button_down_ = false;
3048     button_down_timeout_ = hwstate.timestamp + button_evaluation_timeout;
3049   }
3050 
3051   // If we haven't seen a finger on the pad shortly after the click, do nothing
3052   if (!finger_seen_shortly_after_button_down_ &&
3053       hwstate.timestamp <= button_down_timeout_)
3054     finger_seen_shortly_after_button_down_ = (hwstate.finger_cnt > 0);
3055   if (!finger_seen_shortly_after_button_down_ &&
3056       !zero_finger_click_enable_.val_)
3057     return;
3058 
3059   if (!sent_button_down_) {
3060     stime_t button_down_time = button_down_timeout_ -
3061                                button_evaluation_timeout;
3062     button_type_ = EvaluateButtonType(hwstate, button_down_time);
3063 
3064     if (!hwstate.SameFingersAs(*state_buffer_.Get(0))) {
3065       // Fingers have changed since last state, reset timeout
3066       button_down_timeout_ = hwstate.timestamp + button_finger_timeout;
3067     }
3068 
3069     // button_up before button_evaluation_timeout expired.
3070     // Send up & down for button that was previously down, but not yet sent.
3071     if (button_type_ == GESTURES_BUTTON_NONE)
3072       button_type_ = prev_button_down;
3073     // Send button down if timeout has been reached or button up happened
3074     if (button_down_timeout_ <= hwstate.timestamp ||
3075         phys_up_edge) {
3076       // Send button down
3077       if (result_.type == kGestureTypeButtonsChange)
3078         Err("Gesture type already button?!");
3079       result_ = Gesture(kGestureButtonsChange,
3080                         state_buffer_.Get(1)->timestamp,
3081                         hwstate.timestamp,
3082                         button_type_,
3083                         0,
3084                         false); // is_tap
3085       sent_button_down_ = true;
3086     } else if (timeout) {
3087       *timeout = button_down_timeout_ - hwstate.timestamp;
3088     }
3089   }
3090   if (phys_up_edge) {
3091     // Send button up
3092     if (result_.type != kGestureTypeButtonsChange)
3093       result_ = Gesture(kGestureButtonsChange,
3094                         state_buffer_.Get(1)->timestamp,
3095                         hwstate.timestamp,
3096                         0,
3097                         button_type_,
3098                         false); // is_tap
3099     else
3100       result_.details.buttons.up = button_type_;
3101     // Reset button state
3102     button_type_ = GESTURES_BUTTON_NONE;
3103     button_down_timeout_ = 0;
3104     sent_button_down_ = false;
3105     // When a buttons_up event is generated, we need to reset the
3106     // finger_leave_time_ in order to defer any gesture generation
3107     // right after it.
3108     finger_leave_time_ = hwstate.timestamp;
3109   }
3110 }
3111 
UpdateButtonsTimeout(stime_t now)3112 void ImmediateInterpreter::UpdateButtonsTimeout(stime_t now) {
3113   if (sent_button_down_) {
3114     Err("How is sent_button_down_ set?");
3115     return;
3116   }
3117   if (button_type_ == GESTURES_BUTTON_NONE)
3118     return;
3119   sent_button_down_ = true;
3120   result_ = Gesture(kGestureButtonsChange,
3121                     state_buffer_.Get(1)->timestamp,
3122                     now,
3123                     button_type_,
3124                     0,
3125                     false); // is_tap
3126 }
3127 
FillResultGesture(const HardwareState & hwstate,const FingerMap & fingers)3128 void ImmediateInterpreter::FillResultGesture(
3129     const HardwareState& hwstate,
3130     const FingerMap& fingers) {
3131   bool zero_move = false;
3132   switch (current_gesture_type_) {
3133     case kGestureTypeMove: {
3134       if (fingers.empty())
3135         return;
3136       // Use the finger which has moved the most to compute motion.
3137       // First, need to find out which finger that is.
3138       const FingerState* current = NULL;
3139       if (moving_finger_id_ >= 0)
3140         current = hwstate.GetFingerState(moving_finger_id_);
3141 
3142       const HardwareState* prev_hs = state_buffer_.Get(1);
3143       if (prev_hs && !current) {
3144         float curr_dist_sq = -1;
3145         for (FingerMap::const_iterator it =
3146                  fingers.begin(), e = fingers.end(); it != e; ++it) {
3147           const FingerState* fs = hwstate.GetFingerState(*it);
3148           const FingerState* prev_fs = prev_hs->GetFingerState(fs->tracking_id);
3149           if (!prev_fs)
3150             break;
3151           float dist_sq = DistSq(*fs, *prev_fs);
3152           if (dist_sq > curr_dist_sq) {
3153             current = fs;
3154             curr_dist_sq = dist_sq;
3155           }
3156         }
3157       }
3158       if (!current)
3159         return;
3160 
3161       // Find corresponding finger id in previous state
3162       const FingerState* prev =
3163           state_buffer_.Get(1)->GetFingerState(current->tracking_id);
3164       const FingerState* prev2 = !state_buffer_.Get(2) ? NULL :
3165           state_buffer_.Get(2)->GetFingerState(current->tracking_id);
3166       if (!prev || !current)
3167         return;
3168       if (current->flags & GESTURES_FINGER_MERGE)
3169         return;
3170       stime_t dt = hwstate.timestamp - state_buffer_.Get(1)->timestamp;
3171       bool suppress_finger_movement =
3172           scroll_manager_.SuppressStationaryFingerMovement(
3173               *current, *prev, dt) ||
3174           scroll_manager_.StationaryFingerPressureChangingSignificantly(
3175               state_buffer_, *current);
3176       if (quick_acceleration_factor_.val_ && prev2) {
3177         stime_t dt2 =
3178             state_buffer_.Get(1)->timestamp - state_buffer_.Get(2)->timestamp;
3179         float dist_sq = DistSq(*current, *prev);
3180         float dist_sq2 = DistSq(*prev, *prev2);
3181         if (dist_sq2 * dt &&  // have prev dist and current time
3182             dist_sq2 * dt * dt *
3183             quick_acceleration_factor_.val_ * quick_acceleration_factor_.val_ <
3184             dist_sq * dt2 * dt2) {
3185           return;
3186         }
3187       }
3188       if (suppress_finger_movement) {
3189         scroll_manager_.prev_result_suppress_finger_movement_ = true;
3190         result_ = Gesture(kGestureMove,
3191                           state_buffer_.Get(1)->timestamp,
3192                           hwstate.timestamp,
3193                           0,
3194                           0);
3195         return;
3196       }
3197       scroll_manager_.prev_result_suppress_finger_movement_ = false;
3198       float dx = current->position_x - prev->position_x;
3199       if (current->flags & GESTURES_FINGER_WARP_X_MOVE)
3200         dx = 0.0;
3201       float dy = current->position_y - prev->position_y;
3202       if (current->flags & GESTURES_FINGER_WARP_Y_MOVE)
3203         dy = 0.0;
3204       float dsq = dx * dx + dy * dy;
3205       float dx_total = current->position_x -
3206                        start_positions_[current->tracking_id].x_;
3207       float dy_total = current->position_y -
3208                        start_positions_[current->tracking_id].y_;
3209       float dsq_total = dx_total * dx_total + dy_total * dy_total;
3210 
3211       float dsq_thresh = (move_lock_speed_.val_ * move_lock_speed_.val_) *
3212                          (dt * dt);
3213       if (dsq > dsq_thresh) {
3214         // lock onto this finger
3215         moving_finger_id_ = current->tracking_id;
3216       }
3217 
3218       float dsq_total_thresh =
3219           move_report_distance_.val_ * move_report_distance_.val_;
3220       if (dsq_total >= dsq_total_thresh) {
3221         zero_move = dsq == 0.0;
3222         result_ = Gesture(kGestureMove,
3223                           state_buffer_.Get(1)->timestamp,
3224                           hwstate.timestamp,
3225                           dx,
3226                           dy);
3227       }
3228       break;
3229     }
3230     case kGestureTypeScroll: {
3231       if (!scroll_manager_.FillResultScroll(state_buffer_,
3232                                          prev_active_gs_fingers_,
3233                                          fingers,
3234                                          prev_gesture_type_,
3235                                          prev_result_,
3236                                          &result_,
3237                                          &scroll_buffer_))
3238         return;
3239       break;
3240     }
3241     case kGestureTypeFling: {
3242       scroll_manager_.FillResultFling(state_buffer_, scroll_buffer_, &result_);
3243       break;
3244     }
3245     case kGestureTypeSwipe:
3246     case kGestureTypeFourFingerSwipe: {
3247       if (!three_finger_swipe_enable_.val_)
3248         break;
3249       float sum_delta[] = { 0.0, 0.0 };
3250       bool valid[] = { true, true };
3251       float finger_cnt[] = { 0.0, 0.0 };
3252       float FingerState::*fields[] = { &FingerState::position_x,
3253                                        &FingerState::position_y };
3254       for (FingerMap::const_iterator it =
3255                fingers.begin(), e = fingers.end(); it != e; ++it) {
3256         if (!state_buffer_.Get(1)->GetFingerState(*it)) {
3257           Err("missing prev state?");
3258           continue;
3259         }
3260         // We have this loop in case we want to compute diagonal swipes at
3261         // some point, even if currently we go with just one axis.
3262         for (size_t i = 0; i < arraysize(fields); i++) {
3263           bool correct_axis = (i == 1) == swipe_is_vertical_;
3264           if (!valid[i] || !correct_axis)
3265             continue;
3266           float FingerState::*field = fields[i];
3267           float delta = hwstate.GetFingerState(*it)->*field -
3268               state_buffer_.Get(1)->GetFingerState(*it)->*field;
3269           // The multiply is to see if they have the same sign:
3270           if (sum_delta[i] == 0.0 || sum_delta[i] * delta > 0) {
3271             sum_delta[i] += delta;
3272             finger_cnt[i] += 1.0;
3273           } else {
3274             sum_delta[i] = 0.0;
3275             valid[i] = false;
3276           }
3277         }
3278       }
3279       if (current_gesture_type_ == kGestureTypeSwipe) {
3280         result_ = Gesture(
3281             kGestureSwipe, state_buffer_.Get(1)->timestamp,
3282             hwstate.timestamp,
3283             (!swipe_is_vertical_ && finger_cnt[0]) ?
3284             sum_delta[0] / finger_cnt[0] : 0.0,
3285             (swipe_is_vertical_ && finger_cnt[1]) ?
3286             sum_delta[1] / finger_cnt[1] : 0.0);
3287       } else if (current_gesture_type_ == kGestureTypeFourFingerSwipe) {
3288         result_ = Gesture(
3289             kGestureFourFingerSwipe, state_buffer_.Get(1)->timestamp,
3290             hwstate.timestamp,
3291             (!swipe_is_vertical_ && finger_cnt[0]) ?
3292             sum_delta[0] / finger_cnt[0] : 0.0,
3293             (swipe_is_vertical_ && finger_cnt[1]) ?
3294             sum_delta[1] / finger_cnt[1] : 0.0);
3295       }
3296       break;
3297     }
3298     case kGestureTypeSwipeLift: {
3299       result_ = Gesture(kGestureSwipeLift,
3300                         state_buffer_.Get(1)->timestamp,
3301                         hwstate.timestamp);
3302       break;
3303     }
3304 
3305     case kGestureTypeFourFingerSwipeLift: {
3306       result_ = Gesture(kGestureFourFingerSwipeLift,
3307                         state_buffer_.Get(1)->timestamp,
3308                         hwstate.timestamp);
3309       break;
3310     }
3311     case kGestureTypePinch: {
3312       if (pinch_status_ == GESTURES_ZOOM_START ||
3313           (pinch_status_ == GESTURES_ZOOM_END &&
3314            prev_gesture_type_ == kGestureTypePinch)) {
3315         result_ = Gesture(kGesturePinch, changed_time_, hwstate.timestamp,
3316                           1.0, pinch_status_);
3317         pinch_prev_time_ = hwstate.timestamp;
3318         if (pinch_status_ == GESTURES_ZOOM_END) {
3319           current_gesture_type_ = kGestureTypeNull;
3320           pinch_prev_direction_ = 0;
3321         }
3322       } else if (pinch_status_ == GESTURES_ZOOM_UPDATE) {
3323         float current_dist_sq = TwoSpecificFingerDistanceSq(hwstate, fingers);
3324         if (current_dist_sq < 0) {
3325           current_dist_sq = pinch_prev_distance_sq_;
3326         }
3327 
3328         // Check if pinch scale has changed enough since last update to send a
3329         // new update.  To prevent stationary jitter, we always require the
3330         // scale to change by at least a small amount.  We require more change
3331         // if the pinch has been stationary or changed direction recently.
3332         float jitter_threshold = pinch_res_.val_;
3333         if (hwstate.timestamp - pinch_prev_time_ > pinch_stationary_time_.val_)
3334           jitter_threshold = pinch_stationary_res_.val_;
3335         if ((current_dist_sq - pinch_prev_distance_sq_) *
3336             pinch_prev_direction_ < 0)
3337           jitter_threshold = jitter_threshold > pinch_hysteresis_res_.val_ ?
3338                              jitter_threshold :
3339                              pinch_hysteresis_res_.val_;
3340         bool above_jitter_threshold =
3341             (pinch_prev_distance_sq_ > jitter_threshold * current_dist_sq ||
3342              current_dist_sq > jitter_threshold * pinch_prev_distance_sq_);
3343 
3344         if (above_jitter_threshold) {
3345           result_ = Gesture(kGesturePinch, changed_time_, hwstate.timestamp,
3346                             sqrt(current_dist_sq / pinch_prev_distance_sq_),
3347                             GESTURES_ZOOM_UPDATE);
3348           pinch_prev_direction_ =
3349               current_dist_sq > pinch_prev_distance_sq_ ? 1 : -1;
3350           pinch_prev_distance_sq_ = current_dist_sq;
3351           pinch_prev_time_ = hwstate.timestamp;
3352         }
3353       }
3354       if (pinch_status_ == GESTURES_ZOOM_START) {
3355         pinch_status_ = GESTURES_ZOOM_UPDATE;
3356         // If there is a slow pinch, it may take a little while to detect it,
3357         // allowing the fingers to travel a significant distance, and causing an
3358         // inappropriately large scale in a single frame, followed by slow
3359         // scaling. Here we reduce the initial scale factor depending on how
3360         // quickly we detected the pinch.
3361         float current_dist_sq = TwoSpecificFingerDistanceSq(hwstate, fingers);
3362         float pinch_slowness_ratio = (hwstate.timestamp - changed_time_) *
3363                                      pinch_initial_scale_time_inv_.val_;
3364         pinch_slowness_ratio = fmin(1.0, pinch_slowness_ratio);
3365         pinch_prev_distance_sq_ =
3366             (pinch_slowness_ratio * current_dist_sq) +
3367             ((1 - pinch_slowness_ratio) * pinch_prev_distance_sq_);
3368       }
3369       break;
3370     }
3371     default:
3372       result_.type = kGestureTypeNull;
3373   }
3374   scroll_manager_.UpdateScrollEventBuffer(current_gesture_type_,
3375                                           &scroll_buffer_);
3376   if ((result_.type == kGestureTypeMove && !zero_move) ||
3377       result_.type == kGestureTypeScroll)
3378     last_movement_timestamp_ = hwstate.timestamp;
3379 }
3380 
IntWasWritten(IntProperty * prop)3381 void ImmediateInterpreter::IntWasWritten(IntProperty* prop) {
3382   if (prop == &keyboard_touched_timeval_low_) {
3383     struct timeval tv = {
3384       keyboard_touched_timeval_high_.val_,
3385       keyboard_touched_timeval_low_.val_
3386     };
3387     keyboard_touched_ = StimeFromTimeval(&tv);
3388   }
3389 }
3390 
Initialize(const HardwareProperties * hwprops,Metrics * metrics,MetricsProperties * mprops,GestureConsumer * consumer)3391 void ImmediateInterpreter::Initialize(const HardwareProperties* hwprops,
3392                                       Metrics* metrics,
3393                                       MetricsProperties* mprops,
3394                                       GestureConsumer* consumer) {
3395   Interpreter::Initialize(hwprops, metrics, mprops, consumer);
3396   state_buffer_.Reset(hwprops_->max_finger_cnt);
3397   // Zero finger click needs to be disabled for touchpads that
3398   // integrate their buttons into the pad itself but enabled
3399   // for any other touchpad in case they have separate buttons.
3400   zero_finger_click_enable_.val_ = !hwprops_->is_button_pad;
3401 
3402   is_haptic_pad_ = hwprops_->is_haptic_pad;
3403 }
3404 
AnyGesturingFingerLeft(const HardwareState & state,const FingerMap & prev_gs_fingers)3405 bool AnyGesturingFingerLeft(const HardwareState& state,
3406                             const FingerMap& prev_gs_fingers) {
3407   for (FingerMap::const_iterator it = prev_gs_fingers.begin(),
3408                                  e = prev_gs_fingers.end(); it != e; ++it) {
3409     if (!state.GetFingerState(*it)) {
3410       return true;
3411     }
3412   }
3413   return false;
3414 }
3415 
3416 }  // namespace gestures
3417