summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortdresser@chromium.org <tdresser@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-17 13:52:45 +0000
committertdresser@chromium.org <tdresser@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-17 13:52:45 +0000
commit93425b44c4ea18ca58e3f5585d92795628bc5355 (patch)
tree0d3c398b08ab343ced67a07c48c229b535a8a1ae
parent1895cda784ed3c8a899379f32b334761d386e6ed (diff)
downloadchromium_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.cc3
-rw-r--r--ash/wm/system_gesture_event_filter_unittest.cc27
-rw-r--r--chrome/browser/ui/gesture_prefs_observer_factory_aura.cc16
-rw-r--r--chrome/common/pref_names.cc4
-rw-r--r--chrome/common/pref_names.h2
-rw-r--r--ui/aura/gestures/gesture_recognizer_unittest.cc194
-rw-r--r--ui/base/events.h1
-rw-r--r--ui/base/gestures/gesture_configuration.cc2
-rw-r--r--ui/base/gestures/gesture_configuration.h14
-rw-r--r--ui/base/gestures/gesture_sequence.cc133
-rw-r--r--ui/base/gestures/gesture_sequence.h14
-rw-r--r--ui/base/gestures/gestures.dot4
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"];
}