Commit a649b5e5 authored by miletus@chromium.org's avatar miletus@chromium.org

Generate tap gesture with tap_count = 3 for triple-tap

This is to make triple-tap select a paragraph.

BUG=236402
TEST=triple-tap on a paragraph and make sure the whole paragraph is
     selected.

Review URL: https://chromiumcodereview.appspot.com/16018006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@202735 0039d316-1c4b-4281-b951-d872f2087c98
parent 8400e469
...@@ -57,6 +57,7 @@ enum UMAEventType { ...@@ -57,6 +57,7 @@ enum UMAEventType {
UMA_ET_GESTURE_BEGIN, UMA_ET_GESTURE_BEGIN,
UMA_ET_GESTURE_END, UMA_ET_GESTURE_END,
UMA_ET_GESTURE_DOUBLE_TAP, UMA_ET_GESTURE_DOUBLE_TAP,
UMA_ET_GESTURE_TRIPLE_TAP,
UMA_ET_GESTURE_TWO_FINGER_TAP, UMA_ET_GESTURE_TWO_FINGER_TAP,
UMA_ET_GESTURE_PINCH_BEGIN, UMA_ET_GESTURE_PINCH_BEGIN,
UMA_ET_GESTURE_PINCH_END, UMA_ET_GESTURE_PINCH_END,
...@@ -201,8 +202,10 @@ UMAEventType UMAEventTypeFromEvent(const ui::Event& event) { ...@@ -201,8 +202,10 @@ UMAEventType UMAEventTypeFromEvent(const ui::Event& event) {
int tap_count = gesture.details().tap_count(); int tap_count = gesture.details().tap_count();
if (tap_count == 1) if (tap_count == 1)
return UMA_ET_GESTURE_TAP; return UMA_ET_GESTURE_TAP;
else if (tap_count == 2) if (tap_count == 2)
return UMA_ET_GESTURE_DOUBLE_TAP; return UMA_ET_GESTURE_DOUBLE_TAP;
if (tap_count == 3)
return UMA_ET_GESTURE_TRIPLE_TAP;
NOTREACHED() << "Received tap with tapcount " << tap_count; NOTREACHED() << "Received tap with tapcount " << tap_count;
return UMA_ET_UNKNOWN; return UMA_ET_UNKNOWN;
} }
......
...@@ -2939,6 +2939,61 @@ TEST_F(GestureRecognizerTest, GestureEventDoubleTap) { ...@@ -2939,6 +2939,61 @@ TEST_F(GestureRecognizerTest, GestureEventDoubleTap) {
EXPECT_EQ(2, delegate->tap_count()); EXPECT_EQ(2, delegate->tap_count());
} }
// Check that appropriate touch events generate triple tap gesture events.
TEST_F(GestureRecognizerTest, GestureEventTripleTap) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
const int kWindowWidth = 123;
const int kWindowHeight = 45;
const int kTouchId = 2;
gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
delegate.get(), -1234, bounds, root_window()));
TimedEvents tes;
// First tap (tested in GestureEventTap)
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(104, 201),
kTouchId, tes.Now());
root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(104, 201),
kTouchId, tes.LeapForward(50));
root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
EXPECT_EQ(1, delegate->tap_count());
delegate->Reset();
// Second tap (tested in GestureEventDoubleTap)
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(101, 203),
kTouchId, tes.LeapForward(200));
root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(102, 206),
kTouchId, tes.LeapForward(50));
root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2);
EXPECT_EQ(2, delegate->tap_count());
delegate->Reset();
// Third tap
ui::TouchEvent press3(ui::ET_TOUCH_PRESSED, gfx::Point(102, 206),
kTouchId, tes.LeapForward(200));
root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press3);
ui::TouchEvent release3(ui::ET_TOUCH_RELEASED, gfx::Point(102, 206),
kTouchId, tes.LeapForward(50));
root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release3);
EXPECT_TRUE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
EXPECT_TRUE(delegate->begin());
EXPECT_TRUE(delegate->end());
EXPECT_FALSE(delegate->scroll_begin());
EXPECT_FALSE(delegate->scroll_update());
EXPECT_FALSE(delegate->scroll_end());
EXPECT_EQ(3, delegate->tap_count());
}
// Check that we don't get a double tap when the two taps are far apart. // Check that we don't get a double tap when the two taps are far apart.
TEST_F(GestureRecognizerTest, TwoTapsFarApart) { TEST_F(GestureRecognizerTest, TwoTapsFarApart) {
scoped_ptr<GestureEventConsumeDelegate> delegate( scoped_ptr<GestureEventConsumeDelegate> delegate(
......
...@@ -19,6 +19,7 @@ GesturePoint::GesturePoint() ...@@ -19,6 +19,7 @@ GesturePoint::GesturePoint()
: first_touch_time_(0.0), : first_touch_time_(0.0),
second_last_touch_time_(0.0), second_last_touch_time_(0.0),
last_touch_time_(0.0), last_touch_time_(0.0),
second_last_tap_time_(0.0),
last_tap_time_(0.0), last_tap_time_(0.0),
velocity_calculator_( velocity_calculator_(
GestureConfiguration::points_buffered_for_velocity()), GestureConfiguration::points_buffered_for_velocity()),
...@@ -76,6 +77,8 @@ void GesturePoint::UpdateValues(const TouchEvent& event) { ...@@ -76,6 +77,8 @@ void GesturePoint::UpdateValues(const TouchEvent& event) {
void GesturePoint::UpdateForTap() { void GesturePoint::UpdateForTap() {
// Update the tap-position and time, and reset every other state. // Update the tap-position and time, and reset every other state.
second_last_tap_position_ = last_tap_position_;
second_last_tap_time_ = last_tap_time_;
last_tap_time_ = last_touch_time_; last_tap_time_ = last_touch_time_;
last_tap_position_ = last_touch_position_; last_tap_position_ = last_touch_position_;
} }
...@@ -91,8 +94,16 @@ bool GesturePoint::IsInClickWindow(const TouchEvent& event) const { ...@@ -91,8 +94,16 @@ bool GesturePoint::IsInClickWindow(const TouchEvent& event) const {
} }
bool GesturePoint::IsInDoubleClickWindow(const TouchEvent& event) const { bool GesturePoint::IsInDoubleClickWindow(const TouchEvent& event) const {
return IsInSecondClickTimeWindow() && return IsInClickAggregateTimeWindow(last_tap_time_, last_touch_time_) &&
IsSecondClickInsideManhattanSquare(event); IsPointInsideManhattanSquare(event.location(), last_tap_position_);
}
bool GesturePoint::IsInTripleClickWindow(const TouchEvent& event) const {
return IsInClickAggregateTimeWindow(last_tap_time_, last_touch_time_) &&
IsInClickAggregateTimeWindow(second_last_tap_time_, last_tap_time_) &&
IsPointInsideManhattanSquare(event.location(), last_tap_position_) &&
IsPointInsideManhattanSquare(last_tap_position_,
second_last_tap_position_);
} }
bool GesturePoint::IsInScrollWindow(const TouchEvent& event) const { bool GesturePoint::IsInScrollWindow(const TouchEvent& event) const {
...@@ -161,8 +172,9 @@ bool GesturePoint::IsInClickTimeWindow() const { ...@@ -161,8 +172,9 @@ bool GesturePoint::IsInClickTimeWindow() const {
GestureConfiguration::max_touch_down_duration_in_seconds_for_click(); GestureConfiguration::max_touch_down_duration_in_seconds_for_click();
} }
bool GesturePoint::IsInSecondClickTimeWindow() const { bool GesturePoint::IsInClickAggregateTimeWindow(double before,
double duration = last_touch_time_ - last_tap_time_; double after) const {
double duration = after - before;
return duration < GestureConfiguration::max_seconds_between_double_click(); return duration < GestureConfiguration::max_seconds_between_double_click();
} }
...@@ -171,10 +183,9 @@ bool GesturePoint::IsInsideManhattanSquare(const TouchEvent& event) const { ...@@ -171,10 +183,9 @@ bool GesturePoint::IsInsideManhattanSquare(const TouchEvent& event) const {
first_touch_position_); first_touch_position_);
} }
bool GesturePoint::IsSecondClickInsideManhattanSquare( bool GesturePoint::IsPointInsideManhattanSquare(gfx::Point p1,
const TouchEvent& event) const { gfx::Point p2) const {
int manhattan_distance = abs(event.location().x() - last_tap_position_.x()) + int manhattan_distance = abs(p1.x() - p2.x()) + abs(p1.y() - p2.y());
abs(event.location().y() - last_tap_position_.y());
return manhattan_distance < return manhattan_distance <
GestureConfiguration::max_distance_between_taps_for_double_tap(); GestureConfiguration::max_distance_between_taps_for_double_tap();
} }
......
...@@ -39,6 +39,7 @@ class GesturePoint { ...@@ -39,6 +39,7 @@ class GesturePoint {
// represent a click or scroll etc.) // represent a click or scroll etc.)
bool IsInClickWindow(const TouchEvent& event) const; bool IsInClickWindow(const TouchEvent& event) const;
bool IsInDoubleClickWindow(const TouchEvent& event) const; bool IsInDoubleClickWindow(const TouchEvent& event) const;
bool IsInTripleClickWindow(const TouchEvent& event) const;
bool IsInScrollWindow(const TouchEvent& event) const; bool IsInScrollWindow(const TouchEvent& event) const;
bool IsInFlickWindow(const TouchEvent& event); bool IsInFlickWindow(const TouchEvent& event);
bool IsInHorizontalRailWindow() const; bool IsInHorizontalRailWindow() const;
...@@ -85,8 +86,8 @@ class GesturePoint { ...@@ -85,8 +86,8 @@ class GesturePoint {
private: private:
// Various statistical functions to manipulate gestures. // Various statistical functions to manipulate gestures.
bool IsInClickTimeWindow() const; bool IsInClickTimeWindow() const;
bool IsInSecondClickTimeWindow() const; bool IsInClickAggregateTimeWindow(double before, double after) const;
bool IsSecondClickInsideManhattanSquare(const TouchEvent& event) const; bool IsPointInsideManhattanSquare(gfx::Point p1, gfx::Point p2) const;
bool IsOverMinFlickSpeed(); bool IsOverMinFlickSpeed();
// Returns -1, 0, 1 for |v| below the negative velocity threshold, // Returns -1, 0, 1 for |v| below the negative velocity threshold,
...@@ -112,6 +113,9 @@ class GesturePoint { ...@@ -112,6 +113,9 @@ class GesturePoint {
gfx::Point last_touch_position_; gfx::Point last_touch_position_;
double last_touch_time_; double last_touch_time_;
double second_last_tap_time_;
gfx::Point second_last_tap_position_;
double last_tap_time_; double last_tap_time_;
gfx::Point last_tap_position_; gfx::Point last_tap_position_;
......
...@@ -847,8 +847,12 @@ bool GestureSequence::Click(const TouchEvent& event, ...@@ -847,8 +847,12 @@ bool GestureSequence::Click(const TouchEvent& event,
Gestures* gestures) { Gestures* gestures) {
DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK); DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK);
if (point.IsInClickWindow(event)) { if (point.IsInClickWindow(event)) {
bool double_tap = point.IsInDoubleClickWindow(event); int tap_count = 1;
AppendClickGestureEvent(point, double_tap ? 2 : 1, gestures); if (point.IsInTripleClickWindow(event))
tap_count = 3;
else if (point.IsInDoubleClickWindow(event))
tap_count = 2;
AppendClickGestureEvent(point, tap_count, gestures);
return true; return true;
} else if (point.IsInsideManhattanSquare(event) && } else if (point.IsInsideManhattanSquare(event) &&
!GetLongPressTimer()->IsRunning()) { !GetLongPressTimer()->IsRunning()) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment