summaryrefslogtreecommitdiffstats
path: root/ui/base/gestures
diff options
context:
space:
mode:
authorvarunjain@chromium.org <varunjain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-05 17:46:38 +0000
committervarunjain@chromium.org <varunjain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-05 17:46:38 +0000
commit00bad32d31ded458795fafd313a6b6463ac398f8 (patch)
treebe1ec495f66d131c21bed365d8725b947ef41a77 /ui/base/gestures
parente93c52bafa312857371b4d47fc5d1a83c5929a68 (diff)
downloadchromium_src-00bad32d31ded458795fafd313a6b6463ac398f8.zip
chromium_src-00bad32d31ded458795fafd313a6b6463ac398f8.tar.gz
chromium_src-00bad32d31ded458795fafd313a6b6463ac398f8.tar.bz2
Add two finger tap gesture to gesture recognizer.
BUG=126058 TEST=none Review URL: https://chromiumcodereview.appspot.com/10447129 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@140553 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/base/gestures')
-rw-r--r--ui/base/gestures/gesture_configuration.cc1
-rw-r--r--ui/base/gestures/gesture_configuration.h11
-rw-r--r--ui/base/gestures/gesture_point.h2
-rw-r--r--ui/base/gestures/gesture_sequence.cc113
-rw-r--r--ui/base/gestures/gesture_sequence.h17
-rw-r--r--ui/base/gestures/gestures.dot11
6 files changed, 147 insertions, 8 deletions
diff --git a/ui/base/gestures/gesture_configuration.cc b/ui/base/gestures/gesture_configuration.cc
index 5752144..b83a64a 100644
--- a/ui/base/gestures/gesture_configuration.cc
+++ b/ui/base/gestures/gesture_configuration.cc
@@ -10,6 +10,7 @@ namespace ui {
// associated list of prefs in gesture_prefs_aura.cc.
int GestureConfiguration::default_radius_ = 15;
double GestureConfiguration::long_press_time_in_seconds_ = 1.0;
+double GestureConfiguration::max_distance_for_two_finger_tap_in_pixels_ = 300;
int GestureConfiguration::max_radius_ = 100;
double GestureConfiguration::max_seconds_between_double_click_ = 0.7;
double
diff --git a/ui/base/gestures/gesture_configuration.h b/ui/base/gestures/gesture_configuration.h
index f491ccd..397dbc6 100644
--- a/ui/base/gestures/gesture_configuration.h
+++ b/ui/base/gestures/gesture_configuration.h
@@ -25,6 +25,12 @@ class UI_EXPORT GestureConfiguration {
static double long_press_time_in_seconds() {
return long_press_time_in_seconds_;
}
+ static double max_distance_for_two_finger_tap_in_pixels() {
+ return max_distance_for_two_finger_tap_in_pixels_;
+ }
+ static void set_max_distance_for_two_finger_tap_in_pixels(double val) {
+ max_distance_for_two_finger_tap_in_pixels_ = val;
+ }
static int max_radius() {
return max_radius_;
}
@@ -131,6 +137,11 @@ class UI_EXPORT GestureConfiguration {
// by the device is the touch center.
static int default_radius_;
+ // The maximum allowed distance between two fingers for a two finger tap. If
+ // the distance between two fingers is greater than this value, we will not
+ // recognize a two finger tap.
+ static double max_distance_for_two_finger_tap_in_pixels_;
+
// The maximum allowed size for the radius of a touch region used in
// forming an ET_GESTURE_TAP event.
static int max_radius_;
diff --git a/ui/base/gestures/gesture_point.h b/ui/base/gestures/gesture_point.h
index 19a8a3c..d019892 100644
--- a/ui/base/gestures/gesture_point.h
+++ b/ui/base/gestures/gesture_point.h
@@ -44,6 +44,7 @@ class GesturePoint {
bool IsInFlickWindow(const TouchEvent& event);
bool IsInHorizontalRailWindow() const;
bool IsInVerticalRailWindow() const;
+ bool IsInsideManhattanSquare(const TouchEvent& event) const;
bool HasEnoughDataToEstablishRail() const;
bool BreaksHorizontalRail();
bool BreaksVerticalRail();
@@ -89,7 +90,6 @@ class GesturePoint {
// Various statistical functions to manipulate gestures.
bool IsInClickTimeWindow() const;
bool IsInSecondClickTimeWindow() const;
- bool IsInsideManhattanSquare(const TouchEvent& event) const;
bool IsSecondClickInsideManhattanSquare(const TouchEvent& event) const;
bool IsOverMinFlickSpeed();
diff --git a/ui/base/gestures/gesture_sequence.cc b/ui/base/gestures/gesture_sequence.cc
index c0441fe..f11d5d1 100644
--- a/ui/base/gestures/gesture_sequence.cc
+++ b/ui/base/gestures/gesture_sequence.cc
@@ -88,6 +88,27 @@ enum EdgeStateSignatureType {
GST_SCROLL_SECOND_PRESSED =
G(GS_SCROLL, 1, TS_PRESSED, false),
+ GST_PENDING_TWO_FINGER_TAP_FIRST_RELEASED =
+ G(GS_PENDING_TWO_FINGER_TAP, 0, TS_RELEASED, false),
+
+ GST_PENDING_TWO_FINGER_TAP_SECOND_RELEASED =
+ G(GS_PENDING_TWO_FINGER_TAP, 1, TS_RELEASED, false),
+
+ GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED =
+ G(GS_PENDING_TWO_FINGER_TAP, 0, TS_MOVED, false),
+
+ GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED =
+ G(GS_PENDING_TWO_FINGER_TAP, 1, TS_MOVED, false),
+
+ GST_PENDING_TWO_FINGER_TAP_FIRST_CANCELLED =
+ G(GS_PENDING_TWO_FINGER_TAP, 0, TS_CANCELLED, false),
+
+ GST_PENDING_TWO_FINGER_TAP_SECOND_CANCELLED =
+ G(GS_PENDING_TWO_FINGER_TAP, 1, TS_CANCELLED, false),
+
+ GST_PENDING_TWO_FINGER_TAP_THIRD_PRESSED =
+ G(GS_PENDING_TWO_FINGER_TAP, 2, TS_PRESSED, false),
+
GST_PINCH_FIRST_MOVED =
G(GS_PINCH, 0, TS_MOVED, false),
@@ -262,8 +283,30 @@ 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.
+ if (IsSecondTouchDownCloseEnoughForTwoFingerTap()) {
+ TwoFingerTouchDown(event, point, gestures.get());
+ set_state(GS_PENDING_TWO_FINGER_TAP);
+ } else {
+ PinchStart(event, point, gestures.get());
+ set_state(GS_PINCH);
+ }
+ break;
+ case GST_PENDING_TWO_FINGER_TAP_FIRST_RELEASED:
+ case GST_PENDING_TWO_FINGER_TAP_SECOND_RELEASED:
+ TwoFingerTouchReleased(event, point, gestures.get());
+ set_state(GS_SCROLL);
+ break;
+ case GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED:
+ case GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED:
+ if (TwoFingerTouchMove(event, point, gestures.get()))
+ set_state(GS_PINCH);
+ break;
+ case GST_PENDING_TWO_FINGER_TAP_FIRST_CANCELLED:
+ case GST_PENDING_TWO_FINGER_TAP_SECOND_CANCELLED:
scroll_type_ = ST_FREE;
+ set_state(GS_SCROLL);
+ break;
+ case GST_PENDING_TWO_FINGER_TAP_THIRD_PRESSED:
PinchStart(event, point, gestures.get());
set_state(GS_PINCH);
break;
@@ -414,6 +457,18 @@ GesturePoint* GestureSequence::GetPointByPointId(int point_id) {
return NULL;
}
+bool GestureSequence::IsSecondTouchDownCloseEnoughForTwoFingerTap() {
+ gfx::Point p1 = GetPointByPointId(0)->last_touch_position();
+ gfx::Point p2 = GetPointByPointId(1)->last_touch_position();
+ double max_distance =
+ ui::GestureConfiguration::max_distance_for_two_finger_tap_in_pixels();
+ double distance = (p1.x() - p2.x()) * (p1.x() - p2.x()) +
+ (p1.y() - p2.y()) * (p1.y() - p2.y());
+ if (distance < max_distance * max_distance)
+ return true;
+ return false;
+}
+
void GestureSequence::AppendTapDownGestureEvent(const GesturePoint& point,
Gestures* gestures) {
gestures->push_back(helper_->CreateGestureEvent(
@@ -581,6 +636,16 @@ void GestureSequence::AppendSwipeGesture(const GesturePoint& point,
swipe_x, swipe_y, ComputeTouchBitmask(points_)));
}
+void GestureSequence::AppendTwoFingerTapGestureEvent(Gestures* gestures) {
+ const GesturePoint* point = GetPointByPointId(0);
+ gestures->push_back(helper_->CreateGestureEvent(
+ ui::ET_GESTURE_TWO_FINGER_TAP,
+ point->enclosing_rectangle().CenterPoint(),
+ flags_,
+ base::Time::FromDoubleT(point->last_touch_time()),
+ 0.f, 0.f, 1 << point->touch_id()));
+}
+
bool GestureSequence::Click(const TouchEvent& event,
const GesturePoint& point, Gestures* gestures) {
DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK);
@@ -649,6 +714,42 @@ bool GestureSequence::TouchDown(const TouchEvent& event,
return true;
}
+bool GestureSequence::TwoFingerTouchDown(const TouchEvent& event,
+ const GesturePoint& point, Gestures* gestures) {
+ DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK || state_ == GS_SCROLL);
+ if (state_ == GS_SCROLL) {
+ AppendScrollGestureEnd(point, point.last_touch_position(), gestures,
+ 0.f, 0.f);
+ }
+ second_touch_time_ = event.GetTimestamp();
+ return true;
+}
+
+bool GestureSequence::TwoFingerTouchMove(const TouchEvent& event,
+ const GesturePoint& point, Gestures* gestures) {
+ DCHECK(state_ == GS_PENDING_TWO_FINGER_TAP);
+
+ base::TimeDelta time_delta = event.GetTimestamp() - second_touch_time_;
+ base::TimeDelta max_delta = base::TimeDelta::FromMilliseconds(1000 *
+ ui::GestureConfiguration::max_touch_down_duration_in_seconds_for_click());
+ if (time_delta > max_delta || !point.IsInsideManhattanSquare(event)) {
+ PinchStart(event, point, gestures);
+ return true;
+ }
+ return false;
+}
+
+bool GestureSequence::TwoFingerTouchReleased(const TouchEvent& event,
+ const GesturePoint& point, Gestures* gestures) {
+ DCHECK(state_ == GS_PENDING_TWO_FINGER_TAP);
+ base::TimeDelta time_delta = event.GetTimestamp() - second_touch_time_;
+ base::TimeDelta max_delta = base::TimeDelta::FromMilliseconds(1000 *
+ ui::GestureConfiguration::max_touch_down_duration_in_seconds_for_click());
+ if (time_delta < max_delta && point.IsInsideManhattanSquare(event))
+ AppendTwoFingerTapGestureEvent(gestures);
+ return true;
+}
+
void GestureSequence::AppendLongPressGestureEvent() {
const GesturePoint* point = GetPointByPointId(0);
scoped_ptr<GestureEvent> gesture(helper_->CreateGestureEvent(
@@ -676,8 +777,11 @@ bool GestureSequence::ScrollEnd(const TouchEvent& event,
bool GestureSequence::PinchStart(const TouchEvent& event,
const GesturePoint& point, Gestures* gestures) {
DCHECK(state_ == GS_SCROLL ||
- state_ == GS_PENDING_SYNTHETIC_CLICK);
- AppendTapDownGestureEvent(point, gestures);
+ state_ == GS_PENDING_SYNTHETIC_CLICK ||
+ state_ == GS_PENDING_TWO_FINGER_TAP);
+
+ // Once pinch starts, we immediately break rail scroll.
+ scroll_type_ = ST_FREE;
const GesturePoint* point1 = GetPointByPointId(0);
const GesturePoint* point2 = GetPointByPointId(1);
@@ -686,7 +790,8 @@ bool GestureSequence::PinchStart(const TouchEvent& event,
pinch_distance_start_ = pinch_distance_current_;
AppendPinchGestureBegin(*point1, *point2, gestures);
- if (state_ == GS_PENDING_SYNTHETIC_CLICK) {
+ if (state_ == GS_PENDING_SYNTHETIC_CLICK ||
+ state_ == GS_PENDING_TWO_FINGER_TAP) {
gfx::Point center = bounding_box_.CenterPoint();
AppendScrollGestureBegin(point, center, gestures);
}
diff --git a/ui/base/gestures/gesture_sequence.h b/ui/base/gestures/gesture_sequence.h
index 0a52578..b976bb3 100644
--- a/ui/base/gestures/gesture_sequence.h
+++ b/ui/base/gestures/gesture_sequence.h
@@ -22,6 +22,7 @@ enum GestureState {
GS_PENDING_SYNTHETIC_CLICK,
GS_SCROLL,
GS_PINCH,
+ GS_PENDING_TWO_FINGER_TAP,
};
enum ScrollType {
@@ -71,6 +72,8 @@ class UI_EXPORT GestureSequence {
// with id |point_id|.
GesturePoint* GetPointByPointId(int point_id);
+ bool IsSecondTouchDownCloseEnoughForTwoFingerTap();
+
// Functions to be called to add GestureEvents, after successful recognition.
// Tap gestures.
@@ -109,6 +112,7 @@ class UI_EXPORT GestureSequence {
int swipe_x,
int swipe_y,
Gestures* gestures);
+ void AppendTwoFingerTapGestureEvent(Gestures* gestures);
void set_state(const GestureState state) { state_ = state; }
@@ -133,6 +137,15 @@ class UI_EXPORT GestureSequence {
bool TouchDown(const TouchEvent& event,
const GesturePoint& point,
Gestures* gestures);
+ bool TwoFingerTouchDown(const TouchEvent& event,
+ const GesturePoint& point,
+ Gestures* gestures);
+ bool TwoFingerTouchMove(const TouchEvent& event,
+ const GesturePoint& point,
+ Gestures* gestures);
+ bool TwoFingerTouchReleased(const TouchEvent& event,
+ const GesturePoint& point,
+ Gestures* gestures);
bool ScrollEnd(const TouchEvent& event,
GesturePoint& point,
Gestures* gestures);
@@ -170,6 +183,10 @@ class UI_EXPORT GestureSequence {
// This distance is updated after each PINCH_UPDATE.
float pinch_distance_current_;
+ // This is the time when second touch down was received. Used for determining
+ // if a two finger double tap has happened.
+ base::TimeDelta second_touch_time_;
+
ScrollType scroll_type_;
scoped_ptr<base::OneShotTimer<GestureSequence> > long_press_timer_;
diff --git a/ui/base/gestures/gestures.dot b/ui/base/gestures/gestures.dot
index 6e3aa5c..868c542 100644
--- a/ui/base/gestures/gestures.dot
+++ b/ui/base/gestures/gestures.dot
@@ -13,7 +13,8 @@ M : Move \l\
D : Down \l\
S : Stationary \l\
C : Cancel \l\
-R : Release \l}"
+R : Release \l\
+M_Delay : Move after a certain delay}"
shape = record]
subgraph none_pending {
@@ -25,8 +26,12 @@ GS_PENDING_SYNTHETIC_CLICK -> GS_NO_GESTURE [label= "C0\n R0"];
GS_SCROLL -> GS_SCROLL [label= "M0"];
GS_SCROLL -> GS_NO_GESTURE [label= "C0\n R0\n"];
-GS_PENDING_SYNTHETIC_CLICK -> GS_PINCH [label= "D1"];
-GS_SCROLL -> GS_PINCH [label= "D1"];
+GS_PENDING_SYNTHETIC_CLICK -> GS_PENDING_TWO_FINGER_TAP [label= "D1"];
+GS_SCROLL -> GS_PENDING_TWO_FINGER_TAP [label= "D1"];
+GS_PENDING_TWO_FINGER_TAP -> GS_PINCH [label= "M0\n M1"];
+GS_PENDING_TWO_FINGER_TAP -> GS_PINCH [label= "M_Delay0\n M_Delay1"];
+GS_PENDING_TWO_FINGER_TAP -> GS_PINCH [label= "D2"];
+GS_PENDING_TWO_FINGER_TAP -> GS_SCROLL [label= "R0\n R1\n C0\n C1"];
GS_PINCH -> GS_PINCH [label= "M0\n M1"];
GS_PINCH -> GS_SCROLL [label= "C0\n R0\n C1\n R1"];