xref: /aosp_15_r20/external/libchrome-gestures/include/immediate_interpreter.h (revision aed3e5085e770be5b69ce25295ecf6ddf906af95)
1 // Copyright 2012 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <map>
6 #include <set>
7 
8 #include <gtest/gtest.h>  // for FRIEND_TEST
9 
10 #include "include/finger_metrics.h"
11 #include "include/gestures.h"
12 #include "include/interpreter.h"
13 #include "include/macros.h"
14 #include "include/prop_registry.h"
15 #include "include/tracer.h"
16 #include "include/vector.h"
17 
18 #ifndef GESTURES_IMMEDIATE_INTERPRETER_H_
19 #define GESTURES_IMMEDIATE_INTERPRETER_H_
20 
21 namespace gestures {
22 
23 typedef std::set<short> FingerMap;
24 
25 // This interpreter keeps some memory of the past and, for each incoming
26 // frame of hardware state, immediately determines the gestures to the best
27 // of its abilities.
28 
29 class ImmediateInterpreter;
30 class MultitouchMouseInterpreter;
31 
32 class TapRecord {
33   FRIEND_TEST(ImmediateInterpreterTest, TapRecordTest);
34  public:
TapRecord(const ImmediateInterpreter * immediate_interpreter)35   explicit TapRecord(const ImmediateInterpreter* immediate_interpreter)
36       : immediate_interpreter_(immediate_interpreter),
37         t5r2_(false),
38         t5r2_touched_size_(0),
39         t5r2_released_size_(0),
40         fingers_below_max_age_(true) {}
41   void Update(const HardwareState& hwstate,
42               const HardwareState& prev_hwstate,
43               const std::set<short>& added,
44               const std::set<short>& removed,
45               const std::set<short>& dead);
46   void Clear();
47 
48   // if any gesturing fingers are moving
49   bool Moving(const HardwareState& hwstate, const float dist_max) const;
50   bool Motionless(const HardwareState& hwstate,
51                   const HardwareState& prev_hwstate,
52                   const float max_speed) const;
53 
54   bool TapBegan() const;  // if a tap has begun
55   bool TapComplete() const;  // is a completed tap
56   // return GESTURES_BUTTON_* value or 0, if tap was too light
57   int TapType() const;
58   // If any contact has met the minimum pressure threshold
59   bool MinTapPressureMet() const;
60   bool FingersBelowMaxAge() const;
61  private:
62   void NoteTouch(short the_id, const FingerState& fs);  // Adds to touched_
63   void NoteRelease(short the_id);  // Adds to released_
64   void Remove(short the_id);  // Removes from touched_ and released_
65 
66   float CotapMinPressure() const;
67 
68   std::map<short, FingerState> touched_;
69   std::set<short> released_;
70   // At least one finger must meet the minimum pressure requirement during a
71   // tap. This set contains the fingers that have.
72   std::set<short> min_tap_pressure_met_;
73   // All fingers must meet the cotap pressure, which is half of the min tap
74   // pressure.
75   std::set<short> min_cotap_pressure_met_;
76   // Used to fetch properties
77   const ImmediateInterpreter* immediate_interpreter_;
78   // T5R2: For these pads, we try to track individual IDs, but if we get an
79   // input event with insufficient data, we switch into T5R2 mode, where we
80   // just track the number of contacts. We still maintain the non-T5R2 records
81   // which are useful for tracking if contacts move a lot.
82   // The following are for T5R2 mode:
83   bool t5r2_;  // if set, use T5R2 hacks
84   unsigned short t5r2_touched_size_;  // number of contacts that have arrived
85   unsigned short t5r2_released_size_;  // number of contacts that have left
86   // Whether all the fingers have age less than "Tap Maximum Finger Age".
87   bool fingers_below_max_age_;
88 };
89 
90 struct ScrollEvent {
91   float dx, dy, dt;
92   static ScrollEvent Add(const ScrollEvent& evt_a, const ScrollEvent& evt_b);
93 };
94 class ScrollEventBuffer {
95  public:
ScrollEventBuffer(size_t size)96   explicit ScrollEventBuffer(size_t size)
97       : buf_(new ScrollEvent[size]), max_size_(size), size_(0), head_(0) {}
98   void Insert(float dx, float dy, stime_t timestamp, stime_t prev_timestamp);
99   void Clear();
Size()100   size_t Size() const { return size_; }
101   // 0 is newest, 1 is next newest, ..., size_ - 1 is oldest.
102   const ScrollEvent& Get(size_t offset) const;
103   // For efficiency, returns dist_sq and time of the last num_events events in
104   // the buffer, from which speed can be computed.
105   void GetSpeedSq(size_t num_events, float* dist_sq, float* dt) const;
106 
107  private:
108   std::unique_ptr<ScrollEvent[]> buf_;
109   size_t max_size_;
110   size_t size_;
111   size_t head_;
112   stime_t last_scroll_timestamp_;
113   DISALLOW_COPY_AND_ASSIGN(ScrollEventBuffer);
114 };
115 
116 // Circular buffer for storing a rolling backlog of events for analysis
117 // as well as accessor functions for using the buffer's contents.
118 class HardwareStateBuffer {
119  public:
120   explicit HardwareStateBuffer(size_t size);
121   ~HardwareStateBuffer();
122 
Size()123   size_t Size() const { return size_; }
124 
125   void Reset(size_t max_finger_cnt);
126 
127   // Does a deep copy of state into states_
128   void PushState(const HardwareState& state);
129   // Pops most recently pushed state
130   void PopState();
131 
Get(size_t idx)132   const HardwareState& Get(size_t idx) const {
133     return states_[(idx + newest_index_) % size_];
134   }
135 
Get(size_t idx)136   HardwareState& Get(size_t idx) {
137     return const_cast<HardwareState&>(
138         const_cast<const HardwareStateBuffer*>(this)->Get(idx));
139   }
140 
141  private:
142   std::unique_ptr<HardwareState[]> states_;
143   size_t newest_index_;
144   size_t size_;
145   size_t max_finger_cnt_;
146   DISALLOW_COPY_AND_ASSIGN(HardwareStateBuffer);
147 };
148 
149 struct Point {
PointPoint150   Point() : x_(0.0), y_(0.0) {}
PointPoint151   Point(float x, float y) : x_(x), y_(y) {}
152   bool operator==(const Point& that) const {
153     return x_ == that.x_ && y_ == that.y_;
154   }
155   bool operator!=(const Point& that) const { return !((*this) == that); }
156   float x_, y_;
157 };
158 
159 // Helper class for compute scroll and fling.
160 class ScrollManager {
161   FRIEND_TEST(ImmediateInterpreterTest, FlingDepthTest);
162   FRIEND_TEST(ImmediateInterpreterTest, ScrollManagerTest);
163   FRIEND_TEST(MultitouchMouseInterpreterTest, SimpleTest);
164 
165  public:
166   explicit ScrollManager(PropRegistry* prop_reg);
~ScrollManager()167   ~ScrollManager() {}
168 
169   // Returns true if a finger's movement should be suppressed based on
170   // max_stationary_move_* properties below.
171   bool SuppressStationaryFingerMovement(const FingerState& fs,
172                                         const FingerState& prev,
173                                         stime_t dt);
174 
175   // Looking at this finger and the previous ones within a small window
176   // and returns true iff this finger is stationary and the pressure is
177   // changing so quickly that we expect it's arriving on the pad or
178   // departing.
179   bool StationaryFingerPressureChangingSignificantly(
180       const HardwareStateBuffer& state_buffer,
181       const FingerState& current) const;
182 
183   // Compute a scroll and fill result.  Return false when something goes wrong.
184   bool FillResultScroll(const HardwareStateBuffer& state_buffer,
185                      const FingerMap& prev_gs_fingers,
186                      const FingerMap& gs_fingers,
187                      GestureType prev_gesture_type,
188                      const Gesture& prev_result,
189                      Gesture* result,
190                      ScrollEventBuffer* scroll_buffer);
191 
192   // Compute a fling and fill result.
193   void FillResultFling(const HardwareStateBuffer& state_buffer,
194                     const ScrollEventBuffer& scroll_buffer,
195                     Gesture* result);
196 
197   // Update ScrollEventBuffer when the current gesture type is not scroll.
198   void UpdateScrollEventBuffer(GestureType gesture_type,
199                                ScrollEventBuffer* scroll_buffer) const;
200 
ResetSameFingerState()201   void ResetSameFingerState() {
202     stationary_start_positions_.clear();
203   }
204 
205   // Set to true when a scroll or move is blocked b/c of high pressure
206   // change or small movement. Cleared when a normal scroll or move
207   // goes through.
208   bool prev_result_suppress_finger_movement_;
209 
210  private:
211   // Set to true when generating a non-zero scroll gesture. Reset to false
212   // when a fling is generated.
213   bool did_generate_scroll_;
214 
215   // Returns the number of most recent event events in the scroll_buffer_ that
216   // should be considered for fling. If it returns 0, there should be no fling.
217   size_t ScrollEventsForFlingCount(const ScrollEventBuffer& scroll_buffer)
218     const;
219 
220   // Returns a ScrollEvent that contains velocity estimates for x and y based
221   // on an N-point linear regression.
222   void RegressScrollVelocity(const ScrollEventBuffer& scroll_buffer,
223                              int count, ScrollEvent* out) const;
224 
225   std::map<short, Point> stationary_start_positions_;
226 
227   // In addition to checking for large pressure changes when moving
228   // slow, we can suppress all motion under a certain speed, unless
229   // the total distance exceeds a threshold.
230   DoubleProperty max_stationary_move_speed_;
231   DoubleProperty max_stationary_move_speed_hysteresis_;
232   DoubleProperty max_stationary_move_suppress_distance_;
233 
234   // A finger must change in pressure by less than this per second to trigger
235   // motion.
236   DoubleProperty max_pressure_change_;
237   // If a contact crosses max_pressure_change_, motion continues to be blocked
238   // until the pressure change per second goes below
239   // max_pressure_change_hysteresis_.
240   DoubleProperty max_pressure_change_hysteresis_;
241   // Try to look over a period up to this length of time when looking for large
242   // pressure change.
243   DoubleProperty max_pressure_change_duration_;
244   // A fast-swiping finger may generate rapidly changing pressure and we should
245   // not report a high pressure change in this case.  This is the maximum
246   // speed [mm/s] for which we may consider a finger stationary.
247   DoubleProperty max_stationary_speed_;
248 
249   // y| V  /
250   //  |   /  D   _-
251   //  |  /    _-'
252   //  | /  _-'
253   //  |/_-'   H
254   //  |'____________x
255   // The above quadrant of a cartesian plane shows the angles where we snap
256   // scrolling to vertical or horizontal. Very Vertical or Horizontal scrolls
257   // are snapped, while Diagonal scrolls are not. The two properties below
258   // are the slopes for the two lines.
259   DoubleProperty vertical_scroll_snap_slope_;
260   DoubleProperty horizontal_scroll_snap_slope_;
261 
262   // Depth of recent scroll event buffer used to compute Fling velocity.
263   // For most systems this will be 3.  However, for systems that use 2x
264   // interpolation, this should be 6, to ensure that the scroll events for 3
265   // actual hardware states are used.
266   IntProperty fling_buffer_depth_;
267   // Some platforms report fingers as perfectly stationary for a few frames
268   // before they report lift off. We don't include these non-movement
269   // frames in the scroll buffer, because that would suppress fling.
270   // Platforms with this property should set
271   // fling_buffer_suppress_zero_length_scrolls_ to non-zero.
272   BoolProperty fling_buffer_suppress_zero_length_scrolls_;
273   // When computing a fling, if the fling buffer has an average speed under
274   // this threshold, we do not perform a fling. Units are mm/sec.
275   DoubleProperty fling_buffer_min_avg_speed_;
276 };
277 
278 // Helper class for computing the button type of multi-finger clicks.
279 class FingerButtonClick {
280  public:
281   // Describes the three classes of fingers we deal with while determining
282   // the type of physical button clicks.
283   enum FingerClickStatus {
284     // A 'recent' finger has recently touched down on the touchpad.
285     STATUS_RECENT,
286     // A 'cold' finger has already been on the touchpad for a while,
287     // but has not been moved.
288     STATUS_COLD,
289     // A 'hot' finger has been moved since it touched down.
290     STATUS_HOT
291   };
292 
293   explicit FingerButtonClick(const ImmediateInterpreter* interpreter);
~FingerButtonClick()294   ~FingerButtonClick() {};
295 
296   // Processes the HardwareState finger data. Categorizes fingers into one of
297   // the FingerClickStatus and sort them according to their original timestamps.
298   // Returns true if further analysis is needed. Returns false in trivial cases
299   // where one is safe to use the HardwareState button data directly.
300   bool Update(const HardwareState& hwstate, stime_t button_down_time);
301 
302   // Returns which button type corresponds to which touch count (e.g. 2f = right
303   // click, 3f = middle click).
304   int GetButtonTypeForTouchCount(int touch_count) const;
305 
306   // All these following button type evaluation functions are guaranteed to
307   // return a button but the caller must ensure that the requirements are met.
308   //
309   // Evaluates the button type for the 2f case. Needs at least 2 fingers.
310   int EvaluateTwoFingerButtonType();
311 
312   // Evaluates the button type for >=3f cases. Needs at least 3 fingers.
313   int EvaluateThreeOrMoreFingerButtonType();
314 
315   // Evaluates the button type using finger locations.
316   int EvaluateButtonTypeUsingFigureLocation();
317 
num_fingers()318   int num_fingers() const { return num_fingers_; }
num_recent()319   int num_recent() const { return num_recent_; }
num_cold()320   int num_cold() const { return num_cold_; }
num_hot()321   int num_hot() const { return num_hot_; }
322 
323  private:
324   // Used to fetch properties and other finger status.
325   const ImmediateInterpreter* interpreter_;
326 
327   // Fingers that we are considering for determining the button type.
328   FingerState const * fingers_[4];
329 
330   // FingerClickStatus of each finger.
331   FingerClickStatus fingers_status_[4];
332 
333   // Number of fingers we are considering.
334   int num_fingers_;
335 
336   // Number of fingers of each kind.
337   int num_recent_;
338   int num_cold_;
339   int num_hot_;
340 };
341 
342 class ImmediateInterpreter : public Interpreter, public PropertyDelegate {
343   FRIEND_TEST(ImmediateInterpreterTest, AmbiguousPalmCoScrollTest);
344   FRIEND_TEST(ImmediateInterpreterTest, AvoidAccidentalPinchTest);
345   FRIEND_TEST(ImmediateInterpreterTest, ChangeTimeoutTest);
346   FRIEND_TEST(ImmediateInterpreterTest, ClickTest);
347   FRIEND_TEST(ImmediateInterpreterTest, FlingDepthTest);
348   FRIEND_TEST(ImmediateInterpreterTest, GetGesturingFingersTest);
349   FRIEND_TEST(ImmediateInterpreterTest, GetGesturingFingersWithEmptyStateTest);
350   FRIEND_TEST(ImmediateInterpreterTest, PalmAtEdgeTest);
351   FRIEND_TEST(ImmediateInterpreterTest, PalmReevaluateTest);
352   FRIEND_TEST(ImmediateInterpreterTest, PalmTest);
353   FRIEND_TEST(ImmediateInterpreterTest, PinchTests);
354   FRIEND_TEST(ImmediateInterpreterTest, ScrollResetTapTest);
355   FRIEND_TEST(ImmediateInterpreterTest, ScrollThenFalseTapTest);
356   FRIEND_TEST(ImmediateInterpreterTest, SemiMtActiveAreaTest);
357   FRIEND_TEST(ImmediateInterpreterTest, SemiMtNoPinchTest);
358   FRIEND_TEST(ImmediateInterpreterTest, StationaryPalmTest);
359   FRIEND_TEST(ImmediateInterpreterTest, SwipeTest);
360   FRIEND_TEST(ImmediateInterpreterTest, TapRecordTest);
361   FRIEND_TEST(ImmediateInterpreterTest, TapToClickKeyboardTest);
362   FRIEND_TEST(ImmediateInterpreterTest, TapToClickLowPressureBeginOrEndTest);
363   FRIEND_TEST(ImmediateInterpreterTest, ThumbRetainReevaluateTest);
364   FRIEND_TEST(ImmediateInterpreterTest, ThumbRetainTest);
365   FRIEND_TEST(ImmediateInterpreterTest, WarpedFingersTappingTest);
366   FRIEND_TEST(ImmediateInterpreterTest, ZeroClickInitializationTest);
367   FRIEND_TEST(ImmediateInterpreterTtcEnableTest, TapToClickEnableTest);
368   friend class TapRecord;
369   friend class TapToClickStateMachineTest;
370   friend class FingerButtonClick;
371 
372  public:
373   enum TapToClickState {
374     kTtcIdle,
375     kTtcFirstTapBegan,
376     kTtcTapComplete,
377     kTtcSubsequentTapBegan,
378     kTtcDrag,
379     kTtcDragRelease,
380     kTtcDragRetouch
381   };
382 
383   ImmediateInterpreter(PropRegistry* prop_reg, Tracer* tracer);
~ImmediateInterpreter()384   virtual ~ImmediateInterpreter() {}
385 
386  protected:
387   virtual void SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout);
388 
389   virtual void HandleTimerImpl(stime_t now, stime_t* timeout);
390 
391   virtual void Initialize(const HardwareProperties* hwprops,
392                           Metrics* metrics, MetricsProperties* mprops,
393                           GestureConsumer* consumer);
394 
395  public:
tap_to_click_state()396   TapToClickState tap_to_click_state() const { return tap_to_click_state_; }
397 
tap_min_pressure()398   float tap_min_pressure() const { return tap_min_pressure_.val_; }
399 
tap_max_finger_age()400   stime_t tap_max_finger_age() const { return tap_max_finger_age_.val_; }
401 
device_reports_pressure()402   bool device_reports_pressure() const { return hwprops_->reports_pressure; }
403 
finger_origin_timestamp(short tracking_id)404   stime_t finger_origin_timestamp(short tracking_id) const {
405     return metrics_->GetFinger(tracking_id)->origin_time();
406   }
407 
408  private:
409   // Reset the member variables corresponding to same-finger state and
410   // updates changed_time_ to |now|.
411   void ResetSameFingersState(const HardwareState& hwstate);
412 
413   // Reset the member variables which track old timestamps.  Called when the
414   // clock changes backward.
415   void ResetTime();
416 
417   // Sets pointing_.
418   void UpdatePointingFingers(const HardwareState& hwstate);
419 
420   // Gets the hardware button type (RIGHT, LEFT) based on the
421   // first finger's position.
422   int GetButtonTypeFromPosition(const HardwareState& hwstate);
423 
424   // Returns the square of the distance that this contact has travelled since
425   // fingers changed (origin=false) or since they touched down (origin=true).
426   // If permit_warp is true, we ignore the GESTURES_FINGER_WARP_X/Y flags
427   // unless the more strict GESTURES_FINGER_WARP_TELEPORTATION flag is set.
428   float DistanceTravelledSq(const FingerState& fs,
429                             bool origin,
430                             bool permit_warp = false) const;
431 
432   // Returns the vector that this finger has travelled since
433   // fingers changed (origin=false) or since they touched down (origin=true).
434   // If permit_warp is true, we ignore the GESTURES_FINGER_WARP_X/Y flags
435   // unless the more strict GESTURES_FINGER_WARP_TELEPORTATION flag is set.
436   Point FingerTraveledVector(const FingerState& fs,
437                              bool origin,
438                              bool permit_warp = false) const;
439 
440   // Returns true if there is a potential for pinch zoom but still it's too
441   // early to decide. In this case, there shouldn't be any move or scroll
442   // event.
443   bool EarlyZoomPotential(const HardwareState& hwstate) const;
444 
445   // Returns true if there are two fingers moving in opposite directions.
446   // Moreover, this function makes sure that fingers moving direction hasn't
447   // changed recently.
448   bool ZoomFingersAreConsistent(const HardwareStateBuffer& state_buffer) const;
449 
450   // Returns true if the given finger is moving sufficiently upwards to be
451   // considered the bottom finger of an inward pinch.
452   bool InwardPinch(const HardwareStateBuffer& state_buffer,
453                    const FingerState& fs) const;
454 
455   // Returns Cos(A) where A is the angle between the move vector of two fingers
456   float FingersAngle(const FingerState* before1, const FingerState* before2,
457                      const FingerState* curr1, const FingerState* curr2) const;
458 
459   // Returns true if fingers are not moving in opposite directions.
460   bool ScrollAngle(const FingerState& finger1, const FingerState& finger2);
461 
462   // Returns the square of distance between two fingers.
463   // Returns -1 if not exactly two fingers are present.
464   float TwoFingerDistanceSq(const HardwareState& hwstate) const;
465 
466   // Returns the square of distance between two given fingers.
467   // Returns -1 if fingers don't present in the hwstate.
468   float TwoSpecificFingerDistanceSq(const HardwareState& hwstate,
469                                     const FingerMap& fingers) const;
470 
471   // Updates thumb_ below.
472   void UpdateThumbState(const HardwareState& hwstate);
473 
474   // Returns true iff the keyboard has been recently used.
475   bool KeyboardRecentlyUsed(stime_t now) const;
476 
477   // Updates non_gs_fingers based on a new hardware state. Removes missing and
478   // newly moving fingers from non_gs_fingers.
479   void UpdateNonGsFingers(const HardwareState& hwstate);
480 
481   // Gets the finger or fingers we should consider for gestures.
482   // Currently, it fetches the (up to) two fingers closest to the keyboard
483   // that are not palms. There is one exception: for t5r2 pads with > 2
484   // fingers present, we return all fingers.
485   FingerMap GetGesturingFingers(const HardwareState& hwstate) const;
486 
487   // Updates current_gesture_type_ based on passed-in hwstate and
488   // considering the passed in fingers as gesturing.
489   // Returns the finger(s) that are performing the gesture in
490   // active_gs_fingers.
491   void UpdateCurrentGestureType(const HardwareState& hwstate,
492                                 const FingerMap& gs_fingers,
493                                 FingerMap* active_gs_fingers);
494 
495   // Checks if gesture_type is one of kGestureTypeScroll, kGestureTypeSwipe, or
496   // kGestureTypeFourFingerSwipe
497   bool IsScrollOrSwipe(const GestureType gesture_type);
498 
499   // Checks if a scroll or swipe has ended, and replaces current_gesture_type_
500   // with the appropriate finger lift gesture.
501   void GenerateFingerLiftGesture();
502 
503   // Sorts the fingers referred to in finger_ids (whose details are in hwstate)
504   // according to prodimity and places the sorted range into out_sorted_ids.
505   // The sort first finds the two closes points and includes them first.
506   // Then, it finds the point closest to any included point, repeating until
507   // all points are included.
508   static void SortFingersByProximity(
509       const FingerMap& finger_ids,
510       const HardwareState& hwstate,
511       vector<short, kMaxGesturingFingers>* out_sorted_ids);
512 
513   // If the finger is likely to be a palm and that its contact size/pressure
514   // is diminishing/increasing, we suppress the cursor movement. A real
515   // intentional 1f cursor move near the touchpad boundary usually has a
516   // stationary finger contact size/pressure.
517   bool PalmIsArrivingOrDeparting(const FingerState& finger) const;
518 
519   // Check if a finger is close to any known thumb. Can be used to detect some
520   // thumb split cases.
521   bool IsTooCloseToThumb(const FingerState& finger) const;
522 
523   // If the fingers are near each other in location and pressure and might
524   // to be part of a 2-finger action, returns true. The function can also
525   // be used to check whether the gesture is a left or a right button click
526   // with the parameter checking_button_type.
527   bool TwoFingersGesturing(const FingerState& finger1,
528                            const FingerState& finger2,
529                            bool check_button_type) const;
530 
531   // Given that TwoFingersGesturing returns true for 2 fingers,
532   // This will further look to see if it's really 2 finger scroll or not.
533   // Returns the current state (move or scroll) or kGestureTypeNull if
534   // unknown.
535   GestureType GetTwoFingerGestureType(const FingerState& finger1,
536                                       const FingerState& finger2);
537 
538   // Check for a pinch gesture and update the state machine for detection.
539   // If a pinch was detected it will return true. False otherwise.
540   // To reset the state machine call with reset=true
541   bool UpdatePinchState(const HardwareState& hwstate, bool reset,
542                         const FingerMap& gs_fingers);
543 
544   // Returns a gesture assuming that at least one of the fingers performing
545   // current_gesture_type has left
546   GestureType GetFingerLiftGesture(GestureType current_gesture_type);
547 
548   // Returns the current multi-finger gesture, or kGestureTypeNull if no gesture
549   // should be produced. num_fingers can be 3 or 4.
550   GestureType GetMultiFingerGestureType(const FingerState* const fingers[],
551                                         const int num_fingers);
552 
553   const char* TapToClickStateName(TapToClickState state);
554 
555   stime_t TimeoutForTtcState(TapToClickState state);
556 
557   void SetTapToClickState(TapToClickState state,
558                           stime_t now);
559 
560   void UpdateTapGesture(const HardwareState* hwstate,
561                         const FingerMap& gs_fingers,
562                         const bool same_fingers,
563                         stime_t now,
564                         stime_t* timeout);
565 
566   void UpdateTapState(const HardwareState* hwstate,
567                       const FingerMap& gs_fingers,
568                       const bool same_fingers,
569                       stime_t now,
570                       unsigned* buttons_down,
571                       unsigned* buttons_up,
572                       stime_t* timeout);
573 
574   // Returns true iff the given finger is too close to any other finger to
575   // realistically be doing a tap gesture.
576   bool FingerTooCloseToTap(const HardwareState& hwstate, const FingerState& fs);
577 
578   // Returns true iff finger is in the bottom, dampened zone of the pad
579   bool FingerInDampenedZone(const FingerState& finger) const;
580 
581   // Called when fingers have changed to fill start_positions_
582   // and origin_positions_.
583   void FillStartPositions(const HardwareState& hwstate);
584 
585   // Fills the origin_* member variables.
586   void FillOriginInfo(const HardwareState& hwstate);
587 
588   // Fills moving_ with any moving fingers.
589   FingerMap UpdateMovingFingers(const HardwareState& hwstate);
590 
591   // Update started_moving_time_ to now if any gesturing fingers started moving.
592   void UpdateStartedMovingTime(stime_t now,
593                                const FingerMap& gs_fingers,
594                                const FingerMap& newly_moving_fingers);
595 
596   // Updates the internal button state based on the passed in |hwstate|.
597   // Can optionally request a timeout by setting *timeout.
598   void UpdateButtons(const HardwareState& hwstate, stime_t* timeout);
599 
600   // Called when the timeout is fired for UpdateButtons.
601   void UpdateButtonsTimeout(stime_t now);
602 
603   // By looking at |hwstate| and internal state, determins if a button down
604   // at this time would correspond to a left/middle/right click. Returns
605   // GESTURES_BUTTON_{LEFT,MIDDLE,RIGHT}.
606   int EvaluateButtonType(const HardwareState& hwstate,
607                          stime_t button_down_time);
608 
609   // Precondition: current_mode_ is set to the mode based on |hwstate|.
610   // Computes the resulting gesture, storing it in result_.
611   void FillResultGesture(const HardwareState& hwstate,
612                          const FingerMap& fingers);
613 
614   virtual void IntWasWritten(IntProperty* prop);
615 
616   // Fingers which are prohibited from ever tapping.
617   std::set<short> tap_dead_fingers_;
618 
619   // Active gs fingers are the subset of gs_fingers that are actually performing
620   // a gesture
621   FingerMap prev_active_gs_fingers_;
622 
623   // Fingers that would be considered as possibly gesturing, but others fingers
624   // did the gesturing.
625   FingerMap non_gs_fingers_;
626 
627   FingerMap prev_gs_fingers_;
628   FingerMap prev_tap_gs_fingers_;
629   HardwareProperties hw_props_;
630   Gesture result_;
631   Gesture prev_result_;
632 
633   // Total distance travelled by a finger since its origin timestamp.
634   std::map<short, float> distance_walked_;
635 
636   // Button data
637   // Which button we are going to send/have sent for the physical btn press
638   int button_type_;  // left, middle, or right
639 
640   FingerButtonClick finger_button_click_;
641 
642   // If we have sent button down for the currently down button
643   bool sent_button_down_;
644 
645   // If we haven't sent a button down by this time, send one
646   stime_t button_down_deadline_;
647 
648   // When fingers change, we record the time
649   stime_t changed_time_;
650 
651   // When gesturing fingers move after change, we record the time.
652   stime_t started_moving_time_;
653   // Record which fingers have started moving already.
654   std::set<short> moving_;
655 
656   // When different fingers are gesturing, we record the time
657   stime_t gs_changed_time_;
658 
659   // When fingers leave, we record the time
660   stime_t finger_leave_time_;
661 
662   // When fingers change, we keep track of where they started.
663   // Map: Finger ID -> (x, y) coordinate
664   std::map<short, Point> start_positions_;
665 
666   // Keep track of finger position from when three fingers began moving in the
667   // same direction.
668   // Map: Finger ID -> (x, y) coordinate
669   std::map<short, Point> three_finger_swipe_start_positions_;
670 
671   // Keep track of finger position from when four fingers began moving in the
672   // same direction.
673   // Map: Finger ID -> (x, y) coordinate
674   std::map<short, Point> four_finger_swipe_start_positions_;
675 
676   // We keep track of where each finger started when they touched.
677   // Map: Finger ID -> (x, y) coordinate.
678   std::map<short, Point> origin_positions_;
679 
680   // tracking ids of known fingers that are not palms, nor thumbs.
681   std::set<short> pointing_;
682   // tracking ids of known non-palms. But might be thumbs.
683   std::set<short> fingers_;
684   // contacts believed to be thumbs, and when they were inserted into the map
685   std::map<short, stime_t> thumb_;
686   // Timer of the evaluation period for contacts believed to be thumbs.
687   std::map<short, stime_t> thumb_eval_timer_;
688 
689   // once a moving finger is determined lock onto this one for cursor movement.
690   short moving_finger_id_;
691 
692   // Tap-to-click
693   // The current state:
694   TapToClickState tap_to_click_state_;
695 
696   // When we entered the state:
697   stime_t tap_to_click_state_entered_;
698 
699   TapRecord tap_record_;
700 
701   // Record time when the finger showed motion (uses different motion detection
702   // than last_movement_timestamp_)
703   stime_t tap_drag_last_motion_time_;
704 
705   // True when the finger was stationary for a while during tap to drag
706   bool tap_drag_finger_was_stationary_;
707 
708   // Time when the last motion (scroll, movement) occurred
709   stime_t last_movement_timestamp_;
710 
711   bool swipe_is_vertical_;
712 
713   // If we are currently pointing, scrolling, etc.
714   GestureType current_gesture_type_;
715   // Previous value of current_gesture_type_
716   GestureType prev_gesture_type_;
717 
718   // Cache for distance between fingers at previous pinch gesture event, or
719   // start of pinch detection
720   float pinch_prev_distance_sq_;
721 
722   HardwareStateBuffer state_buffer_;
723   ScrollEventBuffer scroll_buffer_;
724 
725   FingerMetrics* finger_metrics_;
726   std::unique_ptr<FingerMetrics> test_finger_metrics_;
727 
728   // There are three pinch guess states before locking:
729   //   pinch_guess_start_ == -1: No definite guess made about pinch
730   //   pinch_guess_start_ > 0:
731   //     pinch_guess_ == true:  Guess there is a pinch
732   //     pinch_guess_ == false: Guess there is no pinch
733 
734   // When guessing a pinch gesture. Do we guess pinch (true) or no-pinch?
735   bool pinch_guess_;
736   // Time when pinch guess was made. -1 if no guess has been made yet.
737   stime_t pinch_guess_start_;
738   // True when the pinch decision has been locked.
739   bool pinch_locked_;
740   // Pinch status: GESTURES_ZOOM_START, _UPDATE, or _END
741   unsigned pinch_status_;
742   // Direction of previous pinch update:
743   //   0: No previous update
744   //   1: Outward
745   //  -1: Inward
746   int pinch_prev_direction_;
747   // Timestamp of previous pinch update
748   float pinch_prev_time_;
749 
750   // Keeps track of if there was a finger seen during a physical click
751   bool finger_seen_shortly_after_button_down_;
752 
753   bool is_haptic_pad_;
754 
755   // See keyboard_touched_* properties
756   stime_t keyboard_touched_;
757 
758   ScrollManager scroll_manager_;
759 
760   // Properties
761 
762   // Is Tap-To-Click enabled
763   BoolProperty tap_enable_;
764   // Allows Tap-To-Click to be paused
765   BoolProperty tap_paused_;
766   // General time limit [s] for tap gestures
767   DoubleProperty tap_timeout_;
768   // General time limit [s] for time between taps.
769   DoubleProperty inter_tap_timeout_;
770   // Time [s] before a tap gets recognized as a drag.
771   DoubleProperty tap_drag_delay_;
772   // Time [s] it takes to stop dragging when you let go of the touchpad
773   DoubleProperty tap_drag_timeout_;
774   // True if tap dragging is enabled. With it disbled we can respond quickly
775   // to tap clicks.
776   BoolProperty tap_drag_enable_;
777   // True if drag lock is enabled
778   BoolProperty drag_lock_enable_;
779   // Time [s] the finger has to be stationary to be considered dragging
780   DoubleProperty tap_drag_stationary_time_;
781   // Distance [mm] a finger can move and still register a tap
782   DoubleProperty tap_move_dist_;
783   // Minimum pressure a finger must have for it to click when tap to click is on
784   DoubleProperty tap_min_pressure_;
785   // Maximum distance [mm] per frame that a finger can move and still be
786   // considered stationary.
787   DoubleProperty tap_max_movement_;
788   // Maximum finger age for a finger to trigger tap.
789   DoubleProperty tap_max_finger_age_;
790   // If three finger click should be enabled. This is a temporary flag so that
791   // we can deploy this feature behind a file while we work out the bugs.
792   BoolProperty three_finger_click_enable_;
793   // If zero finger click should be enabled. On some platforms, bending the
794   // case may accidentally cause a physical click.  This supresses all clicks
795   // that do not have at least 1 finger detected on the touchpad.
796   BoolProperty zero_finger_click_enable_;
797   // If T5R2 should support three-finger click/tap, which can in some situations
798   // be unreliable.
799   BoolProperty t5r2_three_finger_click_enable_;
800   // Distance [mm] a finger must move after fingers change to count as real
801   // motion
802   DoubleProperty change_move_distance_;
803   // Speed [mm/s] a finger must move to lock on to that finger
804   DoubleProperty move_lock_speed_;
805   // Speed [mm/s] a finger must move to lock on to that finger, when another
806   // finger is already locked.
807   DoubleProperty move_change_lock_speed_;
808   // How much faster a finger must move than the currently locked finger to
809   // switch the lock.
810   DoubleProperty move_change_lock_ratio_;
811   // Distance [mm] a finger must move to report that movement
812   DoubleProperty move_report_distance_;
813   // Time [s] to block movement after number or identify of fingers change
814   DoubleProperty change_timeout_;
815   // Time [s] to wait before locking on to a gesture
816   DoubleProperty evaluation_timeout_;
817   // Time [s] to wait before deciding if the pinch zoom is happening.
818   DoubleProperty pinch_evaluation_timeout_;
819   // Time [s] to wait before decide if a thumb is doing a pinch
820   DoubleProperty thumb_pinch_evaluation_timeout_;
821   // Minimum movement that a thumb should have to be a gesturing finger.
822   DoubleProperty thumb_pinch_min_movement_;
823   // If the ratio of gesturing fingers movement to thumb movement is greater
824   // than this number, then we can't have pinch with thumb.
825   DoubleProperty thumb_pinch_movement_ratio_;
826   // Ratio of Distance_sq * Time * Time for two fingers. This measure is used
827   // to compare the slow movement of two fingers.
828   DoubleProperty thumb_slow_pinch_similarity_ratio_;
829   // If a thumb arrives at the same time as the other fingers, the
830   // thumb_pinch_evaluation_timeout_ is multiplied by this factor
831   DoubleProperty thumb_pinch_delay_factor_;
832   // Minimum movement that fingers must have before we consider their
833   // relative direction. If the movement is smaller than this number, it
834   // will considered as noise.
835   DoubleProperty minimum_movement_direction_detection_;
836   // A finger in the damp zone must move at least this much as much as
837   // the other finger to count toward a gesture. Should be between 0 and 1.
838   DoubleProperty damp_scroll_min_movement_factor_;
839   // If two fingers have a pressure difference greater than diff thresh and
840   // the larger is more than diff factor times the smaller, we assume the
841   // larger is a thumb.
842   DoubleProperty two_finger_pressure_diff_thresh_;
843   DoubleProperty two_finger_pressure_diff_factor_;
844   // Click-and-drags are sometimes wrongly classified as right-clicks if the
845   // physical-clicking finger arrives at the pad later than or at roughly the
846   // same time of the other finger. To distinguish between the two cases, we
847   // use the pressure difference and the fingers' relative positions.
848   DoubleProperty click_drag_pressure_diff_thresh_;
849   DoubleProperty click_drag_pressure_diff_factor_;
850   // Mininum slope of the line connecting two fingers that can qualify a click-
851   // and-drag gesture.
852   DoubleProperty click_drag_min_slope_;
853   // If a large contact moves more than this much times the lowest-pressure
854   // contact, consider it not to be a thumb.
855   DoubleProperty thumb_movement_factor_;
856   // If a large contact moves faster than this much times the lowest-pressure
857   // contact, consider it not to be a thumb.
858   DoubleProperty thumb_speed_factor_;
859   // This much time after fingers change, stop allowing contacts classified
860   // as thumb to be classified as non-thumb.
861   DoubleProperty thumb_eval_timeout_;
862   // If thumb is doing an inward pinch, the thresholds for distance and speed
863   // that thumb needs to move to be a gesturing finger are multiplied by this
864   // factor
865   DoubleProperty thumb_pinch_threshold_ratio_;
866   // If a finger is recognized as thumb, it has only this much time to change
867   // its status and perform a click
868   DoubleProperty thumb_click_prevention_timeout_;
869   // Consider scroll vs pointing if finger moves at least this distance [mm]
870   DoubleProperty two_finger_scroll_distance_thresh_;
871   // Consider move if there is no scroll and one finger moves at least this
872   // distance [mm]
873   DoubleProperty two_finger_move_distance_thresh_;
874   // Minimum distance [mm] one of the three fingers must move to perform a
875   // swipe gesture.
876   DoubleProperty three_finger_swipe_distance_thresh_;
877   // Minimum distance [mm] one of the four fingers must move to perform a
878   // four finger swipe gesture.
879   DoubleProperty four_finger_swipe_distance_thresh_;
880   // Minimum ratio between least and most moving finger to perform a
881   // three finger swipe gesture.
882   DoubleProperty three_finger_swipe_distance_ratio_;
883   // Minimum ratio between least and most moving finger to perform a
884   // four finger swipe gesture.
885   DoubleProperty four_finger_swipe_distance_ratio_;
886   // If three-finger swipe should be enabled
887   BoolProperty three_finger_swipe_enable_;
888   // Height [mm] of the bottom zone
889   DoubleProperty bottom_zone_size_;
890   // Time [s] to after button down to evaluate number of fingers for a click
891   DoubleProperty button_evaluation_timeout_;
892   // Time [s] to evaluate number of fingers for a click after a new touch has
893   // been registered
894   DoubleProperty button_finger_timeout_;
895   // Distance [mm] a finger can move to still be considered for a button click
896   DoubleProperty button_move_dist_;
897   // Distance [mm] a finger can be away from it's expected location to be
898   // considered part of the same finger group
899   DoubleProperty button_max_dist_from_expected_;
900   // Flag to enable the right click on the right side of the hardware button
901   BoolProperty button_right_click_zone_enable_;
902   // The size of the right click zone on the right side of the hardware button
903   DoubleProperty button_right_click_zone_size_;
904   // Timeval of time when keyboard was last touched. After the low one is set,
905   // the two are converted into an stime_t and stored in keyboard_touched_.
906   IntProperty keyboard_touched_timeval_high_;  // seconds
907   IntProperty keyboard_touched_timeval_low_;  // microseconds
908   // During this timeout, which is time [s] since the keyboard has been used,
909   // we are extra aggressive in palm detection. If this time is > 10s apart
910   // from now (either before or after), it's disregarded. We disregard old
911   // values b/c they no longer apply. Because of delays in other interpreters
912   // (LooaheadInterpreter), it's possible to get "future" keyboard used times.
913   // We wouldn't want a single bad future value to stop all tap-to-click, so
914   // we sanity check.
915   DoubleProperty keyboard_palm_prevent_timeout_;
916   // Motion (pointer movement, scroll) must halt for this length of time [s]
917   // before a tap can generate a click.
918   DoubleProperty motion_tap_prevent_timeout_;
919   // A finger must be at least this far from other fingers when it taps [mm].
920   DoubleProperty tapping_finger_min_separation_;
921 
922   // Sum of squares of movement [mm] that is considered as noise during pinch
923   // detection
924   DoubleProperty pinch_noise_level_sq_;
925   // Minimal distance [mm] fingers have to move to indicate a pinch gesture.
926   DoubleProperty pinch_guess_min_movement_;
927   // Minimal distance [mm] a thumb have to move to do a pinch gesture.
928   DoubleProperty pinch_thumb_min_movement_;
929   // Minimal distance [mm] fingers have to move to lock a pinch gesture.
930   DoubleProperty pinch_certain_min_movement_;
931   // Minimum Cos(A) that is acceptable for an inward pinch zoom, where A
932   // is the angle between the lower finger and a vertical vector directed
933   // from top to bottom.
934   DoubleProperty inward_pinch_min_angle_;
935   // Maximum Cos(A) to perform a pinch zoom, where A is the angle between
936   // two fingers.
937   DoubleProperty pinch_zoom_max_angle_;
938   // Minimum Cos(A) to perform a scroll gesture when pinch is enabled,
939   // where A is the angle between two fingers.
940   DoubleProperty scroll_min_angle_;
941   // Minimum movement ratio between fingers before we call it a consistent move
942   // for a pinch.
943   DoubleProperty pinch_guess_consistent_mov_ratio_;
944   // Minimum number of touch events needed to start a pinch zoom
945   IntProperty pinch_zoom_min_events_;
946   // If a pinch is determined quickly we use the original landing position to
947   // determing original pinch width. But if they landed too long ago we use the
948   // pinch width at detection. Inverse of time in seconds.
949   DoubleProperty pinch_initial_scale_time_inv_;
950   // Resolution of pinch events: minimum change in squared pinch scale required
951   // to send a pinch update.
952   DoubleProperty pinch_res_;
953   // Change in squared pinch scale required to send a pinch update after fingers
954   // stay stationary.
955   DoubleProperty pinch_stationary_res_;
956   // Time fingers should remain motionless before being treated as stationary.
957   DoubleProperty pinch_stationary_time_;
958   // Change in squared pinch scale required to send a pinch update after fingers
959   // change direction.
960   DoubleProperty pinch_hysteresis_res_;
961   // Temporary flag to turn pinch on/off while we tune it.
962   BoolProperty pinch_enable_;
963 
964   // Short start time diff of fingers for a two-finger click that indicates
965   // a right click
966   DoubleProperty right_click_start_time_diff_;
967   // Second finger comes down for a while then button clicks down that indicates
968   // a right click
969   DoubleProperty right_click_second_finger_age_;
970   // Suppress moves with a speed more than this much times the previous speed.
971   DoubleProperty quick_acceleration_factor_;
972 };
973 
974 bool AnyGesturingFingerLeft(const HardwareState& state,
975                             const FingerMap& prev_gs_fingers);
976 
977 }  // namespace gestures
978 
979 #endif  // GESTURES_IMMEDIATE_INTERPRETER_H_
980