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