Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 "base/memory/scoped_ptr.h" | |
| 9 #include "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 flags_ = event.flags(); | |
|
sadrul
2011/11/18 19:01:50
It looks like flags_ isn't used anywhere else. Rem
Gajen
2011/11/21 15:56:50
Done.
| |
| 51 scoped_ptr<Gestures> gestures(new Gestures()); | |
| 52 UpdateValues(event); | |
| 53 switch (Signature(state_, event.identity(), event.type(), false)) { | |
| 54 case 0x00000003: | |
| 55 TouchDown(event, gestures.get()); | |
| 56 break; | |
| 57 case 0x00020009: | |
| 58 NoGesture(event, gestures.get()); | |
| 59 break; | |
| 60 case 0x00020001: | |
| 61 Click(event, gestures.get()); | |
| 62 break; | |
| 63 case 0x00020005: | |
| 64 case 0x00020007: | |
| 65 InClickOrScroll(event, gestures.get()); | |
| 66 break; | |
| 67 case 0x00040005: | |
| 68 InScroll(event, gestures.get()); | |
| 69 break; | |
| 70 case 0x00040001: | |
| 71 case 0x00040009: | |
| 72 ScrollEnd(event, gestures.get()); | |
| 73 break; | |
| 74 } | |
| 75 return gestures.release(); | |
| 76 } | |
| 77 | |
| 78 void GestureRecognizer::Reset() { | |
| 79 first_touch_time_ = 0.0; | |
| 80 state_ = GestureRecognizer::GS_NO_GESTURE; | |
| 81 last_touch_time_ = 0.0; | |
| 82 last_touch_position_.SetPoint(0, 0); | |
| 83 x_velocity_ = 0.0; | |
| 84 y_velocity_ = 0.0; | |
| 85 } | |
| 86 | |
| 87 //////////////////////////////////////////////////////////////////////////////// | |
| 88 // GestureRecognizer Private: | |
| 89 | |
| 90 // static | |
| 91 GestureRecognizer::TouchState GestureRecognizer::TouchEventTypeToTouchState( | |
| 92 ui::EventType type) { | |
| 93 switch (type) { | |
| 94 case ui::ET_TOUCH_RELEASED: return TS_RELEASED; | |
| 95 case ui::ET_TOUCH_PRESSED: return TS_PRESSED; | |
| 96 case ui::ET_TOUCH_MOVED: return TS_MOVED; | |
| 97 case ui::ET_TOUCH_STATIONARY: return TS_STATIONARY; | |
| 98 case ui::ET_TOUCH_CANCELLED: return TS_CANCELLED; | |
| 99 default: | |
| 100 VLOG(1) << "Unknown Touch Event type"; | |
| 101 } | |
| 102 return TS_UNKNOWN; | |
| 103 } | |
| 104 | |
| 105 // Builds a signature. Signatures are assembled by joining together | |
| 106 // multiple bits. | |
| 107 // 1 LSB bit so that the computed signature is always greater than 0 | |
| 108 // 3 bits for the |type|. | |
| 109 // 1 bit for |touch_handled| | |
| 110 // 12 bits for |touch_id| | |
| 111 // 15 bits for the |gesture_state|. | |
| 112 unsigned int GestureRecognizer::Signature(GestureState gesture_state, | |
| 113 unsigned int touch_id, ui::EventType type, | |
| 114 bool touch_handled) { | |
| 115 CHECK((touch_id & 0xfff) == touch_id); | |
| 116 TouchState touch_state = TouchEventTypeToTouchState(type); | |
| 117 return 1 + ((touch_state & 0x7) << 1 | (touch_handled ? 1 << 4 : 0) | | |
| 118 ((touch_id & 0xfff) << 5) | (gesture_state << 17)); | |
|
Ian Vollick
2011/11/18 15:25:34
If you're now using a switch statement, it might b
Gajen
2011/11/21 15:56:50
Added new enum GestureSignatureType and Changed Ge
| |
| 119 } | |
|
cpu_(ooo_6.6-7.5)
2011/11/21 00:58:09
I agree with vollick.
Gajen
2011/11/21 15:56:50
Ditto
| |
| 120 | |
| 121 bool GestureRecognizer::IsInClickTimeWindow() { | |
| 122 double duration(last_touch_time_ - first_touch_time_); | |
| 123 return duration >= kMinimumTouchDownDurationInSecondsForClick && | |
| 124 duration < kMaximumTouchDownDurationInSecondsForClick; | |
| 125 } | |
| 126 | |
| 127 bool GestureRecognizer::IsInSecondClickTimeWindow() { | |
| 128 double duration(last_touch_time_ - last_click_time_); | |
| 129 return duration < kMaximumSecondsBetweenDoubleClick; | |
| 130 } | |
| 131 | |
| 132 bool GestureRecognizer::IsInsideManhattanSquare(const TouchEvent& event) { | |
| 133 int manhattanDistance = abs(event.x() - first_touch_position_.x()) + | |
| 134 abs(event.y() - first_touch_position_.y()); | |
| 135 return manhattanDistance < kMaximumTouchMoveInPixelsForClick; | |
| 136 } | |
| 137 | |
| 138 bool GestureRecognizer::IsSecondClickInsideManhattanSquare( | |
| 139 const TouchEvent& event) { | |
| 140 int manhattanDistance = abs(event.x() - last_click_position_.x()) + | |
| 141 abs(event.y() - last_click_position_.y()); | |
| 142 return manhattanDistance < kMaximumTouchMoveInPixelsForClick; | |
| 143 } | |
| 144 | |
| 145 bool GestureRecognizer::IsOverMinFlickSpeed() { | |
| 146 return (x_velocity_ * x_velocity_ + y_velocity_ * y_velocity_) > | |
| 147 kMinFlickSpeedSquared; | |
| 148 } | |
| 149 | |
| 150 void GestureRecognizer::AppendTapDownGestureEvent(const TouchEvent& event, | |
| 151 Gestures* gestures) { | |
| 152 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent( | |
| 153 ui::ET_GESTURE_TAP_DOWN, | |
| 154 first_touch_position_.x(), | |
| 155 first_touch_position_.y(), | |
| 156 event.flags(), | |
| 157 base::Time::FromDoubleT(last_touch_time_), | |
| 158 0.f, 0.f))); | |
| 159 } | |
| 160 | |
| 161 void GestureRecognizer::AppendClickGestureEvent(const TouchEvent& event, | |
| 162 Gestures* gestures) { | |
| 163 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent( | |
| 164 ui::ET_GESTURE_TAP, | |
| 165 first_touch_position_.x(), | |
| 166 first_touch_position_.y(), | |
| 167 event.flags(), | |
| 168 base::Time::FromDoubleT(last_touch_time_), | |
| 169 0.f, 0.f))); | |
| 170 } | |
| 171 | |
| 172 void GestureRecognizer::AppendDoubleClickGestureEvent(const TouchEvent& event, | |
| 173 Gestures* gestures) { | |
| 174 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent( | |
| 175 ui::ET_GESTURE_DOUBLE_TAP, | |
| 176 first_touch_position_.x(), | |
| 177 first_touch_position_.y(), | |
| 178 event.flags(), | |
| 179 base::Time::FromDoubleT(last_touch_time_), | |
| 180 0.f, 0.f))); | |
| 181 } | |
| 182 | |
| 183 void GestureRecognizer::AppendScrollGestureBegin(const TouchEvent& event, | |
| 184 Gestures* gestures) { | |
| 185 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent( | |
| 186 ui::ET_GESTURE_SCROLL_BEGIN, | |
| 187 event.x(), | |
| 188 event.y(), | |
| 189 event.flags(), | |
| 190 base::Time::FromDoubleT(last_touch_time_), | |
| 191 0.f, 0.f))); | |
| 192 } | |
| 193 | |
| 194 void GestureRecognizer::AppendScrollGestureEnd(const TouchEvent& event, | |
| 195 Gestures* gestures, | |
| 196 float x_velocity, | |
| 197 float y_velocity) { | |
| 198 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent( | |
| 199 ui::ET_GESTURE_SCROLL_END, | |
| 200 event.x(), | |
| 201 event.y(), | |
| 202 event.flags(), | |
| 203 base::Time::FromDoubleT(last_touch_time_), | |
| 204 x_velocity, y_velocity))); | |
| 205 } | |
| 206 | |
| 207 void GestureRecognizer:: AppendScrollGestureUpdate(const TouchEvent& event, | |
| 208 Gestures* gestures) { | |
| 209 float delta_x(event.x() - first_touch_position_.x()); | |
| 210 float delta_y(event.y() - first_touch_position_.y()); | |
| 211 | |
| 212 gestures->push_back(linked_ptr<GestureEvent>(new GestureEvent( | |
| 213 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::InClickOrScroll(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 | |
| OLD | NEW |