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

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: Created 9 years, 2 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
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;
rjkroege 2011/10/21 20:02:10 A subsequent CL should connect these changes with
Gajen 2011/10/25 14:32:29 Done.
14 double minimumTouchDownDurationInSecondsForClick = 0.01;
rjkroege 2011/10/21 20:02:10 These ought to be const at the moment. They need
Gajen 2011/10/25 14:32:29 Done.
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 ////////////////////////////////////////////////////////////////////////////////
24 // GestureRecognizer Public:
25
26 GestureRecognizer::GestureRecognizer()
27 : first_touch_time_(0.0),
28 state_(GestureRecognizer::GS_NO_GESTURE),
29 last_touch_time_(0.0),
30 last_click_time_(0.0),
31 x_velocity_(0.0),
32 y_velocity_(0.0),
33 flags_(0) {
34 const unsigned int first_finger = 0;
35 const ui::EventType released = ui::ET_TOUCH_RELEASED;
36 const ui::EventType pressed = ui::ET_TOUCH_PRESSED;
37 const ui::EventType moved = ui::ET_TOUCH_MOVED;
38 const ui::EventType stationary = ui::ET_TOUCH_STATIONARY;
39 const ui::EventType cancelled = ui::ET_TOUCH_CANCELLED;
40
41 AddEdgeFunction(GS_NO_GESTURE, first_finger, pressed, false,
42 &GestureRecognizer::TouchDown);
43 AddEdgeFunction(GS_PENDING_SYNTHETIC_CLICK, first_finger, cancelled, false,
44 &GestureRecognizer::NoGesture);
45 AddEdgeFunction(GS_PENDING_SYNTHETIC_CLICK, first_finger, released, false,
46 &GestureRecognizer::Click);
47 AddEdgeFunction(GS_PENDING_SYNTHETIC_CLICK, first_finger, moved, false,
48 &GestureRecognizer::IsClickOrScroll);
49 AddEdgeFunction(GS_PENDING_SYNTHETIC_CLICK, first_finger, stationary, false,
50 &GestureRecognizer::IsClickOrScroll);
51 AddEdgeFunction(GS_SCROLL, first_finger, moved, false,
52 &GestureRecognizer::InScroll);
53 AddEdgeFunction(GS_SCROLL, first_finger, released, false,
54 &GestureRecognizer::ScrollEnd);
55 AddEdgeFunction(GS_SCROLL, first_finger, cancelled, false,
56 &GestureRecognizer::ScrollEnd);
57 }
58
59 GestureRecognizer::~GestureRecognizer() {
60 }
61
62 GestureRecognizer::Gestures* GestureRecognizer::ProcessTouchEventForGesture(
63 const TouchEvent& event,
64 bool touch_handled) {
65 flags_ = event.flags();
66 scoped_ptr<Gestures> gestures(new Gestures());
67 UpdateValues(event);
68 GestureTransitionFunctionMap::iterator it = edge_functions_.find(
69 Signature(state_, event.identity(), event.type(), touch_handled));
70 if (edge_functions_.end() != it) {
71 GestureTransitionFunction ef = it->second;
72 ((*this).*ef)(event, gestures.get());
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 GestureRecognizer::TouchState GestureRecognizer::TouchEventTypeToTouchState(
90 ui::EventType type) {
91 switch (type) {
92 case ui::ET_TOUCH_RELEASED: return TS_RELEASED;
93 case ui::ET_TOUCH_PRESSED: return TS_PRESSED;
94 case ui::ET_TOUCH_MOVED: return TS_MOVED;
95 case ui::ET_TOUCH_STATIONARY: return TS_STATIONARY;
96 case ui::ET_TOUCH_CANCELLED: return TS_CANCELLED;
97 default:
98 VLOG(1) << "Unknown Touch Event type";
99 }
100 return TS_UNKNOWN;
101 }
102
103 // Builds a signature. Signatures are assembled by joining together
104 // multiple bits.
105 // 1 LSB bit so that the computed signature is always greater than 0
106 // 3 bits for the |type|.
107 // 1 bit for |touch_handled|
108 // 12 bits for |touch_id|
109 // 15 bits for the |gesture_state|.
110 unsigned int GestureRecognizer::Signature(GestureState gesture_state,
111 unsigned int touch_id, ui::EventType type,
112 bool touch_handled) {
113 CHECK((touch_id & 0xfff) == touch_id);
114 TouchState touch_state = TouchEventTypeToTouchState(type);
115 return 1 + ((touch_state & 0x7) << 1 | (touch_handled ? 1 << 4 : 0) |
116 ((touch_id & 0xfff) << 5) | (gesture_state << 17));
117 }
118
119 void GestureRecognizer::AddEdgeFunction(GestureState state,
120 unsigned int touch_id,
121 ui::EventType type,
122 bool touch_handled,
123 GestureTransitionFunction function) {
124 edge_functions_[Signature(state, touch_id, type, touch_handled)] = function;
125 }
126
127 bool GestureRecognizer::IsInClickTimeWindow() {
128 double duration(last_touch_time_ - first_touch_time_);
129 return duration >= minimumTouchDownDurationInSecondsForClick &&
130 duration < maximumTouchDownDurationInSecondsForClick;
131 }
132
133 bool GestureRecognizer::IsInSecondClickTimeWindow() {
134 double duration(last_touch_time_ - last_click_time_);
135 return duration < maximumSecondsBetweenDoubleClick;
136 }
137
138 bool GestureRecognizer::IsInsideManhattanSquare(const TouchEvent& event) {
139 int manhattanDistance = abs(event.x() - first_touch_position_.x()) +
140 abs(event.y() - first_touch_position_.y());
141 return manhattanDistance < maximumTouchMoveInPixelsForClick;
142 }
143
144 bool GestureRecognizer::IsSecondClickInsideManhattanSquare(
145 const TouchEvent& event) {
146 int manhattanDistance = abs(event.x() - last_click_position_.x()) +
147 abs(event.y() - last_click_position_.y());
148 return manhattanDistance < maximumTouchMoveInPixelsForClick;
149 }
150
151 bool GestureRecognizer::IsOverMinFlickSpeed() {
152 return (x_velocity_ * x_velocity_ + y_velocity_ * y_velocity_) >
153 minFlickSpeedSquared;
154 }
155
156 void GestureRecognizer::AppendTapDownGestureEvent(const TouchEvent& event,
157 Gestures* gestures) {
158 gestures->push_back(new GestureEvent(ui::ET_GESTURE_TAP_DOWN,
159 first_touch_position_.x(),
rjkroege 2011/10/21 20:02:10 Bad indent I think.
Gajen 2011/10/25 14:32:29 Done.
Gajen 2011/10/25 14:32:29 Done.
160 first_touch_position_.y(),
161 event.flags(),
162 base::Time::FromDoubleT(last_touch_time_),
163 0.f, 0.f));
164 }
165
166 void GestureRecognizer::AppendClickGestureEvent(const TouchEvent& event,
167 Gestures* gestures) {
168 gestures->push_back(new GestureEvent(ui::ET_GESTURE_TAP,
169 first_touch_position_.x(),
170 first_touch_position_.y(),
171 event.flags(),
172 base::Time::FromDoubleT(last_touch_time_),
173 0.f, 0.f));
174 }
175
176 void GestureRecognizer::AppendDoubleClickGestureEvent(const TouchEvent& event,
177 Gestures* gestures) {
178 gestures->push_back(new GestureEvent(ui::ET_GESTURE_DOUBLE_TAP,
179 first_touch_position_.x(),
180 first_touch_position_.y(),
181 event.flags(),
182 base::Time::FromDoubleT(last_touch_time_),
183 0.f, 0.f));
184 }
185
186 void GestureRecognizer::AppendScrollGestureBegin(const TouchEvent& event,
187 Gestures* gestures) {
188 gestures->push_back(new GestureEvent(ui::ET_GESTURE_SCROLL_BEGIN,
189 event.x(),
190 event.y(),
191 event.flags(),
192 base::Time::FromDoubleT(last_touch_time_),
193 0.f, 0.f));
194 }
195
196 void GestureRecognizer::AppendScrollGestureEnd(const TouchEvent& event,
197 Gestures* gestures,
198 float x_velocity,
199 float y_velocity) {
200 gestures->push_back(new GestureEvent(ui::ET_GESTURE_SCROLL_END,
201 event.x(),
202 event.y(),
203 event.flags(),
204 base::Time::FromDoubleT(last_touch_time_),
205 x_velocity, y_velocity));
206 }
207
208 void GestureRecognizer:: AppendScrollGestureUpdate(const TouchEvent& event,
209 Gestures* gestures) {
210 float delta_x(event.x() - first_touch_position_.x());
211 float delta_y(event.y() - first_touch_position_.y());
212
213 gestures->push_back(new GestureEvent(ui::ET_GESTURE_SCROLL_UPDATE,
214 event.x(),
215 event.y(),
216 event.flags(),
217 base::Time::FromDoubleT(last_touch_time_),
218 delta_x, delta_y));
219
220 first_touch_position_ = event.location();
221 }
222
223 void GestureRecognizer::UpdateValues(const TouchEvent& event) {
224 if (state_ != GS_NO_GESTURE && event.type() == ui::ET_TOUCH_MOVED) {
225 double interval(event.time_stamp().ToDoubleT() - last_touch_time_);
226 x_velocity_ = (event.x() - last_touch_position_.x()) / interval;
227 y_velocity_ = (event.y() - last_touch_position_.y()) / interval;
228 }
229 last_touch_time_ = event.time_stamp().ToDoubleT();
230 last_touch_position_ = event.location();
231 if (state_ == GS_NO_GESTURE) {
232 first_touch_time_ = last_touch_time_;
233 first_touch_position_ = event.location();
234 x_velocity_ = 0.0;
235 y_velocity_ = 0.0;
236 }
237 }
238
239 bool GestureRecognizer::Click(const TouchEvent& event, Gestures* gestures) {
240 bool gesture_added = false;
241 if (IsInClickTimeWindow() && IsInsideManhattanSquare(event)) {
242 gesture_added = true;
243 AppendClickGestureEvent(event, gestures);
244 if (IsInSecondClickTimeWindow() &&
245 IsSecondClickInsideManhattanSquare(event))
246 AppendDoubleClickGestureEvent(event, gestures);
247 last_click_time_ = last_touch_time_;
248 last_click_position_ = last_touch_position_;
249 }
250 Reset();
251 return gesture_added;
252 }
253
254 bool GestureRecognizer::IsClickOrScroll(const TouchEvent& event,
255 Gestures* gestures) {
256 if (IsInClickTimeWindow() && IsInsideManhattanSquare(event)) {
257 SetState(GS_PENDING_SYNTHETIC_CLICK);
258 return false;
259 }
260 if (event.type() == ui::ET_TOUCH_MOVED && !IsInsideManhattanSquare(event)) {
261 AppendScrollGestureBegin(event, gestures);
262 AppendScrollGestureUpdate(event, gestures);
263 SetState(GS_SCROLL);
264 return true;
265 }
266 return false;
267 }
268
269 bool GestureRecognizer::InScroll(const TouchEvent& event, Gestures* gestures) {
270 AppendScrollGestureUpdate(event, gestures);
271 return true;
272 }
273
274 bool GestureRecognizer::NoGesture(const TouchEvent&, Gestures*) {
275 Reset();
276 return false;
277 }
278
279 bool GestureRecognizer::TouchDown(const TouchEvent& event, Gestures* gestures) {
280 AppendTapDownGestureEvent(event, gestures);
281 SetState(GS_PENDING_SYNTHETIC_CLICK);
282 return false;
283 }
284
285 bool GestureRecognizer::ScrollEnd(const TouchEvent& event, Gestures* gestures) {
286 if (IsOverMinFlickSpeed() && event.type() != ui::ET_TOUCH_CANCELLED)
287 AppendScrollGestureEnd(event, gestures, x_velocity_, y_velocity_);
288 else
289 AppendScrollGestureEnd(event, gestures, 0.f, 0.f);
290 SetState(GS_NO_GESTURE);
291 Reset();
292 return false;
293 }
294
295 } // namespace views
OLDNEW
« views/events/event.cc ('K') | « views/touchui/gesture_recognizer.h ('k') | views/views.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698