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 {
UMA_ET_GESTURE_BEGIN,
UMA_ET_GESTURE_END,
UMA_ET_GESTURE_DOUBLE_TAP,
UMA_ET_GESTURE_TRIPLE_TAP,
UMA_ET_GESTURE_TWO_FINGER_TAP,
UMA_ET_GESTURE_PINCH_BEGIN,
UMA_ET_GESTURE_PINCH_END,
......@@ -201,8 +202,10 @@ UMAEventType UMAEventTypeFromEvent(const ui::Event& event) {
int tap_count = gesture.details().tap_count();
if (tap_count == 1)
return UMA_ET_GESTURE_TAP;
else if (tap_count == 2)
if (tap_count == 2)
return UMA_ET_GESTURE_DOUBLE_TAP;
if (tap_count == 3)
return UMA_ET_GESTURE_TRIPLE_TAP;
NOTREACHED() << "Received tap with tapcount " << tap_count;
return UMA_ET_UNKNOWN;
}
......
......@@ -2939,6 +2939,61 @@ TEST_F(GestureRecognizerTest, GestureEventDoubleTap) {
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.
TEST_F(GestureRecognizerTest, TwoTapsFarApart) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
......
......@@ -19,6 +19,7 @@ GesturePoint::GesturePoint()
: first_touch_time_(0.0),
second_last_touch_time_(0.0),
last_touch_time_(0.0),
second_last_tap_time_(0.0),
last_tap_time_(0.0),
velocity_calculator_(
GestureConfiguration::points_buffered_for_velocity()),
......@@ -76,6 +77,8 @@ void GesturePoint::UpdateValues(const TouchEvent& event) {
void GesturePoint::UpdateForTap() {
// 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_position_ = last_touch_position_;
}
......@@ -91,8 +94,16 @@ bool GesturePoint::IsInClickWindow(const TouchEvent& event) const {
}
bool GesturePoint::IsInDoubleClickWindow(const TouchEvent& event) const {
return IsInSecondClickTimeWindow() &&
IsSecondClickInsideManhattanSquare(event);
return IsInClickAggregateTimeWindow(last_tap_time_, last_touch_time_) &&
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 {
......@@ -161,8 +172,9 @@ bool GesturePoint::IsInClickTimeWindow() const {
GestureConfiguration::max_touch_down_duration_in_seconds_for_click();
}
bool GesturePoint::IsInSecondClickTimeWindow() const {
double duration = last_touch_time_ - last_tap_time_;
bool GesturePoint::IsInClickAggregateTimeWindow(double before,
double after) const {
double duration = after - before;
return duration < GestureConfiguration::max_seconds_between_double_click();
}
......@@ -171,10 +183,9 @@ bool GesturePoint::IsInsideManhattanSquare(const TouchEvent& event) const {
first_touch_position_);
}
bool GesturePoint::IsSecondClickInsideManhattanSquare(
const TouchEvent& event) const {
int manhattan_distance = abs(event.location().x() - last_tap_position_.x()) +
abs(event.location().y() - last_tap_position_.y());
bool GesturePoint::IsPointInsideManhattanSquare(gfx::Point p1,
gfx::Point p2) const {
int manhattan_distance = abs(p1.x() - p2.x()) + abs(p1.y() - p2.y());
return manhattan_distance <
GestureConfiguration::max_distance_between_taps_for_double_tap();
}
......
......@@ -39,6 +39,7 @@ class GesturePoint {
// represent a click or scroll etc.)
bool IsInClickWindow(const TouchEvent& event) const;
bool IsInDoubleClickWindow(const TouchEvent& event) const;
bool IsInTripleClickWindow(const TouchEvent& event) const;
bool IsInScrollWindow(const TouchEvent& event) const;
bool IsInFlickWindow(const TouchEvent& event);
bool IsInHorizontalRailWindow() const;
......@@ -85,8 +86,8 @@ class GesturePoint {
private:
// Various statistical functions to manipulate gestures.
bool IsInClickTimeWindow() const;
bool IsInSecondClickTimeWindow() const;
bool IsSecondClickInsideManhattanSquare(const TouchEvent& event) const;
bool IsInClickAggregateTimeWindow(double before, double after) const;
bool IsPointInsideManhattanSquare(gfx::Point p1, gfx::Point p2) const;
bool IsOverMinFlickSpeed();
// Returns -1, 0, 1 for |v| below the negative velocity threshold,
......@@ -112,6 +113,9 @@ class GesturePoint {
gfx::Point last_touch_position_;
double last_touch_time_;
double second_last_tap_time_;
gfx::Point second_last_tap_position_;
double last_tap_time_;
gfx::Point last_tap_position_;
......
......@@ -847,8 +847,12 @@ bool GestureSequence::Click(const TouchEvent& event,
Gestures* gestures) {
DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK);
if (point.IsInClickWindow(event)) {
bool double_tap = point.IsInDoubleClickWindow(event);
AppendClickGestureEvent(point, double_tap ? 2 : 1, gestures);
int tap_count = 1;
if (point.IsInTripleClickWindow(event))
tap_count = 3;
else if (point.IsInDoubleClickWindow(event))
tap_count = 2;
AppendClickGestureEvent(point, tap_count, gestures);
return true;
} else if (point.IsInsideManhattanSquare(event) &&
!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