diff options
author | varunjain@chromium.org <varunjain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-05 17:46:38 +0000 |
---|---|---|
committer | varunjain@chromium.org <varunjain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-05 17:46:38 +0000 |
commit | 00bad32d31ded458795fafd313a6b6463ac398f8 (patch) | |
tree | be1ec495f66d131c21bed365d8725b947ef41a77 /ui/base/gestures | |
parent | e93c52bafa312857371b4d47fc5d1a83c5929a68 (diff) | |
download | chromium_src-00bad32d31ded458795fafd313a6b6463ac398f8.zip chromium_src-00bad32d31ded458795fafd313a6b6463ac398f8.tar.gz chromium_src-00bad32d31ded458795fafd313a6b6463ac398f8.tar.bz2 |
Add two finger tap gesture to gesture recognizer.
BUG=126058
TEST=none
Review URL: https://chromiumcodereview.appspot.com/10447129
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@140553 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/base/gestures')
-rw-r--r-- | ui/base/gestures/gesture_configuration.cc | 1 | ||||
-rw-r--r-- | ui/base/gestures/gesture_configuration.h | 11 | ||||
-rw-r--r-- | ui/base/gestures/gesture_point.h | 2 | ||||
-rw-r--r-- | ui/base/gestures/gesture_sequence.cc | 113 | ||||
-rw-r--r-- | ui/base/gestures/gesture_sequence.h | 17 | ||||
-rw-r--r-- | ui/base/gestures/gestures.dot | 11 |
6 files changed, 147 insertions, 8 deletions
diff --git a/ui/base/gestures/gesture_configuration.cc b/ui/base/gestures/gesture_configuration.cc index 5752144..b83a64a 100644 --- a/ui/base/gestures/gesture_configuration.cc +++ b/ui/base/gestures/gesture_configuration.cc @@ -10,6 +10,7 @@ namespace ui { // associated list of prefs in gesture_prefs_aura.cc. int GestureConfiguration::default_radius_ = 15; double GestureConfiguration::long_press_time_in_seconds_ = 1.0; +double GestureConfiguration::max_distance_for_two_finger_tap_in_pixels_ = 300; int GestureConfiguration::max_radius_ = 100; double GestureConfiguration::max_seconds_between_double_click_ = 0.7; double diff --git a/ui/base/gestures/gesture_configuration.h b/ui/base/gestures/gesture_configuration.h index f491ccd..397dbc6 100644 --- a/ui/base/gestures/gesture_configuration.h +++ b/ui/base/gestures/gesture_configuration.h @@ -25,6 +25,12 @@ class UI_EXPORT GestureConfiguration { static double long_press_time_in_seconds() { return long_press_time_in_seconds_; } + static double max_distance_for_two_finger_tap_in_pixels() { + return max_distance_for_two_finger_tap_in_pixels_; + } + static void set_max_distance_for_two_finger_tap_in_pixels(double val) { + max_distance_for_two_finger_tap_in_pixels_ = val; + } static int max_radius() { return max_radius_; } @@ -131,6 +137,11 @@ class UI_EXPORT GestureConfiguration { // by the device is the touch center. static int default_radius_; + // The maximum allowed distance between two fingers for a two finger tap. If + // the distance between two fingers is greater than this value, we will not + // recognize a two finger tap. + static double max_distance_for_two_finger_tap_in_pixels_; + // The maximum allowed size for the radius of a touch region used in // forming an ET_GESTURE_TAP event. static int max_radius_; diff --git a/ui/base/gestures/gesture_point.h b/ui/base/gestures/gesture_point.h index 19a8a3c..d019892 100644 --- a/ui/base/gestures/gesture_point.h +++ b/ui/base/gestures/gesture_point.h @@ -44,6 +44,7 @@ class GesturePoint { bool IsInFlickWindow(const TouchEvent& event); bool IsInHorizontalRailWindow() const; bool IsInVerticalRailWindow() const; + bool IsInsideManhattanSquare(const TouchEvent& event) const; bool HasEnoughDataToEstablishRail() const; bool BreaksHorizontalRail(); bool BreaksVerticalRail(); @@ -89,7 +90,6 @@ class GesturePoint { // Various statistical functions to manipulate gestures. bool IsInClickTimeWindow() const; bool IsInSecondClickTimeWindow() const; - bool IsInsideManhattanSquare(const TouchEvent& event) const; bool IsSecondClickInsideManhattanSquare(const TouchEvent& event) const; bool IsOverMinFlickSpeed(); diff --git a/ui/base/gestures/gesture_sequence.cc b/ui/base/gestures/gesture_sequence.cc index c0441fe..f11d5d1 100644 --- a/ui/base/gestures/gesture_sequence.cc +++ b/ui/base/gestures/gesture_sequence.cc @@ -88,6 +88,27 @@ enum EdgeStateSignatureType { GST_SCROLL_SECOND_PRESSED = G(GS_SCROLL, 1, TS_PRESSED, false), + GST_PENDING_TWO_FINGER_TAP_FIRST_RELEASED = + G(GS_PENDING_TWO_FINGER_TAP, 0, TS_RELEASED, false), + + GST_PENDING_TWO_FINGER_TAP_SECOND_RELEASED = + G(GS_PENDING_TWO_FINGER_TAP, 1, TS_RELEASED, false), + + GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED = + G(GS_PENDING_TWO_FINGER_TAP, 0, TS_MOVED, false), + + GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED = + G(GS_PENDING_TWO_FINGER_TAP, 1, TS_MOVED, false), + + GST_PENDING_TWO_FINGER_TAP_FIRST_CANCELLED = + G(GS_PENDING_TWO_FINGER_TAP, 0, TS_CANCELLED, false), + + GST_PENDING_TWO_FINGER_TAP_SECOND_CANCELLED = + G(GS_PENDING_TWO_FINGER_TAP, 1, TS_CANCELLED, false), + + GST_PENDING_TWO_FINGER_TAP_THIRD_PRESSED = + G(GS_PENDING_TWO_FINGER_TAP, 2, TS_PRESSED, false), + GST_PINCH_FIRST_MOVED = G(GS_PINCH, 0, TS_MOVED, false), @@ -262,8 +283,30 @@ GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture( break; case GST_SCROLL_SECOND_PRESSED: case GST_PENDING_SYNTHETIC_CLICK_SECOND_PRESSED: - // Once pinch starts, we immediately break rail scroll. + if (IsSecondTouchDownCloseEnoughForTwoFingerTap()) { + TwoFingerTouchDown(event, point, gestures.get()); + set_state(GS_PENDING_TWO_FINGER_TAP); + } else { + PinchStart(event, point, gestures.get()); + set_state(GS_PINCH); + } + break; + case GST_PENDING_TWO_FINGER_TAP_FIRST_RELEASED: + case GST_PENDING_TWO_FINGER_TAP_SECOND_RELEASED: + TwoFingerTouchReleased(event, point, gestures.get()); + set_state(GS_SCROLL); + break; + case GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED: + case GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED: + if (TwoFingerTouchMove(event, point, gestures.get())) + set_state(GS_PINCH); + break; + case GST_PENDING_TWO_FINGER_TAP_FIRST_CANCELLED: + case GST_PENDING_TWO_FINGER_TAP_SECOND_CANCELLED: scroll_type_ = ST_FREE; + set_state(GS_SCROLL); + break; + case GST_PENDING_TWO_FINGER_TAP_THIRD_PRESSED: PinchStart(event, point, gestures.get()); set_state(GS_PINCH); break; @@ -414,6 +457,18 @@ GesturePoint* GestureSequence::GetPointByPointId(int point_id) { return NULL; } +bool GestureSequence::IsSecondTouchDownCloseEnoughForTwoFingerTap() { + gfx::Point p1 = GetPointByPointId(0)->last_touch_position(); + gfx::Point p2 = GetPointByPointId(1)->last_touch_position(); + double max_distance = + ui::GestureConfiguration::max_distance_for_two_finger_tap_in_pixels(); + double distance = (p1.x() - p2.x()) * (p1.x() - p2.x()) + + (p1.y() - p2.y()) * (p1.y() - p2.y()); + if (distance < max_distance * max_distance) + return true; + return false; +} + void GestureSequence::AppendTapDownGestureEvent(const GesturePoint& point, Gestures* gestures) { gestures->push_back(helper_->CreateGestureEvent( @@ -581,6 +636,16 @@ void GestureSequence::AppendSwipeGesture(const GesturePoint& point, swipe_x, swipe_y, ComputeTouchBitmask(points_))); } +void GestureSequence::AppendTwoFingerTapGestureEvent(Gestures* gestures) { + const GesturePoint* point = GetPointByPointId(0); + gestures->push_back(helper_->CreateGestureEvent( + ui::ET_GESTURE_TWO_FINGER_TAP, + point->enclosing_rectangle().CenterPoint(), + flags_, + base::Time::FromDoubleT(point->last_touch_time()), + 0.f, 0.f, 1 << point->touch_id())); +} + bool GestureSequence::Click(const TouchEvent& event, const GesturePoint& point, Gestures* gestures) { DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK); @@ -649,6 +714,42 @@ bool GestureSequence::TouchDown(const TouchEvent& event, return true; } +bool GestureSequence::TwoFingerTouchDown(const TouchEvent& event, + const GesturePoint& point, Gestures* gestures) { + DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK || state_ == GS_SCROLL); + if (state_ == GS_SCROLL) { + AppendScrollGestureEnd(point, point.last_touch_position(), gestures, + 0.f, 0.f); + } + second_touch_time_ = event.GetTimestamp(); + return true; +} + +bool GestureSequence::TwoFingerTouchMove(const TouchEvent& event, + const GesturePoint& point, Gestures* gestures) { + DCHECK(state_ == GS_PENDING_TWO_FINGER_TAP); + + base::TimeDelta time_delta = event.GetTimestamp() - second_touch_time_; + base::TimeDelta max_delta = base::TimeDelta::FromMilliseconds(1000 * + ui::GestureConfiguration::max_touch_down_duration_in_seconds_for_click()); + if (time_delta > max_delta || !point.IsInsideManhattanSquare(event)) { + PinchStart(event, point, gestures); + return true; + } + return false; +} + +bool GestureSequence::TwoFingerTouchReleased(const TouchEvent& event, + const GesturePoint& point, Gestures* gestures) { + DCHECK(state_ == GS_PENDING_TWO_FINGER_TAP); + base::TimeDelta time_delta = event.GetTimestamp() - second_touch_time_; + base::TimeDelta max_delta = base::TimeDelta::FromMilliseconds(1000 * + ui::GestureConfiguration::max_touch_down_duration_in_seconds_for_click()); + if (time_delta < max_delta && point.IsInsideManhattanSquare(event)) + AppendTwoFingerTapGestureEvent(gestures); + return true; +} + void GestureSequence::AppendLongPressGestureEvent() { const GesturePoint* point = GetPointByPointId(0); scoped_ptr<GestureEvent> gesture(helper_->CreateGestureEvent( @@ -676,8 +777,11 @@ bool GestureSequence::ScrollEnd(const TouchEvent& event, bool GestureSequence::PinchStart(const TouchEvent& event, const GesturePoint& point, Gestures* gestures) { DCHECK(state_ == GS_SCROLL || - state_ == GS_PENDING_SYNTHETIC_CLICK); - AppendTapDownGestureEvent(point, gestures); + state_ == GS_PENDING_SYNTHETIC_CLICK || + state_ == GS_PENDING_TWO_FINGER_TAP); + + // Once pinch starts, we immediately break rail scroll. + scroll_type_ = ST_FREE; const GesturePoint* point1 = GetPointByPointId(0); const GesturePoint* point2 = GetPointByPointId(1); @@ -686,7 +790,8 @@ bool GestureSequence::PinchStart(const TouchEvent& event, pinch_distance_start_ = pinch_distance_current_; AppendPinchGestureBegin(*point1, *point2, gestures); - if (state_ == GS_PENDING_SYNTHETIC_CLICK) { + if (state_ == GS_PENDING_SYNTHETIC_CLICK || + state_ == GS_PENDING_TWO_FINGER_TAP) { gfx::Point center = bounding_box_.CenterPoint(); AppendScrollGestureBegin(point, center, gestures); } diff --git a/ui/base/gestures/gesture_sequence.h b/ui/base/gestures/gesture_sequence.h index 0a52578..b976bb3 100644 --- a/ui/base/gestures/gesture_sequence.h +++ b/ui/base/gestures/gesture_sequence.h @@ -22,6 +22,7 @@ enum GestureState { GS_PENDING_SYNTHETIC_CLICK, GS_SCROLL, GS_PINCH, + GS_PENDING_TWO_FINGER_TAP, }; enum ScrollType { @@ -71,6 +72,8 @@ class UI_EXPORT GestureSequence { // with id |point_id|. GesturePoint* GetPointByPointId(int point_id); + bool IsSecondTouchDownCloseEnoughForTwoFingerTap(); + // Functions to be called to add GestureEvents, after successful recognition. // Tap gestures. @@ -109,6 +112,7 @@ class UI_EXPORT GestureSequence { int swipe_x, int swipe_y, Gestures* gestures); + void AppendTwoFingerTapGestureEvent(Gestures* gestures); void set_state(const GestureState state) { state_ = state; } @@ -133,6 +137,15 @@ class UI_EXPORT GestureSequence { bool TouchDown(const TouchEvent& event, const GesturePoint& point, Gestures* gestures); + bool TwoFingerTouchDown(const TouchEvent& event, + const GesturePoint& point, + Gestures* gestures); + bool TwoFingerTouchMove(const TouchEvent& event, + const GesturePoint& point, + Gestures* gestures); + bool TwoFingerTouchReleased(const TouchEvent& event, + const GesturePoint& point, + Gestures* gestures); bool ScrollEnd(const TouchEvent& event, GesturePoint& point, Gestures* gestures); @@ -170,6 +183,10 @@ class UI_EXPORT GestureSequence { // This distance is updated after each PINCH_UPDATE. float pinch_distance_current_; + // This is the time when second touch down was received. Used for determining + // if a two finger double tap has happened. + base::TimeDelta second_touch_time_; + ScrollType scroll_type_; scoped_ptr<base::OneShotTimer<GestureSequence> > long_press_timer_; diff --git a/ui/base/gestures/gestures.dot b/ui/base/gestures/gestures.dot index 6e3aa5c..868c542 100644 --- a/ui/base/gestures/gestures.dot +++ b/ui/base/gestures/gestures.dot @@ -13,7 +13,8 @@ M : Move \l\ D : Down \l\ S : Stationary \l\ C : Cancel \l\ -R : Release \l}" +R : Release \l\ +M_Delay : Move after a certain delay}" shape = record] subgraph none_pending { @@ -25,8 +26,12 @@ GS_PENDING_SYNTHETIC_CLICK -> GS_NO_GESTURE [label= "C0\n R0"]; GS_SCROLL -> GS_SCROLL [label= "M0"]; GS_SCROLL -> GS_NO_GESTURE [label= "C0\n R0\n"]; -GS_PENDING_SYNTHETIC_CLICK -> GS_PINCH [label= "D1"]; -GS_SCROLL -> GS_PINCH [label= "D1"]; +GS_PENDING_SYNTHETIC_CLICK -> GS_PENDING_TWO_FINGER_TAP [label= "D1"]; +GS_SCROLL -> GS_PENDING_TWO_FINGER_TAP [label= "D1"]; +GS_PENDING_TWO_FINGER_TAP -> GS_PINCH [label= "M0\n M1"]; +GS_PENDING_TWO_FINGER_TAP -> GS_PINCH [label= "M_Delay0\n M_Delay1"]; +GS_PENDING_TWO_FINGER_TAP -> GS_PINCH [label= "D2"]; +GS_PENDING_TWO_FINGER_TAP -> GS_SCROLL [label= "R0\n R1\n C0\n C1"]; GS_PINCH -> GS_PINCH [label= "M0\n M1"]; GS_PINCH -> GS_SCROLL [label= "C0\n R0\n C1\n R1"]; |