OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // MSVC++ requires this to be set before any other includes to get M_PI. | 5 // MSVC++ requires this to be set before any other includes to get M_PI. |
6 #define _USE_MATH_DEFINES | 6 #define _USE_MATH_DEFINES |
7 | 7 |
8 #include "ui/events/gesture_detection/gesture_detector.h" | 8 #include "ui/events/gesture_detection/gesture_detector.h" |
9 | 9 |
10 #include <cmath> | 10 #include <cmath> |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 touch_slop(8), | 48 touch_slop(8), |
49 double_tap_slop(100), | 49 double_tap_slop(100), |
50 minimum_fling_velocity(50), | 50 minimum_fling_velocity(50), |
51 maximum_fling_velocity(8000), | 51 maximum_fling_velocity(8000), |
52 swipe_enabled(false), | 52 swipe_enabled(false), |
53 minimum_swipe_velocity(20), | 53 minimum_swipe_velocity(20), |
54 maximum_swipe_deviation_angle(20.f), | 54 maximum_swipe_deviation_angle(20.f), |
55 two_finger_tap_enabled(false), | 55 two_finger_tap_enabled(false), |
56 two_finger_tap_max_separation(300), | 56 two_finger_tap_max_separation(300), |
57 two_finger_tap_timeout(base::TimeDelta::FromMilliseconds(700)), | 57 two_finger_tap_timeout(base::TimeDelta::FromMilliseconds(700)), |
58 velocity_tracker_strategy(VelocityTracker::Strategy::STRATEGY_DEFAULT) { | 58 single_tap_repeat_interval(1), |
59 } | 59 velocity_tracker_strategy(VelocityTracker::Strategy::STRATEGY_DEFAULT) {} |
60 | 60 |
61 GestureDetector::Config::~Config() {} | 61 GestureDetector::Config::~Config() {} |
62 | 62 |
63 class GestureDetector::TimeoutGestureHandler { | 63 class GestureDetector::TimeoutGestureHandler { |
64 public: | 64 public: |
65 TimeoutGestureHandler(const Config& config, GestureDetector* gesture_detector) | 65 TimeoutGestureHandler(const Config& config, GestureDetector* gesture_detector) |
66 : gesture_detector_(gesture_detector) { | 66 : gesture_detector_(gesture_detector) { |
67 DCHECK(config.showpress_timeout <= config.longpress_timeout); | 67 DCHECK(config.showpress_timeout <= config.longpress_timeout); |
68 | 68 |
69 timeout_callbacks_[SHOW_PRESS] = &GestureDetector::OnShowPressTimeout; | 69 timeout_callbacks_[SHOW_PRESS] = &GestureDetector::OnShowPressTimeout; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 min_fling_velocity_(1), | 122 min_fling_velocity_(1), |
123 max_fling_velocity_(1), | 123 max_fling_velocity_(1), |
124 min_swipe_velocity_(0), | 124 min_swipe_velocity_(0), |
125 min_swipe_direction_component_ratio_(0), | 125 min_swipe_direction_component_ratio_(0), |
126 still_down_(false), | 126 still_down_(false), |
127 defer_confirm_single_tap_(false), | 127 defer_confirm_single_tap_(false), |
128 always_in_tap_region_(false), | 128 always_in_tap_region_(false), |
129 always_in_bigger_tap_region_(false), | 129 always_in_bigger_tap_region_(false), |
130 two_finger_tap_allowed_for_gesture_(false), | 130 two_finger_tap_allowed_for_gesture_(false), |
131 is_double_tapping_(false), | 131 is_double_tapping_(false), |
| 132 is_down_candidate_for_repeated_single_tap_(false), |
| 133 current_single_tap_repeat_count_(0), |
| 134 single_tap_repeat_interval_(1), |
132 last_focus_x_(0), | 135 last_focus_x_(0), |
133 last_focus_y_(0), | 136 last_focus_y_(0), |
134 down_focus_x_(0), | 137 down_focus_x_(0), |
135 down_focus_y_(0), | 138 down_focus_y_(0), |
136 longpress_enabled_(true), | 139 longpress_enabled_(true), |
137 showpress_enabled_(true), | 140 showpress_enabled_(true), |
138 swipe_enabled_(false), | 141 swipe_enabled_(false), |
139 two_finger_tap_enabled_(false), | 142 two_finger_tap_enabled_(false), |
140 velocity_tracker_(config.velocity_tracker_strategy) { | 143 velocity_tracker_(config.velocity_tracker_strategy) { |
141 DCHECK(listener_); | 144 DCHECK(listener_); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 handled = HandleSwipeIfNeeded(ev, vx_total / count, vy_total / count); | 230 handled = HandleSwipeIfNeeded(ev, vx_total / count, vy_total / count); |
228 | 231 |
229 if (two_finger_tap_allowed_for_gesture_ && ev.GetPointerCount() == 2 && | 232 if (two_finger_tap_allowed_for_gesture_ && ev.GetPointerCount() == 2 && |
230 (ev.GetEventTime() - secondary_pointer_down_event_->GetEventTime() <= | 233 (ev.GetEventTime() - secondary_pointer_down_event_->GetEventTime() <= |
231 two_finger_tap_timeout_)) { | 234 two_finger_tap_timeout_)) { |
232 handled = listener_->OnTwoFingerTap(*current_down_event_, ev); | 235 handled = listener_->OnTwoFingerTap(*current_down_event_, ev); |
233 } | 236 } |
234 two_finger_tap_allowed_for_gesture_ = false; | 237 two_finger_tap_allowed_for_gesture_ = false; |
235 } break; | 238 } break; |
236 | 239 |
237 case MotionEvent::ACTION_DOWN: | 240 case MotionEvent::ACTION_DOWN: { |
| 241 bool is_repeated_tap = |
| 242 current_down_event_ && previous_up_event_ && |
| 243 IsRepeatedTap(*current_down_event_, *previous_up_event_, ev); |
238 if (double_tap_listener_) { | 244 if (double_tap_listener_) { |
| 245 is_down_candidate_for_repeated_single_tap_ = false; |
239 bool had_tap_message = timeout_handler_->HasTimeout(TAP); | 246 bool had_tap_message = timeout_handler_->HasTimeout(TAP); |
240 if (had_tap_message) | 247 if (had_tap_message) |
241 timeout_handler_->StopTimeout(TAP); | 248 timeout_handler_->StopTimeout(TAP); |
242 if (current_down_event_ && previous_up_event_ && had_tap_message && | 249 if (is_repeated_tap && had_tap_message) { |
243 IsConsideredDoubleTap( | |
244 *current_down_event_, *previous_up_event_, ev)) { | |
245 // This is a second tap. | 250 // This is a second tap. |
246 is_double_tapping_ = true; | 251 is_double_tapping_ = true; |
247 // Give a callback with the first tap of the double-tap. | 252 // Give a callback with the first tap of the double-tap. |
248 handled |= double_tap_listener_->OnDoubleTap(*current_down_event_); | 253 handled |= double_tap_listener_->OnDoubleTap(*current_down_event_); |
249 // Give a callback with down event of the double-tap. | 254 // Give a callback with down event of the double-tap. |
250 handled |= double_tap_listener_->OnDoubleTapEvent(ev); | 255 handled |= double_tap_listener_->OnDoubleTapEvent(ev); |
251 } else { | 256 } else { |
252 // This is a first tap. | 257 // This is a first tap. |
253 DCHECK(double_tap_timeout_ > base::TimeDelta()); | 258 DCHECK(double_tap_timeout_ > base::TimeDelta()); |
254 timeout_handler_->StartTimeout(TAP); | 259 timeout_handler_->StartTimeout(TAP); |
255 } | 260 } |
| 261 } else { |
| 262 is_down_candidate_for_repeated_single_tap_ = is_repeated_tap; |
256 } | 263 } |
257 | 264 |
258 down_focus_x_ = last_focus_x_ = focus_x; | 265 down_focus_x_ = last_focus_x_ = focus_x; |
259 down_focus_y_ = last_focus_y_ = focus_y; | 266 down_focus_y_ = last_focus_y_ = focus_y; |
260 current_down_event_ = ev.Clone(); | 267 current_down_event_ = ev.Clone(); |
261 | 268 |
262 secondary_pointer_down_event_.reset(); | 269 secondary_pointer_down_event_.reset(); |
263 always_in_tap_region_ = true; | 270 always_in_tap_region_ = true; |
264 always_in_bigger_tap_region_ = true; | 271 always_in_bigger_tap_region_ = true; |
265 still_down_ = true; | 272 still_down_ = true; |
266 defer_confirm_single_tap_ = false; | 273 defer_confirm_single_tap_ = false; |
267 two_finger_tap_allowed_for_gesture_ = two_finger_tap_enabled_; | 274 two_finger_tap_allowed_for_gesture_ = two_finger_tap_enabled_; |
268 | 275 |
269 // Always start the SHOW_PRESS timer before the LONG_PRESS timer to ensure | 276 // Always start the SHOW_PRESS timer before the LONG_PRESS timer to ensure |
270 // proper timeout ordering. | 277 // proper timeout ordering. |
271 if (showpress_enabled_) | 278 if (showpress_enabled_) |
272 timeout_handler_->StartTimeout(SHOW_PRESS); | 279 timeout_handler_->StartTimeout(SHOW_PRESS); |
273 if (longpress_enabled_) | 280 if (longpress_enabled_) |
274 timeout_handler_->StartTimeout(LONG_PRESS); | 281 timeout_handler_->StartTimeout(LONG_PRESS); |
275 handled |= listener_->OnDown(ev); | 282 handled |= listener_->OnDown(ev); |
276 break; | 283 } break; |
277 | 284 |
278 case MotionEvent::ACTION_MOVE: | 285 case MotionEvent::ACTION_MOVE: |
279 { | 286 { |
280 const float scroll_x = last_focus_x_ - focus_x; | 287 const float scroll_x = last_focus_x_ - focus_x; |
281 const float scroll_y = last_focus_y_ - focus_y; | 288 const float scroll_y = last_focus_y_ - focus_y; |
282 if (is_double_tapping_) { | 289 if (is_double_tapping_) { |
283 // Give the move events of the double-tap. | 290 // Give the move events of the double-tap. |
284 DCHECK(double_tap_listener_); | 291 DCHECK(double_tap_listener_); |
285 handled |= double_tap_listener_->OnDoubleTapEvent(ev); | 292 handled |= double_tap_listener_->OnDoubleTapEvent(ev); |
286 } else if (always_in_tap_region_) { | 293 } else if (always_in_tap_region_) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 break; | 343 break; |
337 | 344 |
338 case MotionEvent::ACTION_UP: | 345 case MotionEvent::ACTION_UP: |
339 still_down_ = false; | 346 still_down_ = false; |
340 { | 347 { |
341 if (is_double_tapping_) { | 348 if (is_double_tapping_) { |
342 // Finally, give the up event of the double-tap. | 349 // Finally, give the up event of the double-tap. |
343 DCHECK(double_tap_listener_); | 350 DCHECK(double_tap_listener_); |
344 handled |= double_tap_listener_->OnDoubleTapEvent(ev); | 351 handled |= double_tap_listener_->OnDoubleTapEvent(ev); |
345 } else if (always_in_tap_region_) { | 352 } else if (always_in_tap_region_) { |
346 handled = listener_->OnSingleTapUp(ev); | 353 if (is_down_candidate_for_repeated_single_tap_) { |
| 354 current_single_tap_repeat_count_ = |
| 355 (1 + current_single_tap_repeat_count_) % |
| 356 single_tap_repeat_interval_; |
| 357 } else { |
| 358 current_single_tap_repeat_count_ = 0; |
| 359 } |
| 360 handled = listener_->OnSingleTapUp( |
| 361 ev, 1 + current_single_tap_repeat_count_); |
347 if (defer_confirm_single_tap_ && double_tap_listener_ != NULL) { | 362 if (defer_confirm_single_tap_ && double_tap_listener_ != NULL) { |
348 double_tap_listener_->OnSingleTapConfirmed(ev); | 363 double_tap_listener_->OnSingleTapConfirmed(ev); |
349 } | 364 } |
350 } else { | 365 } else { |
351 | 366 current_single_tap_repeat_count_ = 0; |
352 // A fling must travel the minimum tap distance. | 367 // A fling must travel the minimum tap distance. |
353 const int pointer_id = ev.GetPointerId(0); | 368 const int pointer_id = ev.GetPointerId(0); |
354 velocity_tracker_.ComputeCurrentVelocity(1000, max_fling_velocity_); | 369 velocity_tracker_.ComputeCurrentVelocity(1000, max_fling_velocity_); |
355 const float velocity_y = velocity_tracker_.GetYVelocity(pointer_id); | 370 const float velocity_y = velocity_tracker_.GetYVelocity(pointer_id); |
356 const float velocity_x = velocity_tracker_.GetXVelocity(pointer_id); | 371 const float velocity_x = velocity_tracker_.GetXVelocity(pointer_id); |
357 | 372 |
358 if ((std::abs(velocity_y) > min_fling_velocity_) || | 373 if ((std::abs(velocity_y) > min_fling_velocity_) || |
359 (std::abs(velocity_x) > min_fling_velocity_)) { | 374 (std::abs(velocity_x) > min_fling_velocity_)) { |
360 handled = listener_->OnFling( | 375 handled = listener_->OnFling( |
361 *current_down_event_, ev, velocity_x, velocity_y); | 376 *current_down_event_, ev, velocity_x, velocity_y); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 DCHECK_LE(config.maximum_swipe_deviation_angle, 45); | 436 DCHECK_LE(config.maximum_swipe_deviation_angle, 45); |
422 const float maximum_swipe_deviation_angle = | 437 const float maximum_swipe_deviation_angle = |
423 std::min(45.f, std::max(0.001f, config.maximum_swipe_deviation_angle)); | 438 std::min(45.f, std::max(0.001f, config.maximum_swipe_deviation_angle)); |
424 min_swipe_direction_component_ratio_ = | 439 min_swipe_direction_component_ratio_ = |
425 1.f / tan(maximum_swipe_deviation_angle * kDegreesToRadians); | 440 1.f / tan(maximum_swipe_deviation_angle * kDegreesToRadians); |
426 | 441 |
427 two_finger_tap_enabled_ = config.two_finger_tap_enabled; | 442 two_finger_tap_enabled_ = config.two_finger_tap_enabled; |
428 two_finger_tap_distance_square_ = config.two_finger_tap_max_separation * | 443 two_finger_tap_distance_square_ = config.two_finger_tap_max_separation * |
429 config.two_finger_tap_max_separation; | 444 config.two_finger_tap_max_separation; |
430 two_finger_tap_timeout_ = config.two_finger_tap_timeout; | 445 two_finger_tap_timeout_ = config.two_finger_tap_timeout; |
| 446 |
| 447 DCHECK_GE(config.single_tap_repeat_interval, 1); |
| 448 single_tap_repeat_interval_ = config.single_tap_repeat_interval; |
431 } | 449 } |
432 | 450 |
433 void GestureDetector::OnShowPressTimeout() { | 451 void GestureDetector::OnShowPressTimeout() { |
434 listener_->OnShowPress(*current_down_event_); | 452 listener_->OnShowPress(*current_down_event_); |
435 } | 453 } |
436 | 454 |
437 void GestureDetector::OnLongPressTimeout() { | 455 void GestureDetector::OnLongPressTimeout() { |
438 timeout_handler_->StopTimeout(TAP); | 456 timeout_handler_->StopTimeout(TAP); |
439 defer_confirm_single_tap_ = false; | 457 defer_confirm_single_tap_ = false; |
440 listener_->OnLongPress(*current_down_event_); | 458 listener_->OnLongPress(*current_down_event_); |
(...skipping 15 matching lines...) Expand all Loading... |
456 velocity_tracker_.Clear(); | 474 velocity_tracker_.Clear(); |
457 still_down_ = false; | 475 still_down_ = false; |
458 } | 476 } |
459 | 477 |
460 void GestureDetector::CancelTaps() { | 478 void GestureDetector::CancelTaps() { |
461 timeout_handler_->Stop(); | 479 timeout_handler_->Stop(); |
462 is_double_tapping_ = false; | 480 is_double_tapping_ = false; |
463 always_in_tap_region_ = false; | 481 always_in_tap_region_ = false; |
464 always_in_bigger_tap_region_ = false; | 482 always_in_bigger_tap_region_ = false; |
465 defer_confirm_single_tap_ = false; | 483 defer_confirm_single_tap_ = false; |
| 484 is_down_candidate_for_repeated_single_tap_ = false; |
| 485 current_single_tap_repeat_count_ = 0; |
466 } | 486 } |
467 | 487 |
468 bool GestureDetector::IsConsideredDoubleTap( | 488 bool GestureDetector::IsRepeatedTap(const MotionEvent& first_down, |
469 const MotionEvent& first_down, | 489 const MotionEvent& first_up, |
470 const MotionEvent& first_up, | 490 const MotionEvent& second_down) const { |
471 const MotionEvent& second_down) const { | |
472 if (!always_in_bigger_tap_region_) | 491 if (!always_in_bigger_tap_region_) |
473 return false; | 492 return false; |
474 | 493 |
475 const base::TimeDelta delta_time = | 494 const base::TimeDelta delta_time = |
476 second_down.GetEventTime() - first_up.GetEventTime(); | 495 second_down.GetEventTime() - first_up.GetEventTime(); |
477 if (delta_time < double_tap_min_time_ || delta_time > double_tap_timeout_) | 496 if (delta_time > double_tap_timeout_) |
| 497 return false; |
| 498 |
| 499 // Only use the min time when in double-tap detection mode. For repeated |
| 500 // single taps the risk of accidental repeat detection (e.g., from fingernail |
| 501 // interference) is minimal. |
| 502 if (double_tap_listener_ && delta_time < double_tap_min_time_) |
478 return false; | 503 return false; |
479 | 504 |
480 const float delta_x = first_down.GetX() - second_down.GetX(); | 505 const float delta_x = first_down.GetX() - second_down.GetX(); |
481 const float delta_y = first_down.GetY() - second_down.GetY(); | 506 const float delta_y = first_down.GetY() - second_down.GetY(); |
482 return (delta_x * delta_x + delta_y * delta_y < double_tap_slop_square_); | 507 return (delta_x * delta_x + delta_y * delta_y < double_tap_slop_square_); |
483 } | 508 } |
484 | 509 |
485 bool GestureDetector::HandleSwipeIfNeeded(const MotionEvent& up, | 510 bool GestureDetector::HandleSwipeIfNeeded(const MotionEvent& up, |
486 float vx, | 511 float vx, |
487 float vy) { | 512 float vy) { |
(...skipping 15 matching lines...) Expand all Loading... |
503 return false; | 528 return false; |
504 | 529 |
505 if (vx_abs > vy_abs) | 530 if (vx_abs > vy_abs) |
506 vy = 0; | 531 vy = 0; |
507 else | 532 else |
508 vx = 0; | 533 vx = 0; |
509 return listener_->OnSwipe(*current_down_event_, up, vx, vy); | 534 return listener_->OnSwipe(*current_down_event_, up, vx, vy); |
510 } | 535 } |
511 | 536 |
512 } // namespace ui | 537 } // namespace ui |
OLD | NEW |