diff options
author | tdresser@chromium.org <tdresser@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-17 13:52:45 +0000 |
---|---|---|
committer | tdresser@chromium.org <tdresser@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-17 13:52:45 +0000 |
commit | 93425b44c4ea18ca58e3f5585d92795628bc5355 (patch) | |
tree | 0d3c398b08ab343ced67a07c48c229b535a8a1ae | |
parent | 1895cda784ed3c8a899379f32b334761d386e6ed (diff) | |
download | chromium_src-93425b44c4ea18ca58e3f5585d92795628bc5355.zip chromium_src-93425b44c4ea18ca58e3f5585d92795628bc5355.tar.gz chromium_src-93425b44c4ea18ca58e3f5585d92795628bc5355.tar.bz2 |
Three Finger Swipe
Implements a three finger swipe gesture event for the aura Gesture Recognizer.
BUG=122807
TEST=SystemGestureEventFilterTest.TapOutsideRootWindow, GestureRecognizerTest.GestureEventThreeFingerSwipe
Review URL: http://codereview.chromium.org/10037012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132570 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ash/wm/system_gesture_event_filter.cc | 3 | ||||
-rw-r--r-- | ash/wm/system_gesture_event_filter_unittest.cc | 27 | ||||
-rw-r--r-- | chrome/browser/ui/gesture_prefs_observer_factory_aura.cc | 16 | ||||
-rw-r--r-- | chrome/common/pref_names.cc | 4 | ||||
-rw-r--r-- | chrome/common/pref_names.h | 2 | ||||
-rw-r--r-- | ui/aura/gestures/gesture_recognizer_unittest.cc | 194 | ||||
-rw-r--r-- | ui/base/events.h | 1 | ||||
-rw-r--r-- | ui/base/gestures/gesture_configuration.cc | 2 | ||||
-rw-r--r-- | ui/base/gestures/gesture_configuration.h | 14 | ||||
-rw-r--r-- | ui/base/gestures/gesture_sequence.cc | 133 | ||||
-rw-r--r-- | ui/base/gestures/gesture_sequence.h | 14 | ||||
-rw-r--r-- | ui/base/gestures/gestures.dot | 4 |
12 files changed, 411 insertions, 3 deletions
diff --git a/ash/wm/system_gesture_event_filter.cc b/ash/wm/system_gesture_event_filter.cc index 46f2ea17..1568052 100644 --- a/ash/wm/system_gesture_event_filter.cc +++ b/ash/wm/system_gesture_event_filter.cc @@ -37,6 +37,8 @@ ui::TouchStatus SystemGestureEventFilter::PreHandleTouchEvent( ui::GestureStatus SystemGestureEventFilter::PreHandleGestureEvent( aura::Window* target, aura::GestureEvent* event) { // TODO(tdresser) handle system level gesture events + if (event->type() == ui::ET_GESTURE_THREE_FINGER_SWIPE) + return ui::GESTURE_STATUS_CONSUMED; if (target == Shell::GetRootWindow()) return ui::GESTURE_STATUS_CONSUMED; return ui::GESTURE_STATUS_UNKNOWN; @@ -44,4 +46,3 @@ ui::GestureStatus SystemGestureEventFilter::PreHandleGestureEvent( } // namespace internal } // namespace ash - diff --git a/ash/wm/system_gesture_event_filter_unittest.cc b/ash/wm/system_gesture_event_filter_unittest.cc index 35c7596..8e26aec 100644 --- a/ash/wm/system_gesture_event_filter_unittest.cc +++ b/ash/wm/system_gesture_event_filter_unittest.cc @@ -47,4 +47,31 @@ TEST_F(SystemGestureEventFilterTest, TapOutsideRootWindow) { EXPECT_FALSE(consumed); } +// Ensure that a three fingered swipe is consumed by the system event handler. +TEST_F(SystemGestureEventFilterTest, ThreeFingerSwipe) { + aura::RootWindow* root_window = Shell::GetRootWindow(); + + const int kTouchId = 5; + + // Get a target for kTouchId + aura::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(100, 100), kTouchId, + base::Time::NowFromSystemTime() - base::Time()); + root_window->DispatchTouchEvent(&press); + + aura::GestureEvent* event = new aura::GestureEvent( + ui::ET_GESTURE_THREE_FINGER_SWIPE, 0, 0, 0, base::Time::Now(), + 0, 0, 1 << kTouchId); + bool consumed = root_window->DispatchGestureEvent(event); + + EXPECT_TRUE(consumed); + + // The system event filter shouldn't filter out events like tap downs. + aura::GestureEvent* event2 = new aura::GestureEvent( + ui::ET_GESTURE_TAP_DOWN, 0, 0, 0, base::Time::Now(), + 0, 0, 1 << kTouchId); + consumed = root_window->DispatchGestureEvent(event2); + + EXPECT_FALSE(consumed); +} + } // namespace ash diff --git a/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc b/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc index ded9781..87ff5c00 100644 --- a/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc +++ b/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc @@ -49,6 +49,7 @@ const char* kPrefsToObserve[] = { prefs::kLongPressTimeInSeconds, prefs::kMaxSecondsBetweenDoubleClick, prefs::kMaxSeparationForGestureTouchesInPixels, + prefs::kMaxSwipeDeviationRatio, prefs::kMaxTouchDownDurationInSecondsForClick, prefs::kMaxTouchMoveInPixelsForClick, prefs::kMinDistanceForPinchScrollInPixels, @@ -56,6 +57,7 @@ const char* kPrefsToObserve[] = { prefs::kMinPinchUpdateDistanceInPixels, prefs::kMinRailBreakVelocity, prefs::kMinScrollDeltaSquared, + prefs::kMinSwipeSpeed, prefs::kMinTouchDownDurationInSecondsForClick, prefs::kPointsBufferedForVelocity, prefs::kRailBreakProportion, @@ -93,6 +95,9 @@ void GesturePrefsObserver::Update() { GestureConfiguration::set_max_separation_for_gesture_touches_in_pixels( prefs_->GetDouble( prefs::kMaxSeparationForGestureTouchesInPixels)); + GestureConfiguration::set_max_swipe_deviation_ratio( + prefs_->GetDouble( + prefs::kMaxSwipeDeviationRatio)); GestureConfiguration::set_max_touch_down_duration_in_seconds_for_click( prefs_->GetDouble( prefs::kMaxTouchDownDurationInSecondsForClick)); @@ -114,6 +119,9 @@ void GesturePrefsObserver::Update() { GestureConfiguration::set_min_scroll_delta_squared( prefs_->GetDouble( prefs::kMinScrollDeltaSquared)); + GestureConfiguration::set_min_swipe_speed( + prefs_->GetDouble( + prefs::kMinSwipeSpeed)); GestureConfiguration::set_min_touch_down_duration_in_seconds_for_click( prefs_->GetDouble( prefs::kMinTouchDownDurationInSecondsForClick)); @@ -161,6 +169,10 @@ void GesturePrefsObserverFactoryAura::RegisterUserPrefs(PrefService* prefs) { GestureConfiguration::max_separation_for_gesture_touches_in_pixels(), PrefService::UNSYNCABLE_PREF); prefs->RegisterDoublePref( + prefs::kMaxSwipeDeviationRatio, + GestureConfiguration::max_swipe_deviation_ratio(), + PrefService::UNSYNCABLE_PREF); + prefs->RegisterDoublePref( prefs::kMaxTouchDownDurationInSecondsForClick, GestureConfiguration::max_touch_down_duration_in_seconds_for_click(), PrefService::UNSYNCABLE_PREF); @@ -189,6 +201,10 @@ void GesturePrefsObserverFactoryAura::RegisterUserPrefs(PrefService* prefs) { GestureConfiguration::min_scroll_delta_squared(), PrefService::UNSYNCABLE_PREF); prefs->RegisterDoublePref( + prefs::kMinSwipeSpeed, + GestureConfiguration::min_swipe_speed(), + PrefService::UNSYNCABLE_PREF); + prefs->RegisterDoublePref( prefs::kMinTouchDownDurationInSecondsForClick, GestureConfiguration::min_touch_down_duration_in_seconds_for_click(), PrefService::UNSYNCABLE_PREF); diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index ef71820..432642f 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -1814,6 +1814,8 @@ const char kMaxSecondsBetweenDoubleClick[] = "gesture.max_seconds_between_double_click"; const char kMaxSeparationForGestureTouchesInPixels[] = "gesture.max_separation_for_gesture_touches_in_pixels"; +const char kMaxSwipeDeviationRatio[] = + "gesture.max_swipe_deviation_ratio"; const char kMaxTouchDownDurationInSecondsForClick[] = "gesture.max_touch_down_duration_in_seconds_for_click"; const char kMaxTouchMoveInPixelsForClick[] = @@ -1828,6 +1830,8 @@ const char kMinRailBreakVelocity[] = "gesture.min_rail_break_velocity"; const char kMinScrollDeltaSquared[] = "gesture.min_scroll_delta_squared"; +const char kMinSwipeSpeed[] = + "gesture.min_swipe_speed"; const char kMinTouchDownDurationInSecondsForClick[] = "gesture.min_touch_down_duration_in_seconds_for_click"; const char kPointsBufferedForVelocity[] = diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 616283c..05c5853 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -677,6 +677,7 @@ extern const char kPinnedLauncherApps[]; extern const char kLongPressTimeInSeconds[]; extern const char kMaxSecondsBetweenDoubleClick[]; extern const char kMaxSeparationForGestureTouchesInPixels[]; +extern const char kMaxSwipeDeviationRatio[]; extern const char kMaxTouchDownDurationInSecondsForClick[]; extern const char kMaxTouchMoveInPixelsForClick[]; extern const char kMinDistanceForPinchScrollInPixels[]; @@ -684,6 +685,7 @@ extern const char kMinFlickSpeedSquared[]; extern const char kMinPinchUpdateDistanceInPixels[]; extern const char kMinRailBreakVelocity[]; extern const char kMinScrollDeltaSquared[]; +extern const char kMinSwipeSpeed[]; extern const char kMinTouchDownDurationInSecondsForClick[]; extern const char kPointsBufferedForVelocity[]; extern const char kRailBreakProportion[]; diff --git a/ui/aura/gestures/gesture_recognizer_unittest.cc b/ui/aura/gestures/gesture_recognizer_unittest.cc index 6879d8f..80fa46e 100644 --- a/ui/aura/gestures/gesture_recognizer_unittest.cc +++ b/ui/aura/gestures/gesture_recognizer_unittest.cc @@ -37,6 +37,7 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { pinch_update_(false), pinch_end_(false), long_press_(false), + three_finger_swipe_(false), scroll_x_(0), scroll_y_(0), velocity_x_(0), @@ -56,6 +57,7 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { pinch_update_ = false; pinch_end_ = false; long_press_ = false; + three_finger_swipe_ = false; scroll_begin_position_.SetPoint(0, 0); @@ -75,6 +77,7 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { bool pinch_update() const { return pinch_update_; } bool pinch_end() const { return pinch_end_; } bool long_press() const { return long_press_; } + bool three_finger_swipe() const { return three_finger_swipe_; } const gfx::Point scroll_begin_position() const { return scroll_begin_position_; @@ -124,6 +127,11 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { long_press_ = true; touch_id_ = gesture->delta_x(); break; + case ui::ET_GESTURE_THREE_FINGER_SWIPE: + three_finger_swipe_ = true; + velocity_x_ = gesture->delta_x(); + velocity_y_ = gesture->delta_y(); + break; default: NOTREACHED(); } @@ -141,6 +149,7 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { bool pinch_update_; bool pinch_end_; bool long_press_; + bool three_finger_swipe_; gfx::Point scroll_begin_position_; @@ -316,7 +325,6 @@ void SendScrollEvents(RootWindow* root_window, base::TimeDelta time = time_start; for (int i = 0; i < num_steps; i++) { - delegate->Reset(); x += dx; y += dy; time = time + base::TimeDelta::FromMilliseconds(time_step); @@ -1485,5 +1493,189 @@ TEST_F(GestureRecognizerTest, NoTapWithPreventDefaultedRelease) { EXPECT_FALSE(delegate->tap()); } +TEST_F(GestureRecognizerTest, GestureEventThreeFingerSwipe) { + scoped_ptr<GestureEventConsumeDelegate> delegate( + new GestureEventConsumeDelegate()); + const int kTouchId1 = 7; + const int kTouchId2 = 2; + const int kTouchId3 = 9; + gfx::Rect bounds(0, 0, 1000, 1000); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + delegate.get(), -1234, bounds, NULL)); + + TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), + kTouchId1, GetTime()); + TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), + kTouchId2, GetTime()); + TouchEvent press3(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), + kTouchId3, GetTime()); + + TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(0, 0), + kTouchId1, GetTime()); + TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(0, 0), + kTouchId2, GetTime()); + TouchEvent release3(ui::ET_TOUCH_RELEASED, gfx::Point(0, 0), + kTouchId3, GetTime()); + + root_window()->DispatchTouchEvent(&press1); + root_window()->DispatchTouchEvent(&press2); + root_window()->DispatchTouchEvent(&press3); + + delegate->Reset(); + + // Start by testing all four directions + + int kBufferedPoints = + ui::GestureConfiguration::points_buffered_for_velocity(); + + // Swipe right + SendScrollEvents(root_window(), 1, 1, press1.time_stamp(), + 100, 10, kTouchId1, 1, kBufferedPoints, delegate.get()); + SendScrollEvents(root_window(), 1, 1, press2.time_stamp(), + 100, 10, kTouchId2, 1, kBufferedPoints, delegate.get()); + SendScrollEvents(root_window(), 1, 1, press3.time_stamp(), + 100, 10, kTouchId3, 1, kBufferedPoints, delegate.get()); + + EXPECT_TRUE(delegate->three_finger_swipe()); + EXPECT_EQ(1, delegate->velocity_x()); + EXPECT_EQ(0, delegate->velocity_y()); + + root_window()->DispatchTouchEvent(&release1); + root_window()->DispatchTouchEvent(&release2); + root_window()->DispatchTouchEvent(&release3); + + root_window()->DispatchTouchEvent(&press1); + root_window()->DispatchTouchEvent(&press2); + root_window()->DispatchTouchEvent(&press3); + + delegate->Reset(); + + // Swipe left + SendScrollEvents(root_window(), 1, 1, + press1.time_stamp(), + -100, 10, kTouchId1, 1, kBufferedPoints, delegate.get()); + SendScrollEvents(root_window(), 1, 1, + press2.time_stamp(), + -100, 10, kTouchId2, 1, kBufferedPoints, delegate.get()); + SendScrollEvents(root_window(), 1, 1, + press3.time_stamp(), + -100, 10, kTouchId3, 1, kBufferedPoints, delegate.get()); + + EXPECT_TRUE(delegate->three_finger_swipe()); + EXPECT_EQ(-1, delegate->velocity_x()); + EXPECT_EQ(0, delegate->velocity_y()); + + root_window()->DispatchTouchEvent(&release1); + root_window()->DispatchTouchEvent(&release2); + root_window()->DispatchTouchEvent(&release3); + + root_window()->DispatchTouchEvent(&press1); + root_window()->DispatchTouchEvent(&press2); + root_window()->DispatchTouchEvent(&press3); + + delegate->Reset(); + + // Swipe down + SendScrollEvents(root_window(), 1, 1, + press1.time_stamp(), + 10, 100, kTouchId1, 1, kBufferedPoints, delegate.get()); + SendScrollEvents(root_window(), 1, 1, + press2.time_stamp(), + 10, 100, kTouchId2, 1, kBufferedPoints, delegate.get()); + SendScrollEvents(root_window(), 1, 1, + press3.time_stamp(), + 10, 100, kTouchId3, 1, kBufferedPoints, delegate.get()); + + EXPECT_TRUE(delegate->three_finger_swipe()); + EXPECT_EQ(0, delegate->velocity_x()); + EXPECT_EQ(1, delegate->velocity_y()); + + root_window()->DispatchTouchEvent(&release1); + root_window()->DispatchTouchEvent(&release2); + root_window()->DispatchTouchEvent(&release3); + + root_window()->DispatchTouchEvent(&press1); + root_window()->DispatchTouchEvent(&press2); + root_window()->DispatchTouchEvent(&press3); + + delegate->Reset(); + + // Swipe up + SendScrollEvents(root_window(), 1, 1, + press1.time_stamp(), + 10, -100, kTouchId1, 1, kBufferedPoints, delegate.get()); + SendScrollEvents(root_window(), 1, 1, + press2.time_stamp(), + 10, -100, kTouchId2, 1, kBufferedPoints, delegate.get()); + SendScrollEvents(root_window(), 1, 1, + press3.time_stamp(), + 10, -100, kTouchId3, 1, kBufferedPoints, delegate.get()); + + EXPECT_TRUE(delegate->three_finger_swipe()); + EXPECT_EQ(0, delegate->velocity_x()); + EXPECT_EQ(-1, delegate->velocity_y()); + + // Only one swipe can occur per press of three fingers + delegate->Reset(); + + SendScrollEvents(root_window(), 1, 1, + press1.time_stamp(), + 10, -100, kTouchId1, 1, kBufferedPoints, delegate.get()); + SendScrollEvents(root_window(), 1, 1, + press2.time_stamp(), + 10, -100, kTouchId2, 1, kBufferedPoints, delegate.get()); + SendScrollEvents(root_window(), 1, 1, + press3.time_stamp(), + 10, -100, kTouchId3, 1, kBufferedPoints, delegate.get()); + + EXPECT_FALSE(delegate->three_finger_swipe()); + + root_window()->DispatchTouchEvent(&release1); + root_window()->DispatchTouchEvent(&release2); + root_window()->DispatchTouchEvent(&release3); + + root_window()->DispatchTouchEvent(&press1); + root_window()->DispatchTouchEvent(&press2); + root_window()->DispatchTouchEvent(&press3); + + delegate->Reset(); + + // Swiping diagonally doesn't fire an event + SendScrollEvents(root_window(), 1, 1, + press1.time_stamp(), + 100, -100, kTouchId1, 1, kBufferedPoints, delegate.get()); + SendScrollEvents(root_window(), 1, 1, + press2.time_stamp(), + 100, -100, kTouchId2, 1, kBufferedPoints, delegate.get()); + SendScrollEvents(root_window(), 1, 1, + press3.time_stamp(), + 100, -100, kTouchId3, 1, kBufferedPoints, delegate.get()); + + EXPECT_FALSE(delegate->three_finger_swipe()); + + root_window()->DispatchTouchEvent(&release1); + root_window()->DispatchTouchEvent(&release2); + root_window()->DispatchTouchEvent(&release3); + + root_window()->DispatchTouchEvent(&press1); + root_window()->DispatchTouchEvent(&press2); + root_window()->DispatchTouchEvent(&press3); + + delegate->Reset(); + + // Have to swipe in a consistent direction + SendScrollEvents(root_window(), 1, 1, + press1.time_stamp(), + 100, 10, kTouchId1, 1, kBufferedPoints, delegate.get()); + SendScrollEvents(root_window(), 1, 1, + press2.time_stamp(), + 100, 10, kTouchId2, 1, kBufferedPoints, delegate.get()); + SendScrollEvents(root_window(), 1, 1, + press3.time_stamp(), + -100, 10, kTouchId3, 1, kBufferedPoints, delegate.get()); + + EXPECT_FALSE(delegate->three_finger_swipe()); +} + } // namespace test } // namespace aura diff --git a/ui/base/events.h b/ui/base/events.h index 814ffe3..33fb77f 100644 --- a/ui/base/events.h +++ b/ui/base/events.h @@ -54,6 +54,7 @@ enum EventType { ET_GESTURE_PINCH_END, ET_GESTURE_PINCH_UPDATE, ET_GESTURE_LONG_PRESS, + ET_GESTURE_THREE_FINGER_SWIPE, // Scroll support. // TODO[davemoore] we need to unify these events w/ touch and gestures. diff --git a/ui/base/gestures/gesture_configuration.cc b/ui/base/gestures/gesture_configuration.cc index 9128aa5..17a9d6f 100644 --- a/ui/base/gestures/gesture_configuration.cc +++ b/ui/base/gestures/gesture_configuration.cc @@ -12,6 +12,7 @@ double GestureConfiguration::long_press_time_in_seconds_ = 0.5; double GestureConfiguration::max_seconds_between_double_click_ = 0.7; double GestureConfiguration::max_separation_for_gesture_touches_in_pixels_ = 150; +double GestureConfiguration::max_swipe_deviation_ratio_ = 3; double GestureConfiguration::max_touch_down_duration_in_seconds_for_click_ = 0.8; double GestureConfiguration::max_touch_move_in_pixels_for_click_ = 20; @@ -20,6 +21,7 @@ double GestureConfiguration::min_flick_speed_squared_ = 550.f * 550.f; double GestureConfiguration::min_pinch_update_distance_in_pixels_ = 5; double GestureConfiguration::min_rail_break_velocity_ = 200; double GestureConfiguration::min_scroll_delta_squared_ = 5 * 5; +double GestureConfiguration::min_swipe_speed_ = 20; double GestureConfiguration::min_touch_down_duration_in_seconds_for_click_ = 0.01; diff --git a/ui/base/gestures/gesture_configuration.h b/ui/base/gestures/gesture_configuration.h index 83f953b..c1aa5dc 100644 --- a/ui/base/gestures/gesture_configuration.h +++ b/ui/base/gestures/gesture_configuration.h @@ -37,6 +37,12 @@ class UI_EXPORT GestureConfiguration { static void set_max_separation_for_gesture_touches_in_pixels(int val) { max_separation_for_gesture_touches_in_pixels_ = val; } + static double max_swipe_deviation_ratio() { + return max_swipe_deviation_ratio_; + } + static void set_max_swipe_deviation_ratio(double val) { + max_swipe_deviation_ratio_ = val; + } static double max_touch_down_duration_in_seconds_for_click() { return max_touch_down_duration_in_seconds_for_click_; } @@ -79,6 +85,12 @@ class UI_EXPORT GestureConfiguration { static void set_min_scroll_delta_squared(double val) { min_scroll_delta_squared_ = val; } + static double min_swipe_speed() { + return min_swipe_speed_; + } + static void set_min_swipe_speed(double val) { + min_swipe_speed_ = val; + } static double min_touch_down_duration_in_seconds_for_click() { return min_touch_down_duration_in_seconds_for_click_; } @@ -111,6 +123,7 @@ class UI_EXPORT GestureConfiguration { static double long_press_time_in_seconds_; static double max_seconds_between_double_click_; static double max_separation_for_gesture_touches_in_pixels_; + static double max_swipe_deviation_ratio_; static double max_touch_down_duration_in_seconds_for_click_; static double max_touch_move_in_pixels_for_click_; static double min_distance_for_pinch_scroll_in_pixels_; @@ -118,6 +131,7 @@ class UI_EXPORT GestureConfiguration { static double min_pinch_update_distance_in_pixels_; static double min_rail_break_velocity_; static double min_scroll_delta_squared_; + static double min_swipe_speed_; static double min_touch_down_duration_in_seconds_for_click_; static int points_buffered_for_velocity_; static double rail_break_proportion_; diff --git a/ui/base/gestures/gesture_sequence.cc b/ui/base/gestures/gesture_sequence.cc index 69af3f7..ac619f8 100644 --- a/ui/base/gestures/gesture_sequence.cc +++ b/ui/base/gestures/gesture_sequence.cc @@ -4,6 +4,8 @@ #include "ui/base/gestures/gesture_sequence.h" +#include <cmath> + #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/time.h" @@ -102,6 +104,36 @@ enum EdgeStateSignatureType { GST_PINCH_SECOND_CANCELLED = G(GS_PINCH, 1, TS_CANCELLED, false), + + GST_PINCH_THIRD_PRESSED = + G(GS_PINCH, 2, TS_PRESSED, false), + + GST_THREE_FINGER_SWIPE_FIRST_RELEASED = + G(GS_THREE_FINGER_SWIPE, 0, TS_RELEASED, false), + + GST_THREE_FINGER_SWIPE_SECOND_RELEASED = + G(GS_THREE_FINGER_SWIPE, 1, TS_RELEASED, false), + + GST_THREE_FINGER_SWIPE_THIRD_RELEASED = + G(GS_THREE_FINGER_SWIPE, 2, TS_RELEASED, false), + + GST_THREE_FINGER_SWIPE_FIRST_MOVED = + G(GS_THREE_FINGER_SWIPE, 0, TS_MOVED, false), + + GST_THREE_FINGER_SWIPE_SECOND_MOVED = + G(GS_THREE_FINGER_SWIPE, 1, TS_MOVED, false), + + GST_THREE_FINGER_SWIPE_THIRD_MOVED = + G(GS_THREE_FINGER_SWIPE, 2, TS_MOVED, false), + + GST_THREE_FINGER_SWIPE_FIRST_CANCELLED = + G(GS_THREE_FINGER_SWIPE, 0, TS_CANCELLED, false), + + GST_THREE_FINGER_SWIPE_SECOND_CANCELLED = + G(GS_THREE_FINGER_SWIPE, 1, TS_CANCELLED, false), + + GST_THREE_FINGER_SWIPE_THIRD_CANCELLED = + G(GS_THREE_FINGER_SWIPE, 2, TS_CANCELLED, false), }; // Builds a signature. Signatures are assembled by joining together @@ -227,6 +259,28 @@ GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture( scroll_type_ = ST_FREE; set_state(GS_SCROLL); break; + case GST_PINCH_THIRD_PRESSED: + three_finger_swipe_has_fired_ = false; + set_state(GS_THREE_FINGER_SWIPE); + break; + case GST_THREE_FINGER_SWIPE_FIRST_RELEASED: + case GST_THREE_FINGER_SWIPE_SECOND_RELEASED: + case GST_THREE_FINGER_SWIPE_THIRD_RELEASED: + case GST_THREE_FINGER_SWIPE_FIRST_CANCELLED: + case GST_THREE_FINGER_SWIPE_SECOND_CANCELLED: + case GST_THREE_FINGER_SWIPE_THIRD_CANCELLED: + set_state(GS_PINCH); + break; + case GST_THREE_FINGER_SWIPE_FIRST_MOVED: + case GST_THREE_FINGER_SWIPE_SECOND_MOVED: + case GST_THREE_FINGER_SWIPE_THIRD_MOVED: + if (!three_finger_swipe_has_fired_) { + ThreeFingerSwipeUpdate(event, point, gestures.get()); + GetPointByPointId(0)->UpdateForScroll(); + GetPointByPointId(1)->UpdateForScroll(); + GetPointByPointId(2)->UpdateForScroll(); + } + break; } if (state_ != last_state) @@ -409,6 +463,30 @@ void GestureSequence::AppendPinchGestureUpdate(const GesturePoint& p1, scale, 0.f, 1 << p1.touch_id() | 1 << p2.touch_id()))); } +void GestureSequence::AppendThreeFingerSwipeGestureEvent(const GesturePoint& p1, + const GesturePoint& p2, + const GesturePoint& p3, + float x_velocity, + float y_velocity, + Gestures* gestures) { + int x = ( + p1.last_touch_position().x() + + p2.last_touch_position().x() + + p3.last_touch_position().x()) / 3; + int y = ( + p1.last_touch_position().y() + + p2.last_touch_position().y() + + p3.last_touch_position().y()) / 3; + gfx::Point center(x, y); + gestures->push_back(helper_->CreateGestureEvent( + ui::ET_GESTURE_THREE_FINGER_SWIPE, + center, + flags_, + base::Time::FromDoubleT(p1.last_touch_time()), + x_velocity, y_velocity, + 1 << p1.touch_id() | 1 << p2.touch_id() | 1 << p3.touch_id())); +} + bool GestureSequence::Click(const TouchEvent& event, const GesturePoint& point, Gestures* gestures) { DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK); @@ -569,4 +647,59 @@ bool GestureSequence::PinchEnd(const TouchEvent& event, return true; } +bool GestureSequence::ThreeFingerSwipeUpdate(const TouchEvent& event, + const GesturePoint& point, Gestures* gestures) { + DCHECK(state_ == GS_THREE_FINGER_SWIPE); + + GesturePoint* point1 = GetPointByPointId(0); + GesturePoint* point2 = GetPointByPointId(1); + GesturePoint* point3 = GetPointByPointId(2); + + int min_velocity = GestureConfiguration::min_swipe_speed(); + + float vx1 = point1->XVelocity(); + float vx2 = point2->XVelocity(); + float vx3 = point3->XVelocity(); + float vy1 = point1->YVelocity(); + float vy2 = point2->YVelocity(); + float vy3 = point3->YVelocity(); + + float vx = (vx1 + vx2 + vx3) / 3; + float vy = (vy1 + vy2 + vy3) / 3; + + // Not moving fast enough + if (fabs(vx) < min_velocity && fabs(vy) < min_velocity) + return false; + + // Diagonal swipe, no event fired + // TODO(tdresser|sadrul): consider adding diagonal swipes + float ratio = fabs(vx) > fabs(vy) ? fabs(vx / vy) : fabs(vy / vx); + if (ratio < GestureConfiguration::max_swipe_deviation_ratio()) + return false; + + if (fabs(vx) > fabs(vy)) { + int sign = vx > 0 ? 1 : -1; + // ensure all touches are moving in the same direction, and are + // all moving faster than min_velocity. + if (vx1 * sign < min_velocity || + vx2 * sign < min_velocity || + vx3 * sign < min_velocity) + return false; + AppendThreeFingerSwipeGestureEvent(*point1, *point2, *point3, + sign, 0, gestures); + } else { + int sign = vy > 0 ? 1 : -1; + // ensure all touches are moving in the same direction, and are + // all moving faster than min_velocity. + if (vy1 * sign < min_velocity || + vy2 * sign < min_velocity || + vy3 * sign < min_velocity) + return false; + AppendThreeFingerSwipeGestureEvent(*point1, *point2, *point3, + 0, sign, gestures); + } + three_finger_swipe_has_fired_ = true; + return true; +} + } // namespace ui diff --git a/ui/base/gestures/gesture_sequence.h b/ui/base/gestures/gesture_sequence.h index de829d5..e8d7aab 100644 --- a/ui/base/gestures/gesture_sequence.h +++ b/ui/base/gestures/gesture_sequence.h @@ -20,7 +20,8 @@ enum GestureState { GS_NO_GESTURE, GS_PENDING_SYNTHETIC_CLICK, GS_SCROLL, - GS_PINCH + GS_PINCH, + GS_THREE_FINGER_SWIPE }; enum ScrollType { @@ -99,6 +100,13 @@ class UI_EXPORT GestureSequence { float scale, Gestures* gestures); + void AppendThreeFingerSwipeGestureEvent(const GesturePoint& p1, + const GesturePoint& p2, + const GesturePoint& p3, + float x_velocity, + float y_velocity, + Gestures* gestures); + void set_state(const GestureState state ) { state_ = state; } // Various GestureTransitionFunctions for a signature. @@ -134,6 +142,9 @@ class UI_EXPORT GestureSequence { bool PinchEnd(const TouchEvent& event, const GesturePoint& point, Gestures* gestures); + bool ThreeFingerSwipeUpdate(const TouchEvent& event, + const GesturePoint& point, + Gestures* gestures); // Current state of gesture recognizer. GestureState state_; @@ -148,6 +159,7 @@ class UI_EXPORT GestureSequence { float pinch_distance_current_; ScrollType scroll_type_; + bool three_finger_swipe_has_fired_; scoped_ptr<base::OneShotTimer<GestureSequence> > long_press_timer_; GesturePoint points_[kMaxGesturePoints]; diff --git a/ui/base/gestures/gestures.dot b/ui/base/gestures/gestures.dot index a095575..6e3aa5c 100644 --- a/ui/base/gestures/gestures.dot +++ b/ui/base/gestures/gestures.dot @@ -29,4 +29,8 @@ GS_PENDING_SYNTHETIC_CLICK -> GS_PINCH [label= "D1"]; GS_SCROLL -> GS_PINCH [label= "D1"]; GS_PINCH -> GS_PINCH [label= "M0\n M1"]; GS_PINCH -> GS_SCROLL [label= "C0\n R0\n C1\n R1"]; + +GS_PINCH -> GS_PENDING_THREE_FINGER_SWIPE [label= "D2"]; +GS_PENDING_THREE_FINGER_SWIPE -> GS_PINCH [label= "C0\n R0\n C1\n R1\n C2\n R2"]; +GS_PENDING_THREE_FINGER_SWIPE -> GS_PENDING_THREE_FINGER_SWIPE [label= "M0\n M1\n M2"]; } |