summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ash/wm/system_gesture_event_filter.cc129
-rw-r--r--ash/wm/system_gesture_event_filter.h21
-rw-r--r--ash/wm/system_gesture_event_filter_unittest.cc27
-rw-r--r--ui/aura/gestures/gesture_recognizer_unittest.cc232
-rw-r--r--ui/aura/root_window_unittest.cc11
-rw-r--r--ui/aura/window_unittest.cc2
-rw-r--r--ui/base/events.h5
-rw-r--r--ui/base/gestures/gesture_point.cc6
-rw-r--r--ui/base/gestures/gesture_point.h4
-rw-r--r--ui/base/gestures/gesture_sequence.cc364
-rw-r--r--ui/base/gestures/gesture_sequence.h47
11 files changed, 447 insertions, 401 deletions
diff --git a/ash/wm/system_gesture_event_filter.cc b/ash/wm/system_gesture_event_filter.cc
index 7cd673e..639a216 100644
--- a/ash/wm/system_gesture_event_filter.cc
+++ b/ash/wm/system_gesture_event_filter.cc
@@ -4,101 +4,17 @@
#include "ash/wm/system_gesture_event_filter.h"
-#include "ash/accelerators/accelerator_controller.h"
#include "ash/shell.h"
+#include "ash/accelerators/accelerator_controller.h"
#include "ash/system/brightness/brightness_control_delegate.h"
#include "ash/volume_control_delegate.h"
-#include "ash/wm/window_resizer.h"
-#include "ash/wm/window_util.h"
-#include "ash/wm/workspace/snap_sizer.h"
#include "ui/aura/event.h"
#include "ui/aura/root_window.h"
#include "ui/gfx/screen.h"
-#include "ui/views/widget/widget.h"
-#include "ui/views/widget/widget_delegate.h"
-
-namespace {
-
-const int kSystemPinchPoints = 4;
-
-enum SystemGestureStatus {
- SYSTEM_GESTURE_PROCESSED, // The system gesture has been processed.
- SYSTEM_GESTURE_IGNORED, // The system gesture was ignored.
- SYSTEM_GESTURE_END, // Marks the end of the sytem gesture.
-};
-
-aura::Window* GetTargetForSystemGestureEvent(aura::Window* target) {
- aura::Window* system_target = target;
- if (!system_target || system_target == ash::Shell::GetPrimaryRootWindow())
- system_target = ash::wm::GetActiveWindow();
- if (system_target)
- system_target = system_target->GetToplevelWindow();
- return system_target;
-}
-
-}
namespace ash {
namespace internal {
-class SystemPinchHandler {
- public:
- explicit SystemPinchHandler(aura::Window* target)
- : target_(target) {
- widget_ = views::Widget::GetWidgetForNativeWindow(target_);
- }
-
- ~SystemPinchHandler() {
- }
-
- SystemGestureStatus ProcessGestureEvent(const aura::GestureEvent& event) {
- // The target has changed, somehow. Let's bale.
- if (!widget_)
- return SYSTEM_GESTURE_END;
-
- switch (event.type()) {
- case ui::ET_GESTURE_TAP_UP:
- if (event.delta_x() == kSystemPinchPoints) {
- gfx::Rect bounds = target_->bounds();
- int grid = Shell::GetInstance()->GetGridSize();
- bounds.set_x(WindowResizer::AlignToGridRoundUp(bounds.x(), grid));
- bounds.set_y(WindowResizer::AlignToGridRoundUp(bounds.y(), grid));
- target_->SetBounds(bounds);
- return SYSTEM_GESTURE_END;
- }
- break;
-
- case ui::ET_GESTURE_SCROLL_UPDATE: {
- if (wm::IsWindowFullscreen(target_) ||
- !widget_->widget_delegate()->CanResize())
- break;
-
- gfx::Rect bounds = target_->bounds();
- bounds.set_x(static_cast<int>(bounds.x() + event.delta_x()));
- bounds.set_y(static_cast<int>(bounds.y() + event.delta_y()));
- target_->SetBounds(bounds);
- break;
- }
-
- case ui::ET_GESTURE_PINCH_UPDATE: {
- // TODO(sad): Process PINCH_UPDATEs too.
- break;
- }
-
- default:
- break;
- }
-
- return SYSTEM_GESTURE_PROCESSED;
- }
-
- private:
- aura::Window* target_;
- views::Widget* widget_;
-
- DISALLOW_COPY_AND_ASSIGN(SystemPinchHandler);
-};
-
SystemGestureEventFilter::SystemGestureEventFilter()
: aura::EventFilter(),
overlap_percent_(5),
@@ -128,6 +44,9 @@ 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 || target == Shell::GetPrimaryRootWindow()) {
switch (event->type()) {
case ui::ET_GESTURE_SCROLL_BEGIN: {
@@ -183,49 +102,9 @@ ui::GestureStatus SystemGestureEventFilter::PreHandleGestureEvent(
}
return ui::GESTURE_STATUS_CONSUMED;
}
-
- aura::Window* system_target = GetTargetForSystemGestureEvent(target);
- if (!system_target)
- return ui::GESTURE_STATUS_UNKNOWN;
-
- WindowPinchHandlerMap::iterator find = pinch_handlers_.find(system_target);
- if (find != pinch_handlers_.end()) {
- SystemGestureStatus status =
- (*find).second->ProcessGestureEvent(*event);
- if (status == SYSTEM_GESTURE_END)
- ClearGestureHandlerForWindow(system_target);
- return ui::GESTURE_STATUS_CONSUMED;
- } else {
- if (event->type() == ui::ET_GESTURE_TAP_DOWN &&
- event->delta_x() >= kSystemPinchPoints) {
- pinch_handlers_[system_target] = new SystemPinchHandler(system_target);
- system_target->AddObserver(this);
- return ui::GESTURE_STATUS_CONSUMED;
- }
- }
-
return ui::GESTURE_STATUS_UNKNOWN;
}
-void SystemGestureEventFilter::OnWindowVisibilityChanged(aura::Window* window,
- bool visible) {
- if (!visible)
- ClearGestureHandlerForWindow(window);
-}
-
-void SystemGestureEventFilter::OnWindowDestroying(aura::Window* window) {
- ClearGestureHandlerForWindow(window);
-}
-
-void SystemGestureEventFilter::ClearGestureHandlerForWindow(
- aura::Window* window) {
- WindowPinchHandlerMap::iterator find = pinch_handlers_.find(window);
- DCHECK(find != pinch_handlers_.end());
- delete (*find).second;
- pinch_handlers_.erase(find);
- window->RemoveObserver(this);
-}
-
bool SystemGestureEventFilter::HandleDeviceControl(aura::GestureEvent* event) {
gfx::Rect screen = gfx::Screen::GetPrimaryMonitor().bounds();
double percent = 100.0 * (event->y() - screen.y()) / screen.height();
diff --git a/ash/wm/system_gesture_event_filter.h b/ash/wm/system_gesture_event_filter.h
index 08a692c..f240691 100644
--- a/ash/wm/system_gesture_event_filter.h
+++ b/ash/wm/system_gesture_event_filter.h
@@ -8,9 +8,6 @@
#include "ash/shell.h"
#include "ui/aura/event_filter.h"
-#include "ui/aura/window_observer.h"
-
-#include <map>
namespace aura {
class MouseEvent;
@@ -21,8 +18,6 @@ class Window;
namespace ash {
namespace internal {
-class SystemPinchHandler;
-
enum BezelStart {
BEZEL_START_UNSET = 0,
BEZEL_START_TOP,
@@ -38,8 +33,7 @@ enum ScrollOrientation {
};
// An event filter which handles system level gesture events.
-class SystemGestureEventFilter : public aura::EventFilter,
- public aura::WindowObserver {
+class SystemGestureEventFilter : public aura::EventFilter {
public:
SystemGestureEventFilter();
virtual ~SystemGestureEventFilter();
@@ -55,15 +49,7 @@ class SystemGestureEventFilter : public aura::EventFilter,
aura::Window* target,
aura::GestureEvent* event) OVERRIDE;
- // Overridden from aura::WindowObserver.
- virtual void OnWindowVisibilityChanged(aura::Window* window,
- bool visible) OVERRIDE;
- virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
-
private:
- // Removes system-gesture handlers for a window.
- void ClearGestureHandlerForWindow(aura::Window* window);
-
// Handle events meant for volume / brightness. Returns true when no further
// events from this gesture should be sent.
bool HandleDeviceControl(aura::GestureEvent* event);
@@ -76,11 +62,6 @@ class SystemGestureEventFilter : public aura::EventFilter,
// further events from this gesture should be sent.
bool HandleApplicationControl(aura::GestureEvent* event);
- typedef std::map<aura::Window*, SystemPinchHandler*> WindowPinchHandlerMap;
- // Created on demand when a system-level pinch gesture is initiated. Destroyed
- // when the system-level pinch gesture ends for the window.
- WindowPinchHandlerMap pinch_handlers_;
-
// The percentage of the screen to the left and right which belongs to
// device gestures.
const int overlap_percent_;
diff --git a/ash/wm/system_gesture_event_filter_unittest.cc b/ash/wm/system_gesture_event_filter_unittest.cc
index c22b168..ed2fcb8 100644
--- a/ash/wm/system_gesture_event_filter_unittest.cc
+++ b/ash/wm/system_gesture_event_filter_unittest.cc
@@ -130,6 +130,33 @@ 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::GetPrimaryRootWindow();
+
+ 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);
+}
+
// Ensure that the device control operation gets properly handled.
TEST_F(SystemGestureEventFilterTest, DeviceControl) {
aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
diff --git a/ui/aura/gestures/gesture_recognizer_unittest.cc b/ui/aura/gestures/gesture_recognizer_unittest.cc
index 27f64501..be0d51f 100644
--- a/ui/aura/gestures/gesture_recognizer_unittest.cc
+++ b/ui/aura/gestures/gesture_recognizer_unittest.cc
@@ -44,6 +44,7 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
pinch_end_(false),
long_press_(false),
fling_(false),
+ three_finger_swipe_(false),
scroll_x_(0),
scroll_y_(0),
velocity_x_(0),
@@ -66,6 +67,7 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
pinch_end_ = false;
long_press_ = false;
fling_ = false;
+ three_finger_swipe_ = false;
scroll_begin_position_.SetPoint(0, 0);
tap_location_.SetPoint(0, 0);
@@ -89,6 +91,7 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
bool pinch_end() const { return pinch_end_; }
bool long_press() const { return long_press_; }
bool fling() const { return fling_; }
+ bool three_finger_swipe() const { return three_finger_swipe_; }
const gfx::Point scroll_begin_position() const {
return scroll_begin_position_;
@@ -152,7 +155,10 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
EXPECT_TRUE(velocity_x_ != 0 || velocity_y_ != 0);
fling_ = true;
break;
- case ui::ET_GESTURE_TAP_UP:
+ case ui::ET_GESTURE_THREE_FINGER_SWIPE:
+ three_finger_swipe_ = true;
+ velocity_x_ = gesture->delta_x();
+ velocity_y_ = gesture->delta_y();
break;
default:
NOTREACHED();
@@ -172,6 +178,7 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
bool pinch_end_;
bool long_press_;
bool fling_;
+ bool three_finger_swipe_;
gfx::Point scroll_begin_position_;
gfx::Point tap_location_;
@@ -1560,6 +1567,45 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) {
EXPECT_FALSE(delegate->pinch_update());
}
+TEST_F(GestureRecognizerTest, GestureEventPinchScrollOnlyWhenBothFingersMove) {
+ scoped_ptr<GestureEventConsumeDelegate> delegate(
+ new GestureEventConsumeDelegate());
+ const int kWindowWidth = 1000;
+ const int kWindowHeight = 1000;
+ const int kTouchId1 = 3;
+ const int kTouchId2 = 5;
+ gfx::Rect bounds(0, 0, kWindowWidth, kWindowHeight);
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ delegate.get(), -1234, bounds, NULL));
+
+ delegate->Reset();
+ TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(100, 100),
+ kTouchId1, GetTime());
+
+ root_window()->DispatchTouchEvent(&press1);
+
+ delegate->Reset();
+ TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(110, 110),
+ kTouchId2, GetTime());
+ root_window()->DispatchTouchEvent(&press2);
+
+ SendScrollEvents(root_window(), 100, 100, press1.time_stamp(),
+ 1, 10, kTouchId1, 1,
+ ui::GestureConfiguration::points_buffered_for_velocity(),
+ delegate.get());
+
+ SendScrollEvents(root_window(), 110, 110, press1.time_stamp() +
+ base::TimeDelta::FromMilliseconds(1000),
+ 1, 10, kTouchId2, 1,
+ ui::GestureConfiguration::points_buffered_for_velocity(),
+ delegate.get());
+ // At no point were both fingers moving at the same time,
+ // so no scrolling should have occurred
+
+ EXPECT_EQ(0, delegate->scroll_x());
+ EXPECT_EQ(0, delegate->scroll_y());
+}
+
TEST_F(GestureRecognizerTest, GestureEventIgnoresDisconnectedEvents) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
@@ -1707,5 +1753,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/aura/root_window_unittest.cc b/ui/aura/root_window_unittest.cc
index 904ff5f..45b16a7 100644
--- a/ui/aura/root_window_unittest.cc
+++ b/ui/aura/root_window_unittest.cc
@@ -424,9 +424,6 @@ std::string EventTypeToString(ui::EventType type) {
case ui::ET_GESTURE_TAP_DOWN:
return "GESTURE_TAP_DOWN";
- case ui::ET_GESTURE_TAP_UP:
- return "GESTURE_TAP_UP";
-
case ui::ET_GESTURE_DOUBLE_TAP:
return "GESTURE_DOUBLE_TAP";
@@ -470,8 +467,7 @@ TEST_F(RootWindowTest, GestureToMouseEventTest) {
root_window()->DispatchTouchEvent(&touch_pressed_event);
root_window()->DispatchTouchEvent(&touch_released_event);
EXPECT_EQ("TOUCH_PRESSED GESTURE_TAP_DOWN TOUCH_RELEASED GESTURE_TAP "
- "MOUSE_ENTERED MOUSE_MOVED MOUSE_PRESSED MOUSE_RELEASED "
- "GESTURE_TAP_UP",
+ "MOUSE_ENTERED MOUSE_MOVED MOUSE_PRESSED MOUSE_RELEASED",
EventTypesToString(filter->events()));
filter->events().clear();
}
@@ -516,8 +512,7 @@ TEST_F(RootWindowTest, GestureToMouseEventTest) {
TouchEvent touch_event(ui::ET_TOUCH_RELEASED, gfx::Point(300, 201), 1,
base::TimeDelta());
root_window()->DispatchTouchEvent(&touch_event);
- EXPECT_EQ("TOUCH_RELEASED GESTURE_SCROLL_END MOUSE_DRAGGED MOUSE_RELEASED "
- "GESTURE_TAP_UP",
+ EXPECT_EQ("TOUCH_RELEASED GESTURE_SCROLL_END MOUSE_DRAGGED MOUSE_RELEASED",
EventTypesToString(filter->events()));
filter->events().clear();
}
@@ -557,7 +552,7 @@ TEST_F(RootWindowTest, MouseMoveThenTouch) {
root_window()->DispatchTouchEvent(&touch_released_event);
EXPECT_EQ("TOUCH_PRESSED GESTURE_TAP_DOWN TOUCH_RELEASED GESTURE_TAP "
"MOUSE_EXITED MOUSE_ENTERED MOUSE_MOVED MOUSE_PRESSED "
- "MOUSE_RELEASED GESTURE_TAP_UP",
+ "MOUSE_RELEASED",
EventTypesToString(filter->events()));
filter->events().clear();
}
diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc
index 6e5bcbe..6fa116e 100644
--- a/ui/aura/window_unittest.cc
+++ b/ui/aura/window_unittest.cc
@@ -659,7 +659,7 @@ TEST_F(WindowTest, TouchCaptureDoesntCancelCapturedTouches) {
gfx::Point(10, 10), 0, getTime() +
base::TimeDelta::FromMilliseconds(50));
root_window()->DispatchTouchEvent(&release);
- EXPECT_EQ(2, delegate.gesture_event_count());
+ EXPECT_EQ(1, delegate.gesture_event_count());
}
// Changes capture while capture is already ongoing.
diff --git a/ui/base/events.h b/ui/base/events.h
index 6c9f271..e779dbf 100644
--- a/ui/base/events.h
+++ b/ui/base/events.h
@@ -53,15 +53,12 @@ enum EventType {
ET_GESTURE_SCROLL_UPDATE,
ET_GESTURE_TAP,
ET_GESTURE_TAP_DOWN,
- ET_GESTURE_TAP_UP,
ET_GESTURE_DOUBLE_TAP,
ET_GESTURE_PINCH_BEGIN,
ET_GESTURE_PINCH_END,
ET_GESTURE_PINCH_UPDATE,
ET_GESTURE_LONG_PRESS,
- // A SWIPE gesture can happen at the end of a TAP_UP gesture if the
- // finger(s) were moving quickly before they are released.
- ET_GESTURE_MULTIFINGER_SWIPE,
+ 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_point.cc b/ui/base/gestures/gesture_point.cc
index d75250a..6b7dbf1 100644
--- a/ui/base/gestures/gesture_point.cc
+++ b/ui/base/gestures/gesture_point.cc
@@ -99,6 +99,12 @@ bool GesturePoint::DidScroll(const TouchEvent& event, int dist) const {
abs(last_touch_position_.y() - first_touch_position_.y()) > dist;
}
+float GesturePoint::Distance(const GesturePoint& point) const {
+ float x_diff = point.last_touch_position_.x() - last_touch_position_.x();
+ float y_diff = point.last_touch_position_.y() - last_touch_position_.y();
+ return sqrt(x_diff * x_diff + y_diff * y_diff);
+}
+
bool GesturePoint::HasEnoughDataToEstablishRail() const {
int dx = x_delta();
int dy = y_delta();
diff --git a/ui/base/gestures/gesture_point.h b/ui/base/gestures/gesture_point.h
index 19a8a3c..871427b 100644
--- a/ui/base/gestures/gesture_point.h
+++ b/ui/base/gestures/gesture_point.h
@@ -55,8 +55,6 @@ class GesturePoint {
double last_touch_time() const { return last_touch_time_; }
const gfx::Point& last_touch_position() const { return last_touch_position_; }
- int x() const { return last_touch_position_.x(); }
- int y() const { return last_touch_position_.y(); }
// point_id_ is used to drive GestureSequence::ProcessTouchEventForGesture.
// point_ids are maintained such that the set of point_ids is always
@@ -83,6 +81,8 @@ class GesturePoint {
float XVelocity() { return velocity_calculator_.XVelocity(); }
float YVelocity() { return velocity_calculator_.YVelocity(); }
+ float Distance(const GesturePoint& point) const;
+
const gfx::Rect& enclosing_rectangle() const { return enclosing_rect_; }
private:
diff --git a/ui/base/gestures/gesture_sequence.cc b/ui/base/gestures/gesture_sequence.cc
index 5e74aff..02d4b4e 100644
--- a/ui/base/gestures/gesture_sequence.cc
+++ b/ui/base/gestures/gesture_sequence.cc
@@ -109,38 +109,32 @@ enum EdgeStateSignatureType {
GST_PINCH_THIRD_PRESSED =
G(GS_PINCH, 2, TS_PRESSED, false),
- GST_PINCH_THIRD_MOVED =
- G(GS_PINCH, 2, TS_MOVED, false),
+ GST_THREE_FINGER_SWIPE_FIRST_RELEASED =
+ G(GS_THREE_FINGER_SWIPE, 0, TS_RELEASED, false),
- GST_PINCH_THIRD_RELEASED =
- G(GS_PINCH, 2, TS_RELEASED, false),
+ GST_THREE_FINGER_SWIPE_SECOND_RELEASED =
+ G(GS_THREE_FINGER_SWIPE, 1, TS_RELEASED, false),
- GST_PINCH_THIRD_CANCELLED =
- G(GS_PINCH, 2, TS_CANCELLED, false),
+ GST_THREE_FINGER_SWIPE_THIRD_RELEASED =
+ G(GS_THREE_FINGER_SWIPE, 2, TS_RELEASED, false),
- GST_PINCH_FOURTH_PRESSED =
- G(GS_PINCH, 3, TS_PRESSED, false),
+ GST_THREE_FINGER_SWIPE_FIRST_MOVED =
+ G(GS_THREE_FINGER_SWIPE, 0, TS_MOVED, false),
- GST_PINCH_FOURTH_MOVED =
- G(GS_PINCH, 3, TS_MOVED, false),
+ GST_THREE_FINGER_SWIPE_SECOND_MOVED =
+ G(GS_THREE_FINGER_SWIPE, 1, TS_MOVED, false),
- GST_PINCH_FOURTH_RELEASED =
- G(GS_PINCH, 3, TS_RELEASED, false),
+ GST_THREE_FINGER_SWIPE_THIRD_MOVED =
+ G(GS_THREE_FINGER_SWIPE, 2, TS_MOVED, false),
- GST_PINCH_FOURTH_CANCELLED =
- G(GS_PINCH, 3, TS_CANCELLED, false),
+ GST_THREE_FINGER_SWIPE_FIRST_CANCELLED =
+ G(GS_THREE_FINGER_SWIPE, 0, TS_CANCELLED, false),
- GST_PINCH_FIFTH_PRESSED =
- G(GS_PINCH, 4, TS_PRESSED, false),
+ GST_THREE_FINGER_SWIPE_SECOND_CANCELLED =
+ G(GS_THREE_FINGER_SWIPE, 1, TS_CANCELLED, false),
- GST_PINCH_FIFTH_MOVED =
- G(GS_PINCH, 4, TS_MOVED, false),
-
- GST_PINCH_FIFTH_RELEASED =
- G(GS_PINCH, 4, TS_RELEASED, false),
-
- GST_PINCH_FIFTH_CANCELLED =
- G(GS_PINCH, 4, 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
@@ -161,21 +155,6 @@ EdgeStateSignatureType Signature(GestureState gesture_state,
}
#undef G
-float BoundingBoxDiagonal(const gfx::Rect& rect) {
- float width = rect.width() * rect.width();
- float height = rect.height() * rect.height();
- return sqrt(width + height);
-}
-
-unsigned int ComputeTouchBitmask(const GesturePoint* points) {
- unsigned int touch_bitmask = 0;
- for (int i = 0; i < GestureSequence::kMaxGesturePoints; ++i) {
- if (points[i].in_use())
- touch_bitmask |= 1 << points[i].touch_id();
- }
- return touch_bitmask;
-}
-
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -187,6 +166,7 @@ GestureSequence::GestureSequence(GestureEventHelper* helper)
pinch_distance_start_(0.f),
pinch_distance_current_(0.f),
scroll_type_(ST_FREE),
+ three_finger_swipe_has_fired_(false),
long_press_timer_(CreateTimer()),
point_count_(0),
helper_(helper) {
@@ -222,7 +202,6 @@ GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture(
scoped_ptr<Gestures> gestures(new Gestures());
GesturePoint& point = GesturePointForEvent(event);
point.UpdateValues(event);
- RecreateBoundingBox();
flags_ = event.GetEventFlags();
const int point_id = points_[event.GetTouchId()].point_id();
if (point_id < 0)
@@ -262,62 +241,54 @@ 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.
- scroll_type_ = ST_FREE;
PinchStart(event, point, gestures.get());
set_state(GS_PINCH);
break;
case GST_PINCH_FIRST_MOVED:
case GST_PINCH_SECOND_MOVED:
- case GST_PINCH_THIRD_MOVED:
- case GST_PINCH_FOURTH_MOVED:
- case GST_PINCH_FIFTH_MOVED:
if (PinchUpdate(event, point, gestures.get())) {
- for (int i = 0; i < point_count_; ++i)
- GetPointByPointId(i)->UpdateForScroll();
+ GetPointByPointId(0)->UpdateForScroll();
+ GetPointByPointId(1)->UpdateForScroll();
}
break;
case GST_PINCH_FIRST_RELEASED:
case GST_PINCH_SECOND_RELEASED:
- case GST_PINCH_THIRD_RELEASED:
- case GST_PINCH_FOURTH_RELEASED:
- case GST_PINCH_FIFTH_RELEASED:
case GST_PINCH_FIRST_CANCELLED:
case GST_PINCH_SECOND_CANCELLED:
- case GST_PINCH_THIRD_CANCELLED:
- case GST_PINCH_FOURTH_CANCELLED:
- case GST_PINCH_FIFTH_CANCELLED:
- if (point_count_ == 2) {
- PinchEnd(event, point, gestures.get());
-
- // Once pinch ends, it should still be possible to scroll with the
- // remaining finger on the screen.
- set_state(GS_SCROLL);
- } else {
- // Was it a swipe? i.e. were all the fingers moving in the same
- // direction?
- MaybeSwipe(event, point, gestures.get());
-
- // Nothing else to do if we have more than 2 fingers active, since after
- // the release/cancel, there are still enough fingers to do pinch.
- // pinch_distance_current_ and pinch_distance_start_ will be updated
- // when the bounding-box is updated.
- }
- ResetVelocities();
+ PinchEnd(event, point, gestures.get());
+
+ // Once pinch ends, it should still be possible to scroll with the
+ // remaining finger on the screen.
+ scroll_type_ = ST_FREE;
+ set_state(GS_SCROLL);
break;
case GST_PINCH_THIRD_PRESSED:
- case GST_PINCH_FOURTH_PRESSED:
- case GST_PINCH_FIFTH_PRESSED:
- AppendTapDownGestureEvent(point, gestures.get());
- pinch_distance_current_ = BoundingBoxDiagonal(bounding_box_);
- pinch_distance_start_ = pinch_distance_current_;
+ 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:
+ GetPointByPointId(0)->ResetVelocity();
+ GetPointByPointId(1)->ResetVelocity();
+ GetPointByPointId(2)->ResetVelocity();
+ 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 (event.GetEventType() == ui::ET_TOUCH_RELEASED ||
- event.GetEventType() == ui::ET_TOUCH_CANCELLED)
- AppendTapUpGestureEvent(point, gestures.get());
-
if (state_ != last_state)
DVLOG(4) << "Gesture Sequence"
<< " State: " << state_
@@ -338,16 +309,10 @@ GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture(
if (point.point_id() > old_point.point_id())
point.set_point_id(point.point_id() - 1);
}
-
if (old_point.in_use()) {
old_point.Reset();
--point_count_;
DCHECK_GE(point_count_, 0);
- RecreateBoundingBox();
- if (state_ == GS_PINCH) {
- pinch_distance_current_ = BoundingBoxDiagonal(bounding_box_);
- pinch_distance_start_ = pinch_distance_current_;
- }
}
}
@@ -361,33 +326,6 @@ void GestureSequence::Reset() {
point_count_ = 0;
}
-void GestureSequence::RecreateBoundingBox() {
- // TODO(sad): Recreating the bounding box at every touch-event is not very
- // efficient. This should be made better.
- int left = INT_MAX, top = INT_MAX, right = INT_MIN, bottom = INT_MIN;
- for (int i = 0; i < kMaxGesturePoints; ++i) {
- if (!points_[i].in_use())
- continue;
- if (left > points_[i].x())
- left = points_[i].x();
- if (right < points_[i].x())
- right = points_[i].x();
- if (top > points_[i].y())
- top = points_[i].y();
- if (bottom < points_[i].y())
- bottom = points_[i].y();
- }
- bounding_box_last_center_ = bounding_box_.CenterPoint();
- bounding_box_.SetRect(left, top, right - left, bottom - top);
-}
-
-void GestureSequence::ResetVelocities() {
- for (int i = 0; i < kMaxGesturePoints; ++i) {
- if (points_[i].in_use())
- points_[i].ResetVelocity();
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
// GestureSequence Protected:
@@ -421,17 +359,7 @@ void GestureSequence::AppendTapDownGestureEvent(const GesturePoint& point,
point.first_touch_position(),
flags_,
base::Time::FromDoubleT(point.last_touch_time()),
- point_count_, 0.f, 1 << point.touch_id()));
-}
-
-void GestureSequence::AppendTapUpGestureEvent(const GesturePoint& point,
- Gestures* gestures) {
- gestures->push_back(helper_->CreateGestureEvent(
- ui::ET_GESTURE_TAP_UP,
- point.first_touch_position(),
- flags_,
- base::Time::FromDoubleT(point.last_touch_time()),
- point_count_, 0.f, 1 << point.touch_id()));
+ 0.f, 0.f, 1 << point.touch_id()));
}
void GestureSequence::AppendClickGestureEvent(const GesturePoint& point,
@@ -508,10 +436,9 @@ void GestureSequence::AppendScrollGestureEnd(const GesturePoint& point,
void GestureSequence::AppendScrollGestureUpdate(const GesturePoint& point,
const gfx::Point& location,
Gestures* gestures) {
- int dx = location.x() - bounding_box_last_center_.x();
- int dy = location.y() - bounding_box_last_center_.y();
- if (dx == 0 && dy == 0)
- return;
+ int dx = point.x_delta();
+ int dy = point.y_delta();
+
if (scroll_type_ == ST_HORIZONTAL)
dy = 0;
else if (scroll_type_ == ST_VERTICAL)
@@ -522,13 +449,13 @@ void GestureSequence::AppendScrollGestureUpdate(const GesturePoint& point,
location,
flags_,
base::Time::FromDoubleT(point.last_touch_time()),
- dx, dy, ComputeTouchBitmask(points_)));
+ dx, dy, 1 << point.touch_id()));
}
void GestureSequence::AppendPinchGestureBegin(const GesturePoint& p1,
const GesturePoint& p2,
Gestures* gestures) {
- gfx::Point center = bounding_box_.CenterPoint();
+ gfx::Point center = p1.last_touch_position().Middle(p2.last_touch_position());
gestures->push_back(helper_->CreateGestureEvent(
ui::ET_GESTURE_PINCH_BEGIN,
center,
@@ -541,40 +468,52 @@ void GestureSequence::AppendPinchGestureEnd(const GesturePoint& p1,
const GesturePoint& p2,
float scale,
Gestures* gestures) {
- gfx::Point center = bounding_box_.CenterPoint();
+ gfx::Point center = p1.last_touch_position().Middle(p2.last_touch_position());
gestures->push_back(helper_->CreateGestureEvent(
ui::ET_GESTURE_PINCH_END,
center,
flags_,
base::Time::FromDoubleT(p1.last_touch_time()),
- 0.f, 0.f,
- 1 << p1.touch_id() | 1 << p2.touch_id()));
+ scale, 0.f, 1 << p1.touch_id() | 1 << p2.touch_id()));
}
-void GestureSequence::AppendPinchGestureUpdate(const GesturePoint& point,
+void GestureSequence::AppendPinchGestureUpdate(const GesturePoint& p1,
+ const GesturePoint& p2,
float scale,
Gestures* gestures) {
// TODO(sad): Compute rotation and include it in delta_y.
// http://crbug.com/113145
+ gfx::Point center = p1.last_touch_position().Middle(p2.last_touch_position());
gestures->push_back(helper_->CreateGestureEvent(
ui::ET_GESTURE_PINCH_UPDATE,
- bounding_box_.CenterPoint(),
+ center,
flags_,
- base::Time::FromDoubleT(point.last_touch_time()),
- scale, 0.f,
- ComputeTouchBitmask(points_)));
-}
-
-void GestureSequence::AppendSwipeGesture(const GesturePoint& point,
- int swipe_x,
- int swipe_y,
- Gestures* gestures) {
+ base::Time::FromDoubleT(p1.last_touch_time()),
+ 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_MULTIFINGER_SWIPE,
- bounding_box_.CenterPoint(),
+ ui::ET_GESTURE_THREE_FINGER_SWIPE,
+ center,
flags_,
- base::Time::FromDoubleT(point.last_touch_time()),
- swipe_x, swipe_y, ComputeTouchBitmask(points_)));
+ 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,
@@ -678,12 +617,13 @@ bool GestureSequence::PinchStart(const TouchEvent& event,
const GesturePoint* point1 = GetPointByPointId(0);
const GesturePoint* point2 = GetPointByPointId(1);
- pinch_distance_current_ = BoundingBoxDiagonal(bounding_box_);
+ pinch_distance_current_ = point1->Distance(*point2);
pinch_distance_start_ = pinch_distance_current_;
AppendPinchGestureBegin(*point1, *point2, gestures);
if (state_ == GS_PENDING_SYNTHETIC_CLICK) {
- gfx::Point center = bounding_box_.CenterPoint();
+ gfx::Point center = point1->last_touch_position().Middle(
+ point2->last_touch_position());
AppendScrollGestureBegin(point, center, gestures);
}
@@ -694,18 +634,29 @@ bool GestureSequence::PinchUpdate(const TouchEvent& event,
const GesturePoint& point, Gestures* gestures) {
DCHECK(state_ == GS_PINCH);
- float distance = BoundingBoxDiagonal(bounding_box_);
+ const GesturePoint* point1 = GetPointByPointId(0);
+ const GesturePoint* point2 = GetPointByPointId(1);
- if (abs(distance - pinch_distance_current_) >=
+ float distance = point1->Distance(*point2);
+ if (abs(distance - pinch_distance_current_) <
GestureConfiguration::min_pinch_update_distance_in_pixels()) {
- AppendPinchGestureUpdate(point,
+ // The fingers didn't move towards each other, or away from each other,
+ // enough to constitute a pinch. But perhaps they moved enough in the same
+ // direction to do a two-finger scroll.
+ if (!point1->DidScroll(event,
+ GestureConfiguration::min_distance_for_pinch_scroll_in_pixels()) ||
+ !point2->DidScroll(event,
+ GestureConfiguration::min_distance_for_pinch_scroll_in_pixels()))
+ return false;
+
+ gfx::Point center = point1->last_touch_position().Middle(
+ point2->last_touch_position());
+ AppendScrollGestureUpdate(point, center, gestures);
+ } else {
+ AppendPinchGestureUpdate(*point1, *point2,
distance / pinch_distance_current_, gestures);
pinch_distance_current_ = distance;
- } else {
- gfx::Point center = bounding_box_.CenterPoint();
- AppendScrollGestureUpdate(point, center, gestures);
}
-
return true;
}
@@ -716,79 +667,70 @@ bool GestureSequence::PinchEnd(const TouchEvent& event,
GesturePoint* point1 = GetPointByPointId(0);
GesturePoint* point2 = GetPointByPointId(1);
- float distance = BoundingBoxDiagonal(bounding_box_);
+ float distance = point1->Distance(*point2);
AppendPinchGestureEnd(*point1, *point2,
distance / pinch_distance_start_, gestures);
+ point1->ResetVelocity();
+ point2->ResetVelocity();
+
pinch_distance_start_ = 0;
pinch_distance_current_ = 0;
return true;
}
-bool GestureSequence::MaybeSwipe(const TouchEvent& event,
- const GesturePoint& point,
- Gestures* gestures) {
- DCHECK(state_ == GS_PINCH);
- float velocity_x = 0.f, velocity_y = 0.f;
- bool swipe_x = true, swipe_y = true;
- int sign_x = 0, sign_y = 0;
- int i = 0;
-
- for (i = 0; i < kMaxGesturePoints; ++i) {
- if (points_[i].in_use())
- break;
- }
- DCHECK(i < kMaxGesturePoints);
-
- velocity_x = points_[i].XVelocity();
- velocity_y = points_[i].YVelocity();
- sign_x = velocity_x < 0 ? -1 : 1;
- sign_y = velocity_y < 0 ? -1 : 1;
-
- for (++i; i < kMaxGesturePoints; ++i) {
- if (!points_[i].in_use())
- continue;
-
- if (sign_x * points_[i].XVelocity() < 0)
- swipe_x = false;
+bool GestureSequence::ThreeFingerSwipeUpdate(const TouchEvent& event,
+ const GesturePoint& point, Gestures* gestures) {
+ DCHECK(state_ == GS_THREE_FINGER_SWIPE);
- if (sign_y * points_[i].YVelocity() < 0)
- swipe_y = false;
+ GesturePoint* point1 = GetPointByPointId(0);
+ GesturePoint* point2 = GetPointByPointId(1);
+ GesturePoint* point3 = GetPointByPointId(2);
- velocity_x += points_[i].XVelocity();
- velocity_y += points_[i].YVelocity();
- }
+ int min_velocity = GestureConfiguration::min_swipe_speed();
- float min_velocity = GestureConfiguration::min_swipe_speed();
- min_velocity *= min_velocity;
+ float vx1 = point1->XVelocity();
+ float vx2 = point2->XVelocity();
+ float vx3 = point3->XVelocity();
+ float vy1 = point1->YVelocity();
+ float vy2 = point2->YVelocity();
+ float vy3 = point3->YVelocity();
- velocity_x = fabs(velocity_x / point_count_);
- velocity_y = fabs(velocity_y / point_count_);
- if (velocity_x < min_velocity)
- swipe_x = false;
- if (velocity_y < min_velocity)
- swipe_y = false;
+ float vx = (vx1 + vx2 + vx3) / 3;
+ float vy = (vy1 + vy2 + vy3) / 3;
- if (!swipe_x && !swipe_y)
+ // Not moving fast enough
+ if (fabs(vx) < min_velocity && fabs(vy) < min_velocity)
return false;
- if (!swipe_x)
- velocity_x = 0.001f;
- if (!swipe_y)
- velocity_y = 0.001f;
-
- float ratio = velocity_x > velocity_y ? velocity_x / velocity_y :
- velocity_y / velocity_x;
+ // 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 (velocity_x > velocity_y)
- sign_y = 0;
- else
- sign_x = 0;
-
- AppendSwipeGesture(point, sign_x, sign_y, gestures);
-
+ 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;
}
diff --git a/ui/base/gestures/gesture_sequence.h b/ui/base/gestures/gesture_sequence.h
index b8a9a02..e8d7aab 100644
--- a/ui/base/gestures/gesture_sequence.h
+++ b/ui/base/gestures/gesture_sequence.h
@@ -10,7 +10,6 @@
#include "ui/base/events.h"
#include "ui/base/gestures/gesture_point.h"
#include "ui/base/gestures/gesture_recognizer.h"
-#include "ui/gfx/rect.h"
namespace ui {
class TouchEvent;
@@ -22,6 +21,7 @@ enum GestureState {
GS_PENDING_SYNTHETIC_CLICK,
GS_SCROLL,
GS_PINCH,
+ GS_THREE_FINGER_SWIPE
};
enum ScrollType {
@@ -59,12 +59,6 @@ class UI_EXPORT GestureSequence {
private:
void Reset();
- // Recreates the axis-aligned bounding box that contains all the touch-points
- // at their most recent position.
- void RecreateBoundingBox();
-
- void ResetVelocities();
-
GesturePoint& GesturePointForEvent(const TouchEvent& event);
// Do a linear scan through points_ to find the GesturePoint
@@ -75,7 +69,6 @@ class UI_EXPORT GestureSequence {
// Tap gestures.
void AppendTapDownGestureEvent(const GesturePoint& point, Gestures* gestures);
- void AppendTapUpGestureEvent(const GesturePoint& point, Gestures* gestures);
void AppendClickGestureEvent(const GesturePoint& point, Gestures* gestures);
void AppendDoubleClickGestureEvent(const GesturePoint& point,
Gestures* gestures);
@@ -102,13 +95,17 @@ class UI_EXPORT GestureSequence {
const GesturePoint& p2,
float scale,
Gestures* gestures);
- void AppendPinchGestureUpdate(const GesturePoint& point,
+ void AppendPinchGestureUpdate(const GesturePoint& p1,
+ const GesturePoint& p2,
float scale,
Gestures* gestures);
- void AppendSwipeGesture(const GesturePoint& point,
- int swipe_x,
- int swipe_y,
- 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; }
@@ -119,11 +116,11 @@ class UI_EXPORT GestureSequence {
const GesturePoint& point,
Gestures* gestures);
bool ScrollStart(const TouchEvent& event,
- GesturePoint& point,
- Gestures* gestures);
+ GesturePoint& point,
+ Gestures* gestures);
void BreakRailScroll(const TouchEvent& event,
- GesturePoint& point,
- Gestures* gestures);
+ GesturePoint& point,
+ Gestures* gestures);
bool ScrollUpdate(const TouchEvent& event,
const GesturePoint& point,
Gestures* gestures);
@@ -145,9 +142,9 @@ class UI_EXPORT GestureSequence {
bool PinchEnd(const TouchEvent& event,
const GesturePoint& point,
Gestures* gestures);
- bool MaybeSwipe(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_;
@@ -155,15 +152,6 @@ class UI_EXPORT GestureSequence {
// ui::EventFlags.
int flags_;
- // We maintain the smallest axis-aligned rectangle that contains all the
- // current touch-points. The 'distance' represents the diagonal distance.
- // This box is updated after every touch-event.
- gfx::Rect bounding_box_;
- gfx::Point bounding_box_last_center_;
-
- // For pinch, the 'distance' represents the diagonal distance of
- // |bounding_box_|.
-
// The distance between the two points at PINCH_START.
float pinch_distance_start_;
@@ -171,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];