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