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