Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(349)

Side by Side Diff: ui/views/touchui/gesture_recognizer.cc

Issue 9076002: Initial views touchui Gesture Recognizer support (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix win release build Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/views/touchui/gesture_recognizer.h ('k') | ui/views/view.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/views/touchui/gesture_recognizer.h"
6
7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "ui/views/events/event.h"
10
11 namespace {
12 // TODO(Gajen): Make these configurable in sync with this CL http://code.google.
13 // com/p/chromium/issues/detail?id=100773.
14 const double kMaximumTouchDownDurationInSecondsForClick = 0.8;
15 const double kMinimumTouchDownDurationInSecondsForClick = 0.01;
16 const double kMaximumSecondsBetweenDoubleClick = 0.7;
17 const int kMaximumTouchMoveInPixelsForClick = 20;
18 const float kMinFlickSpeedSquared = 550.f * 550.f;
19
20 } // namespace
21
22 namespace views {
23
24 ////////////////////////////////////////////////////////////////////////////////
25 // GestureRecognizer Public:
26
27 GestureRecognizer::GestureRecognizer()
28 : first_touch_time_(0.0),
29 state_(GestureRecognizer::GS_NO_GESTURE),
30 last_touch_time_(0.0),
31 last_click_time_(0.0),
32 x_velocity_(0.0),
33 y_velocity_(0.0),
34 flags_(0) {
35 }
36
37 GestureRecognizer::~GestureRecognizer() {
38 }
39
40 GestureRecognizer* GestureRecognizer::GetInstance() {
41 return Singleton<GestureRecognizer>::get();
42 }
43
44 GestureRecognizer::Gestures* GestureRecognizer::ProcessTouchEventForGesture(
45 const TouchEvent& event,
46 ui::TouchStatus status) {
47 if (status != ui::TOUCH_STATUS_UNKNOWN)
48 return false; // The event was consumed by a touch sequence.
49
50 scoped_ptr<Gestures> gestures(new Gestures());
51 UpdateValues(event);
52 switch (Signature(state_, event.identity(), event.type(), false)) {
53 case GST_NO_GESTURE_FIRST_PRESSED:
54 TouchDown(event, gestures.get());
55 break;
56 case GST_PENDING_SYNTHETIC_CLICK_FIRST_RELEASED:
57 Click(event, gestures.get());
58 break;
59 case GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED:
60 case GST_PENDING_SYNTHETIC_CLICK_FIRST_STATIONARY:
61 InClickOrScroll(event, gestures.get());
62 break;
63 case GST_PENDING_SYNTHETIC_CLICK_FIRST_CANCELLED:
64 NoGesture(event, gestures.get());
65 break;
66 case GST_SCROLL_FIRST_MOVED:
67 InScroll(event, gestures.get());
68 break;
69 case GST_SCROLL_FIRST_RELEASED:
70 case GST_SCROLL_FIRST_CANCELLED:
71 ScrollEnd(event, gestures.get());
72 break;
73 }
74 return gestures.release();
75 }
76
77 void GestureRecognizer::Reset() {
78 first_touch_time_ = 0.0;
79 state_ = GestureRecognizer::GS_NO_GESTURE;
80 last_touch_time_ = 0.0;
81 last_touch_position_.SetPoint(0, 0);
82 x_velocity_ = 0.0;
83 y_velocity_ = 0.0;
84 }
85
86 ////////////////////////////////////////////////////////////////////////////////
87 // GestureRecognizer Private:
88
89 // static
90 GestureRecognizer::TouchState GestureRecognizer::TouchEventTypeToTouchState(
91 ui::EventType type) {
92 switch (type) {
93 case ui::ET_TOUCH_RELEASED: return TS_RELEASED;
94 case ui::ET_TOUCH_PRESSED: return TS_PRESSED;
95 case ui::ET_TOUCH_MOVED: return TS_MOVED;
96 case ui::ET_TOUCH_STATIONARY: return TS_STATIONARY;
97 case ui::ET_TOUCH_CANCELLED: return TS_CANCELLED;
98 default:
99 VLOG(1) << "Unknown Touch Event type";
100 }
101 return TS_UNKNOWN;
102 }
103
104 unsigned int GestureRecognizer::Signature(GestureState gesture_state,
105 unsigned int touch_id, ui::EventType type,
106 bool touch_handled) {
107 CHECK((touch_id & 0xfff) == touch_id);
108 TouchState touch_state = TouchEventTypeToTouchState(type);
109 return 1 + ((touch_state & 0x7) << 1 | (touch_handled ? 1 << 4 : 0) |
110 ((touch_id & 0xfff) << 5) | (gesture_state << 17));
111 }
112
113 bool GestureRecognizer::IsInClickTimeWindow() {
114 double duration(last_touch_time_ - first_touch_time_);
115 return duration >= kMinimumTouchDownDurationInSecondsForClick &&
116 duration < kMaximumTouchDownDurationInSecondsForClick;
117 }
118
119 bool GestureRecognizer::IsInSecondClickTimeWindow() {
120 double duration(last_touch_time_ - last_click_time_);
121 return duration < kMaximumSecondsBetweenDoubleClick;
122 }
123
124 bool GestureRecognizer::IsInsideManhattanSquare(const TouchEvent& event) {
125 int manhattanDistance = abs(event.x() - first_touch_position_.x()) +
126 abs(event.y() - first_touch_position_.y());
127 return manhattanDistance < kMaximumTouchMoveInPixelsForClick;
128 }
129
130 bool GestureRecognizer::IsSecondClickInsideManhattanSquare(
131 const TouchEvent& event) {
132 int manhattanDistance = abs(event.x() - last_click_position_.x()) +
133 abs(event.y() - last_click_position_.y());
134 return manhattanDistance < kMaximumTouchMoveInPixelsForClick;
135 }
136
137 bool GestureRecognizer::IsOverMinFlickSpeed() {
138 return (x_velocity_ * x_velocity_ + y_velocity_ * y_velocity_) >
139 kMinFlickSpeedSquared;
140 }
141
142 void GestureRecognizer::AppendTapDownGestureEvent(const TouchEvent& event,
143 Gestures* gestures) {
144 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
145 ui::ET_GESTURE_TAP_DOWN,
146 first_touch_position_.x(),
147 first_touch_position_.y(),
148 event.flags(),
149 base::Time::FromDoubleT(last_touch_time_),
150 0.f, 0.f)));
151 }
152
153 void GestureRecognizer::AppendClickGestureEvent(const TouchEvent& event,
154 Gestures* gestures) {
155 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
156 ui::ET_GESTURE_TAP,
157 first_touch_position_.x(),
158 first_touch_position_.y(),
159 event.flags(),
160 base::Time::FromDoubleT(last_touch_time_),
161 0.f, 0.f)));
162 }
163
164 void GestureRecognizer::AppendDoubleClickGestureEvent(const TouchEvent& event,
165 Gestures* gestures) {
166 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
167 ui::ET_GESTURE_DOUBLE_TAP,
168 first_touch_position_.x(),
169 first_touch_position_.y(),
170 event.flags(),
171 base::Time::FromDoubleT(last_touch_time_),
172 0.f, 0.f)));
173 }
174
175 void GestureRecognizer::AppendScrollGestureBegin(const TouchEvent& event,
176 Gestures* gestures) {
177 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
178 ui::ET_GESTURE_SCROLL_BEGIN,
179 event.x(),
180 event.y(),
181 event.flags(),
182 base::Time::FromDoubleT(last_touch_time_),
183 0.f, 0.f)));
184 }
185
186 void GestureRecognizer::AppendScrollGestureEnd(const TouchEvent& event,
187 Gestures* gestures,
188 float x_velocity,
189 float y_velocity) {
190 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
191 ui::ET_GESTURE_SCROLL_END,
192 event.x(),
193 event.y(),
194 event.flags(),
195 base::Time::FromDoubleT(last_touch_time_),
196 x_velocity, y_velocity)));
197 }
198
199 void GestureRecognizer:: AppendScrollGestureUpdate(const TouchEvent& event,
200 Gestures* gestures) {
201 float delta_x(event.x() - first_touch_position_.x());
202 float delta_y(event.y() - first_touch_position_.y());
203
204 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent(
205 ui::ET_GESTURE_SCROLL_UPDATE,
206 event.x(),
207 event.y(),
208 event.flags(),
209 base::Time::FromDoubleT(last_touch_time_),
210 delta_x, delta_y)));
211
212 first_touch_position_ = event.location();
213 }
214
215 void GestureRecognizer::UpdateValues(const TouchEvent& event) {
216 if (state_ != GS_NO_GESTURE && event.type() == ui::ET_TOUCH_MOVED) {
217 double interval(event.time_stamp().ToDoubleT() - last_touch_time_);
218 x_velocity_ = (event.x() - last_touch_position_.x()) / interval;
219 y_velocity_ = (event.y() - last_touch_position_.y()) / interval;
220 }
221 last_touch_time_ = event.time_stamp().ToDoubleT();
222 last_touch_position_ = event.location();
223 if (state_ == GS_NO_GESTURE) {
224 first_touch_time_ = last_touch_time_;
225 first_touch_position_ = event.location();
226 x_velocity_ = 0.0;
227 y_velocity_ = 0.0;
228 }
229 }
230
231 bool GestureRecognizer::Click(const TouchEvent& event, Gestures* gestures) {
232 bool gesture_added = false;
233 if (IsInClickTimeWindow() && IsInsideManhattanSquare(event)) {
234 gesture_added = true;
235 AppendClickGestureEvent(event, gestures);
236 if (IsInSecondClickTimeWindow() &&
237 IsSecondClickInsideManhattanSquare(event))
238 AppendDoubleClickGestureEvent(event, gestures);
239 last_click_time_ = last_touch_time_;
240 last_click_position_ = last_touch_position_;
241 }
242 Reset();
243 return gesture_added;
244 }
245
246 bool GestureRecognizer::InClickOrScroll(const TouchEvent& event,
247 Gestures* gestures) {
248 if (IsInClickTimeWindow() && IsInsideManhattanSquare(event)) {
249 SetState(GS_PENDING_SYNTHETIC_CLICK);
250 return false;
251 }
252 if (event.type() == ui::ET_TOUCH_MOVED && !IsInsideManhattanSquare(event)) {
253 AppendScrollGestureBegin(event, gestures);
254 AppendScrollGestureUpdate(event, gestures);
255 SetState(GS_SCROLL);
256 return true;
257 }
258 return false;
259 }
260
261 bool GestureRecognizer::InScroll(const TouchEvent& event, Gestures* gestures) {
262 AppendScrollGestureUpdate(event, gestures);
263 return true;
264 }
265
266 bool GestureRecognizer::NoGesture(const TouchEvent&, Gestures*) {
267 Reset();
268 return false;
269 }
270
271 bool GestureRecognizer::TouchDown(const TouchEvent& event, Gestures* gestures) {
272 AppendTapDownGestureEvent(event, gestures);
273 SetState(GS_PENDING_SYNTHETIC_CLICK);
274 return false;
275 }
276
277 bool GestureRecognizer::ScrollEnd(const TouchEvent& event, Gestures* gestures) {
278 if (IsOverMinFlickSpeed() && event.type() != ui::ET_TOUCH_CANCELLED)
279 AppendScrollGestureEnd(event, gestures, x_velocity_, y_velocity_);
280 else
281 AppendScrollGestureEnd(event, gestures, 0.f, 0.f);
282 SetState(GS_NO_GESTURE);
283 Reset();
284 return false;
285 }
286
287 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/touchui/gesture_recognizer.h ('k') | ui/views/view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698