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

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

Issue 8364039: Initial views touchui GestureRecognizer support (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Event injection as per Robert comments Created 9 years, 1 month 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
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 "views/touchui/gesture_recognizer.h"
6
7 #include "base/logging.h"
8 #include "ui/base/events.h"
9 #include "views/events/event.h"
10
11 namespace {
12
13 double maximumTouchDownDurationInSecondsForClick = 0.8;
14 double minimumTouchDownDurationInSecondsForClick = 0.01;
15 double maximumSecondsBetweenDoubleClick = 0.7;
16 int maximumTouchMoveInPixelsForClick = 20;
17 float minFlickSpeedSquared = 550.f * 550.f;
18
19 } // namespace
20
21 namespace views {
22
23 GestureRecognizer::PassGestureEvent::PassGestureEvent(GestureEvent* event)
24 : event_(event) {
25 }
26
27 GestureRecognizer::PassGestureEvent::~PassGestureEvent() {
28 free(event_);
29 event_ = NULL;
30 }
31
32 ////////////////////////////////////////////////////////////////////////////////
33 // GestureRecognizer Public:
34
35 GestureRecognizer::GestureRecognizer()
36 : first_touch_time_(0.0),
37 state_(GestureRecognizer::GS_NO_GESTURE),
38 last_touch_time_(0.0),
39 last_click_time_(0.0),
40 x_velocity_(0.0),
41 y_velocity_(0.0),
42 flags_(0) {
43 const unsigned int first_finger = 0;
44 const ui::EventType released = ui::ET_TOUCH_RELEASED;
45 const ui::EventType pressed = ui::ET_TOUCH_PRESSED;
46 const ui::EventType moved = ui::ET_TOUCH_MOVED;
47 const ui::EventType stationary = ui::ET_TOUCH_STATIONARY;
48 const ui::EventType cancelled = ui::ET_TOUCH_CANCELLED;
49
50 AddEdgeFunction(GS_NO_GESTURE, first_finger, pressed, false,
51 &GestureRecognizer::TouchDown);
52 AddEdgeFunction(GS_PENDING_SYNTHETIC_CLICK, first_finger, cancelled, false,
53 &GestureRecognizer::NoGesture);
54 AddEdgeFunction(GS_PENDING_SYNTHETIC_CLICK, first_finger, released, false,
55 &GestureRecognizer::Click);
56 AddEdgeFunction(GS_PENDING_SYNTHETIC_CLICK, first_finger, moved, false,
57 &GestureRecognizer::IsClickOrScroll);
58 AddEdgeFunction(GS_PENDING_SYNTHETIC_CLICK, first_finger, stationary, false,
59 &GestureRecognizer::IsClickOrScroll);
60 AddEdgeFunction(GS_SCROLL, first_finger, moved, false,
61 &GestureRecognizer::InScroll);
62 AddEdgeFunction(GS_SCROLL, first_finger, released, false,
63 &GestureRecognizer::ScrollEnd);
64 AddEdgeFunction(GS_SCROLL, first_finger, cancelled, false,
65 &GestureRecognizer::ScrollEnd);
66 }
67
68 GestureRecognizer::~GestureRecognizer() {
69 }
70
71 GestureRecognizer::Gestures* GestureRecognizer::ProcessTouchEventForGesture(
72 const TouchEvent& event,
73 bool touch_handled) {
74 flags_ = event.flags();
75 scoped_ptr<Gestures> gestures(new Gestures());
76 UpdateValues(event);
77 GestureTransitionFunctionMap::iterator it = edge_functions_.find(
78 Signature(state_, event.identity(), event.type(), touch_handled));
79 if (edge_functions_.end() != it) {
80 GestureTransitionFunction ef = it->second;
81 ((*this).*ef)(event, gestures.get());
82 }
83 return gestures.release();
84 }
85
86 void GestureRecognizer::Reset() {
87 first_touch_time_ = 0.0;
88 state_ = GestureRecognizer::GS_NO_GESTURE;
89 last_touch_time_ = 0.0;
90 last_touch_position_.SetPoint(0, 0);
91 x_velocity_ = 0.0;
92 y_velocity_ = 0.0;
93 }
94
95 ////////////////////////////////////////////////////////////////////////////////
96 // GestureRecognizer Private:
97
98 GestureRecognizer::TouchState GestureRecognizer::TouchEventTypeToTouchState(
99 ui::EventType type) {
100 switch (type) {
101 case ui::ET_TOUCH_RELEASED: return TS_RELEASED;
102 case ui::ET_TOUCH_PRESSED: return TS_PRESSED;
103 case ui::ET_TOUCH_MOVED: return TS_MOVED;
104 case ui::ET_TOUCH_STATIONARY: return TS_STATIONARY;
105 case ui::ET_TOUCH_CANCELLED: return TS_CANCELLED;
106 default:
107 VLOG(1) << "Unknown Touch Event type";
108 }
109 return TS_UNKNOWN;
110 }
111
112 // Builds a signature. Signatures are assembled by joining together
113 // multiple bits.
114 // 1 LSB bit so that the computed signature is always greater than 0
115 // 3 bits for the |type|.
116 // 1 bit for |touch_handled|
117 // 12 bits for |touch_id|
118 // 15 bits for the |gesture_state|.
119 unsigned int GestureRecognizer::Signature(GestureState gesture_state,
120 unsigned int touch_id, ui::EventType type,
121 bool touch_handled) {
122 CHECK((touch_id & 0xfff) == touch_id);
123 TouchState touch_state = TouchEventTypeToTouchState(type);
124 return 1 + ((touch_state & 0x7) << 1 | (touch_handled ? 1 << 4 : 0) |
125 ((touch_id & 0xfff) << 5) | (gesture_state << 17));
126 }
127
128 void GestureRecognizer::AddEdgeFunction(GestureState state,
129 unsigned int touch_id,
130 ui::EventType type,
131 bool touch_handled,
132 GestureTransitionFunction function) {
133 edge_functions_[Signature(state, touch_id, type, touch_handled)] = function;
134 }
135
136 bool GestureRecognizer::IsInClickTimeWindow() {
137 double duration(last_touch_time_ - first_touch_time_);
138 return duration >= minimumTouchDownDurationInSecondsForClick &&
139 duration < maximumTouchDownDurationInSecondsForClick;
140 }
141
142 bool GestureRecognizer::IsInSecondClickTimeWindow() {
143 double duration(last_touch_time_ - last_click_time_);
144 return duration < maximumSecondsBetweenDoubleClick;
145 }
146
147 bool GestureRecognizer::IsInsideManhattanSquare(const TouchEvent& event) {
148 int manhattanDistance = abs(event.x() - first_touch_position_.x()) +
149 abs(event.y() - first_touch_position_.y());
150 return manhattanDistance < maximumTouchMoveInPixelsForClick;
151 }
152
153 bool GestureRecognizer::IsSecondClickInsideManhattanSquare(
154 const TouchEvent& event) {
155 int manhattanDistance = abs(event.x() - last_click_position_.x()) +
156 abs(event.y() - last_click_position_.y());
157 return manhattanDistance < maximumTouchMoveInPixelsForClick;
158 }
159
160 bool GestureRecognizer::IsOverMinFlickSpeed() {
161 return (x_velocity_ * x_velocity_ + y_velocity_ * y_velocity_) >
162 minFlickSpeedSquared;
163 }
164
165 void GestureRecognizer::AppendTapDownGestureEvent(const TouchEvent& event,
166 Gestures* gestures) {
167 gestures->push_back(PassGestureEvent(new GestureEvent(ui::ET_GESTURE_TAP_DOWN,
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::AppendClickGestureEvent(const TouchEvent& event,
176 Gestures* gestures) {
177 gestures->push_back(PassGestureEvent(new GestureEvent(ui::ET_GESTURE_TAP,
178 first_touch_position_.x(),
179 first_touch_position_.y(),
180 event.flags(),
181 base::Time::FromDoubleT(last_touch_time_),
182 0.f, 0.f)));
183 }
184
185 void GestureRecognizer::AppendDoubleClickGestureEvent(const TouchEvent& event,
186 Gestures* gestures) {
187 gestures->push_back(PassGestureEvent(new GestureEvent(
188 ui::ET_GESTURE_DOUBLE_TAP,
189 first_touch_position_.x(),
190 first_touch_position_.y(),
191 event.flags(),
192 base::Time::FromDoubleT(last_touch_time_),
193 0.f, 0.f)));
194 }
195
196 void GestureRecognizer::AppendScrollGestureBegin(const TouchEvent& event,
197 Gestures* gestures) {
198 gestures->push_back(PassGestureEvent(new GestureEvent(
199 ui::ET_GESTURE_SCROLL_BEGIN,
200 event.x(),
201 event.y(),
202 event.flags(),
203 base::Time::FromDoubleT(last_touch_time_),
204 0.f, 0.f)));
205 }
206
207 void GestureRecognizer::AppendScrollGestureEnd(const TouchEvent& event,
208 Gestures* gestures,
209 float x_velocity,
210 float y_velocity) {
211 gestures->push_back(PassGestureEvent(new GestureEvent(
212 ui::ET_GESTURE_SCROLL_END,
213 event.x(),
214 event.y(),
215 event.flags(),
216 base::Time::FromDoubleT(last_touch_time_),
217 x_velocity, y_velocity)));
218 }
219
220 void GestureRecognizer:: AppendScrollGestureUpdate(const TouchEvent& event,
221 Gestures* gestures) {
222 float delta_x(event.x() - first_touch_position_.x());
223 float delta_y(event.y() - first_touch_position_.y());
224
225 gestures->push_back(PassGestureEvent(new GestureEvent(
226 ui::ET_GESTURE_SCROLL_UPDATE,
227 event.x(),
228 event.y(),
229 event.flags(),
230 base::Time::FromDoubleT(last_touch_time_),
231 delta_x, delta_y)));
232
233 first_touch_position_ = event.location();
234 }
235
236 void GestureRecognizer::UpdateValues(const TouchEvent& event) {
237 if (state_ != GS_NO_GESTURE && event.type() == ui::ET_TOUCH_MOVED) {
238 double interval(event.time_stamp().ToDoubleT() - last_touch_time_);
239 x_velocity_ = (event.x() - last_touch_position_.x()) / interval;
240 y_velocity_ = (event.y() - last_touch_position_.y()) / interval;
241 }
242 last_touch_time_ = event.time_stamp().ToDoubleT();
243 last_touch_position_ = event.location();
244 if (state_ == GS_NO_GESTURE) {
245 first_touch_time_ = last_touch_time_;
246 first_touch_position_ = event.location();
247 x_velocity_ = 0.0;
248 y_velocity_ = 0.0;
249 }
250 }
251
252 bool GestureRecognizer::Click(const TouchEvent& event, Gestures* gestures) {
253 bool gesture_added = false;
254 if (IsInClickTimeWindow() && IsInsideManhattanSquare(event)) {
255 gesture_added = true;
256 AppendClickGestureEvent(event, gestures);
257 if (IsInSecondClickTimeWindow() &&
258 IsSecondClickInsideManhattanSquare(event))
259 AppendDoubleClickGestureEvent(event, gestures);
260 last_click_time_ = last_touch_time_;
261 last_click_position_ = last_touch_position_;
262 }
263 Reset();
264 return gesture_added;
265 }
266
267 bool GestureRecognizer::IsClickOrScroll(const TouchEvent& event,
268 Gestures* gestures) {
269 if (IsInClickTimeWindow() && IsInsideManhattanSquare(event)) {
270 SetState(GS_PENDING_SYNTHETIC_CLICK);
271 return false;
272 }
273 if (event.type() == ui::ET_TOUCH_MOVED && !IsInsideManhattanSquare(event)) {
274 AppendScrollGestureBegin(event, gestures);
275 AppendScrollGestureUpdate(event, gestures);
276 SetState(GS_SCROLL);
277 return true;
278 }
279 return false;
280 }
281
282 bool GestureRecognizer::InScroll(const TouchEvent& event, Gestures* gestures) {
283 AppendScrollGestureUpdate(event, gestures);
284 return true;
285 }
286
287 bool GestureRecognizer::NoGesture(const TouchEvent&, Gestures*) {
288 Reset();
289 return false;
290 }
291
292 bool GestureRecognizer::TouchDown(const TouchEvent& event, Gestures* gestures) {
293 AppendTapDownGestureEvent(event, gestures);
294 SetState(GS_PENDING_SYNTHETIC_CLICK);
295 return false;
296 }
297
298 bool GestureRecognizer::ScrollEnd(const TouchEvent& event, Gestures* gestures) {
299 if (IsOverMinFlickSpeed() && event.type() != ui::ET_TOUCH_CANCELLED)
300 AppendScrollGestureEnd(event, gestures, x_velocity_, y_velocity_);
301 else
302 AppendScrollGestureEnd(event, gestures, 0.f, 0.f);
303 SetState(GS_NO_GESTURE);
304 Reset();
305 return false;
306 }
307
308 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698