| // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "gestures/include/fling_stop_filter_interpreter.h" |
| |
| #include "gestures/include/util.h" |
| |
| namespace gestures { |
| |
| FlingStopFilterInterpreter::FlingStopFilterInterpreter( |
| PropRegistry* prop_reg, Interpreter* next, Tracer* tracer, |
| GestureInterpreterDeviceClass devclass) |
| : FilterInterpreter(NULL, next, tracer, false), |
| already_extended_(false), |
| prev_touch_cnt_(0), |
| prev_gesture_type_(kGestureTypeNull), |
| fling_stop_already_sent_(false), |
| fling_stop_deadline_(NO_DEADLINE), |
| devclass_(devclass), |
| fling_stop_timeout_(prop_reg, "Fling Stop Timeout", 0.03), |
| fling_stop_extra_delay_(prop_reg, "Fling Stop Extra Delay", 0.055) { |
| InitName(); |
| } |
| |
| void FlingStopFilterInterpreter::SyncInterpretImpl(HardwareState* hwstate, |
| stime_t* timeout) { |
| fingers_of_last_hwstate_.clear(); |
| for (int i = 0; i < hwstate->finger_cnt; i++) |
| fingers_of_last_hwstate_.insert(hwstate->fingers[i].tracking_id); |
| |
| UpdateFlingStopDeadline(*hwstate); |
| |
| stime_t next_timeout = NO_DEADLINE; |
| if (fling_stop_deadline_ != NO_DEADLINE) { |
| if (!already_extended_ && NeedsExtraTime(*hwstate)) { |
| fling_stop_deadline_ += fling_stop_extra_delay_.val_; |
| already_extended_ = true; |
| } |
| if (hwstate->timestamp > fling_stop_deadline_) { |
| // sub in a fling before processing other interpreters |
| ProduceGesture(Gesture(kGestureFling, prev_timestamp_, |
| hwstate->timestamp, 0.0, 0.0, |
| GESTURES_FLING_TAP_DOWN)); |
| fling_stop_already_sent_ = true; |
| fling_stop_deadline_ = NO_DEADLINE; |
| } |
| } |
| next_->SyncInterpret(hwstate, &next_timeout); |
| *timeout = SetNextDeadlineAndReturnTimeoutVal(hwstate->timestamp, |
| fling_stop_deadline_, |
| next_timeout); |
| } |
| |
| bool FlingStopFilterInterpreter::NeedsExtraTime( |
| const HardwareState& hwstate) const { |
| int num_new_fingers = 0; |
| for (int i = 0; i < hwstate.finger_cnt; i++) { |
| const short id = hwstate.fingers[i].tracking_id; |
| if (!SetContainsValue(fingers_present_for_last_fling_, id)) { |
| num_new_fingers++; |
| } |
| } |
| |
| return (num_new_fingers >= 2); |
| } |
| |
| bool FlingStopFilterInterpreter::FlingStopNeeded(const Gesture& gesture) const { |
| if (fling_stop_already_sent_ || gesture.type == prev_gesture_type_) |
| return false; |
| |
| if (devclass_ == GESTURES_DEVCLASS_MULTITOUCH_MOUSE && |
| gesture.type == kGestureTypeMove) |
| return false; |
| |
| return (gesture.type != kGestureTypeFling && |
| gesture.type != kGestureTypeSwipeLift && |
| gesture.type != kGestureTypeFourFingerSwipeLift); |
| } |
| |
| void FlingStopFilterInterpreter::ConsumeGesture(const Gesture& gesture) { |
| if (gesture.type == kGestureTypeFling) { |
| fingers_present_for_last_fling_ = fingers_of_last_hwstate_; |
| already_extended_ = false; |
| } |
| |
| if (FlingStopNeeded(gesture)) { |
| // sub in a fling before a new gesture |
| ProduceGesture(Gesture(kGestureFling, gesture.start_time, |
| gesture.start_time, 0.0, 0.0, |
| GESTURES_FLING_TAP_DOWN)); |
| } |
| ProduceGesture(gesture); |
| fling_stop_deadline_ = NO_DEADLINE; |
| prev_gesture_type_ = gesture.type; |
| fling_stop_already_sent_ = false; |
| } |
| |
| void FlingStopFilterInterpreter::UpdateFlingStopDeadline( |
| const HardwareState& hwstate) { |
| if (fling_stop_timeout_.val_ <= 0.0) |
| return; |
| |
| stime_t now = hwstate.timestamp; |
| bool finger_added = hwstate.touch_cnt > prev_touch_cnt_; |
| |
| if (finger_added && fling_stop_deadline_ == NO_DEADLINE) { |
| // first finger added in a while. Note it. |
| fling_stop_deadline_ = now + fling_stop_timeout_.val_; |
| return; |
| } |
| |
| prev_timestamp_ = now; |
| prev_touch_cnt_ = hwstate.touch_cnt; |
| } |
| |
| void FlingStopFilterInterpreter::HandleTimerImpl(stime_t now, |
| stime_t* timeout) { |
| if (!ShouldCallNextTimer(fling_stop_deadline_)) { |
| if (fling_stop_deadline_ > now) { |
| Err("Spurious callback. now: %f, fs deadline: %f, next deadline: %f", |
| now, fling_stop_deadline_, next_timer_deadline_); |
| return; |
| } |
| fling_stop_deadline_ = NO_DEADLINE; |
| ProduceGesture(Gesture(kGestureFling, prev_timestamp_, |
| now, 0.0, 0.0, |
| GESTURES_FLING_TAP_DOWN)); |
| fling_stop_already_sent_ = true; |
| stime_t next_timeout = |
| next_timer_deadline_ == NO_DEADLINE || next_timer_deadline_ <= now ? |
| NO_DEADLINE : next_timer_deadline_ - now; |
| *timeout = SetNextDeadlineAndReturnTimeoutVal(now, fling_stop_deadline_, |
| next_timeout); |
| return; |
| } |
| // Call next_ |
| if (next_timer_deadline_ > now) { |
| Err("Spurious callback. now: %f, fs deadline: %f, next deadline: %f", |
| now, fling_stop_deadline_, next_timer_deadline_); |
| return; |
| } |
| stime_t next_timeout = NO_DEADLINE; |
| next_->HandleTimer(now, &next_timeout); |
| *timeout = SetNextDeadlineAndReturnTimeoutVal(now, fling_stop_deadline_, |
| next_timeout); |
| } |
| |
| } // namespace gestures |