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

Side by Side Diff: ui/events/gesture_detection/gesture_detector.cc

Issue 2058723003: Slop region check for multi-finger scroll (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 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
OLDNEW
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 <stddef.h> 10 #include <stddef.h>
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 touch_slop_square_(0), 123 touch_slop_square_(0),
124 double_tap_touch_slop_square_(0), 124 double_tap_touch_slop_square_(0),
125 double_tap_slop_square_(0), 125 double_tap_slop_square_(0),
126 two_finger_tap_distance_square_(0), 126 two_finger_tap_distance_square_(0),
127 min_fling_velocity_(1), 127 min_fling_velocity_(1),
128 max_fling_velocity_(1), 128 max_fling_velocity_(1),
129 min_swipe_velocity_(0), 129 min_swipe_velocity_(0),
130 min_swipe_direction_component_ratio_(0), 130 min_swipe_direction_component_ratio_(0),
131 still_down_(false), 131 still_down_(false),
132 defer_confirm_single_tap_(false), 132 defer_confirm_single_tap_(false),
133 always_in_tap_region_(false), 133 all_pointers_within_slop_regions_(false),
134 always_in_bigger_tap_region_(false), 134 always_in_bigger_tap_region_(false),
135 two_finger_tap_allowed_for_gesture_(false), 135 two_finger_tap_allowed_for_gesture_(false),
136 is_double_tapping_(false), 136 is_double_tapping_(false),
137 is_down_candidate_for_repeated_single_tap_(false), 137 is_down_candidate_for_repeated_single_tap_(false),
138 maximum_pointer_count_(0),
138 current_single_tap_repeat_count_(0), 139 current_single_tap_repeat_count_(0),
139 single_tap_repeat_interval_(1), 140 single_tap_repeat_interval_(1),
140 last_focus_x_(0), 141 last_focus_x_(0),
141 last_focus_y_(0), 142 last_focus_y_(0),
142 down_focus_x_(0), 143 down_focus_x_(0),
143 down_focus_y_(0), 144 down_focus_y_(0),
144 longpress_enabled_(true), 145 longpress_enabled_(true),
145 showpress_enabled_(true), 146 showpress_enabled_(true),
146 swipe_enabled_(false), 147 swipe_enabled_(false),
147 two_finger_tap_enabled_(false), 148 two_finger_tap_enabled_(false),
(...skipping 30 matching lines...) Expand all
178 switch (action) { 179 switch (action) {
179 case MotionEvent::ACTION_NONE: 180 case MotionEvent::ACTION_NONE:
180 NOTREACHED(); 181 NOTREACHED();
181 return handled; 182 return handled;
182 183
183 case MotionEvent::ACTION_POINTER_DOWN: { 184 case MotionEvent::ACTION_POINTER_DOWN: {
184 down_focus_x_ = last_focus_x_ = focus_x; 185 down_focus_x_ = last_focus_x_ = focus_x;
185 down_focus_y_ = last_focus_y_ = focus_y; 186 down_focus_y_ = last_focus_y_ = focus_y;
186 // Cancel long press and taps. 187 // Cancel long press and taps.
187 CancelTaps(); 188 CancelTaps();
189 maximum_pointer_count_ = std::max(maximum_pointer_count_,
190 static_cast<int>(ev.GetPointerCount()));
191
192 // Even when two_finger_tap_allowed_for_gesture_ is false,
193 // second pointer down information must be stored to check
194 // the slop region in multi-finger scrolls.
195 if (ev.GetPointerCount() == 2)
196 secondary_pointer_down_event_ = ev.Clone();
188 197
189 if (!two_finger_tap_allowed_for_gesture_) 198 if (!two_finger_tap_allowed_for_gesture_)
190 break; 199 break;
191 200
192 const int action_index = ev.GetActionIndex(); 201 const int action_index = ev.GetActionIndex();
193 const float dx = ev.GetX(action_index) - current_down_event_->GetX(); 202 const float dx = ev.GetX(action_index) - current_down_event_->GetX();
194 const float dy = ev.GetY(action_index) - current_down_event_->GetY(); 203 const float dy = ev.GetY(action_index) - current_down_event_->GetY();
195 204
196 if (ev.GetPointerCount() == 2 && 205 if (maximum_pointer_count_ > 2 ||
197 dx * dx + dy * dy < two_finger_tap_distance_square_) { 206 dx * dx + dy * dy >= two_finger_tap_distance_square_)
198 secondary_pointer_down_event_ = ev.Clone();
199 } else {
200 two_finger_tap_allowed_for_gesture_ = false; 207 two_finger_tap_allowed_for_gesture_ = false;
201 }
202 } break; 208 } break;
203 209
204 case MotionEvent::ACTION_POINTER_UP: { 210 case MotionEvent::ACTION_POINTER_UP: {
205 down_focus_x_ = last_focus_x_ = focus_x; 211 down_focus_x_ = last_focus_x_ = focus_x;
206 down_focus_y_ = last_focus_y_ = focus_y; 212 down_focus_y_ = last_focus_y_ = focus_y;
207 213
208 // Check the dot product of current velocities. 214 // Check the dot product of current velocities.
209 // If the pointer that left was opposing another velocity vector, clear. 215 // If the pointer that left was opposing another velocity vector, clear.
210 velocity_tracker_.ComputeCurrentVelocity(1000, max_fling_velocity_); 216 velocity_tracker_.ComputeCurrentVelocity(1000, max_fling_velocity_);
211 const int up_index = ev.GetActionIndex(); 217 const int up_index = ev.GetActionIndex();
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 } 271 }
266 } else { 272 } else {
267 is_down_candidate_for_repeated_single_tap_ = is_repeated_tap; 273 is_down_candidate_for_repeated_single_tap_ = is_repeated_tap;
268 } 274 }
269 275
270 down_focus_x_ = last_focus_x_ = focus_x; 276 down_focus_x_ = last_focus_x_ = focus_x;
271 down_focus_y_ = last_focus_y_ = focus_y; 277 down_focus_y_ = last_focus_y_ = focus_y;
272 current_down_event_ = ev.Clone(); 278 current_down_event_ = ev.Clone();
273 279
274 secondary_pointer_down_event_.reset(); 280 secondary_pointer_down_event_.reset();
275 always_in_tap_region_ = true; 281 all_pointers_within_slop_regions_ = true;
276 always_in_bigger_tap_region_ = true; 282 always_in_bigger_tap_region_ = true;
277 still_down_ = true; 283 still_down_ = true;
278 defer_confirm_single_tap_ = false; 284 defer_confirm_single_tap_ = false;
279 two_finger_tap_allowed_for_gesture_ = two_finger_tap_enabled_; 285 two_finger_tap_allowed_for_gesture_ = two_finger_tap_enabled_;
286 maximum_pointer_count_ = 1;
280 287
281 // Always start the SHOW_PRESS timer before the LONG_PRESS timer to ensure 288 // Always start the SHOW_PRESS timer before the LONG_PRESS timer to ensure
282 // proper timeout ordering. 289 // proper timeout ordering.
283 if (showpress_enabled_) 290 if (showpress_enabled_)
284 timeout_handler_->StartTimeout(SHOW_PRESS); 291 timeout_handler_->StartTimeout(SHOW_PRESS);
285 if (longpress_enabled_) 292 if (longpress_enabled_)
286 timeout_handler_->StartTimeout(LONG_PRESS); 293 timeout_handler_->StartTimeout(LONG_PRESS);
287 handled |= listener_->OnDown(ev); 294 handled |= listener_->OnDown(ev);
288 } break; 295 } break;
289 296
290 case MotionEvent::ACTION_MOVE: 297 case MotionEvent::ACTION_MOVE:
291 { 298 {
292 const float scroll_x = last_focus_x_ - focus_x; 299 const float scroll_x = last_focus_x_ - focus_x;
293 const float scroll_y = last_focus_y_ - focus_y; 300 const float scroll_y = last_focus_y_ - focus_y;
294 if (is_double_tapping_) { 301 if (is_double_tapping_) {
295 // Give the move events of the double-tap. 302 // Give the move events of the double-tap.
296 DCHECK(double_tap_listener_); 303 DCHECK(double_tap_listener_);
297 handled |= double_tap_listener_->OnDoubleTapEvent(ev); 304 handled |= double_tap_listener_->OnDoubleTapEvent(ev);
298 } else if (always_in_tap_region_) { 305 } else if (all_pointers_within_slop_regions_) {
306 if (!IsWithinTouchSlop(ev)) {
307 handled = listener_->OnScroll(
308 *current_down_event_, ev,
309 (ev.GetPointerCount() > 1 ? *secondary_pointer_down_event_
310 : ev),
311 scroll_x, scroll_y);
312 last_focus_x_ = focus_x;
313 last_focus_y_ = focus_y;
314 all_pointers_within_slop_regions_ = false;
315 timeout_handler_->Stop();
316 }
317
299 const float delta_x = focus_x - down_focus_x_; 318 const float delta_x = focus_x - down_focus_x_;
300 const float delta_y = focus_y - down_focus_y_; 319 const float delta_y = focus_y - down_focus_y_;
301 const float distance_square = delta_x * delta_x + delta_y * delta_y; 320 const float distance_square = delta_x * delta_x + delta_y * delta_y;
302 if (distance_square > touch_slop_square_) {
303 handled = listener_->OnScroll(
304 *current_down_event_, ev, scroll_x, scroll_y);
305 last_focus_x_ = focus_x;
306 last_focus_y_ = focus_y;
307 always_in_tap_region_ = false;
308 timeout_handler_->Stop();
309 }
310 if (distance_square > double_tap_touch_slop_square_) 321 if (distance_square > double_tap_touch_slop_square_)
311 always_in_bigger_tap_region_ = false; 322 always_in_bigger_tap_region_ = false;
312 } else if (std::abs(scroll_x) > kScrollEpsilon || 323 } else if (std::abs(scroll_x) > kScrollEpsilon ||
313 std::abs(scroll_y) > kScrollEpsilon) { 324 std::abs(scroll_y) > kScrollEpsilon) {
314 // We should eventually apply touch slop for multi-finger 325 handled = listener_->OnScroll(
315 // scrolls as well as single finger scrolls. See 326 *current_down_event_, ev,
316 // crbug.com/492185 for details. 327 (ev.GetPointerCount() > 1 ? *secondary_pointer_down_event_ : ev),
317 handled = 328 scroll_x, scroll_y);
318 listener_->OnScroll(*current_down_event_, ev, scroll_x, scroll_y);
319 last_focus_x_ = focus_x; 329 last_focus_x_ = focus_x;
320 last_focus_y_ = focus_y; 330 last_focus_y_ = focus_y;
321 } 331 }
322 332
323 if (!two_finger_tap_allowed_for_gesture_) 333 if (!two_finger_tap_allowed_for_gesture_)
324 break; 334 break;
325 335
326 // Two-finger tap should be prevented if either pointer exceeds its 336 // Two-finger tap should be prevented if either pointer exceeds its
327 // (independent) slop region. 337 // (independent) slop region.
328 const int id0 = current_down_event_->GetPointerId(0); 338 // If the event has had more than two pointers down at any time,
329 const int ev_idx0 = ev.GetPointerId(0) == id0 ? 0 : 1; 339 // two finger tap should be prevented.
330 340 if (maximum_pointer_count_ > 2 || !IsWithinTouchSlop(ev)) {
331 // Check if the primary pointer exceeded the slop region.
332 float dx = current_down_event_->GetX() - ev.GetX(ev_idx0);
333 float dy = current_down_event_->GetY() - ev.GetY(ev_idx0);
334 if (dx * dx + dy * dy > touch_slop_square_) {
335 two_finger_tap_allowed_for_gesture_ = false; 341 two_finger_tap_allowed_for_gesture_ = false;
336 break;
337 }
338 if (ev.GetPointerCount() == 2) {
339 // Check if the secondary pointer exceeded the slop region.
340 const int ev_idx1 = ev_idx0 == 0 ? 1 : 0;
341 const int idx1 = secondary_pointer_down_event_->GetActionIndex();
342 dx = secondary_pointer_down_event_->GetX(idx1) - ev.GetX(ev_idx1);
343 dy = secondary_pointer_down_event_->GetY(idx1) - ev.GetY(ev_idx1);
344 if (dx * dx + dy * dy > touch_slop_square_)
345 two_finger_tap_allowed_for_gesture_ = false;
346 } 342 }
347 } 343 }
348 break; 344 break;
349 345
350 case MotionEvent::ACTION_UP: 346 case MotionEvent::ACTION_UP:
351 still_down_ = false; 347 still_down_ = false;
352 { 348 {
353 if (is_double_tapping_) { 349 if (is_double_tapping_) {
354 // Finally, give the up event of the double-tap. 350 // Finally, give the up event of the double-tap.
355 DCHECK(double_tap_listener_); 351 DCHECK(double_tap_listener_);
356 handled |= double_tap_listener_->OnDoubleTapEvent(ev); 352 handled |= double_tap_listener_->OnDoubleTapEvent(ev);
357 } else if (always_in_tap_region_) { 353 } else if (all_pointers_within_slop_regions_ &&
354 maximum_pointer_count_ == 1) {
358 if (is_down_candidate_for_repeated_single_tap_) { 355 if (is_down_candidate_for_repeated_single_tap_) {
359 current_single_tap_repeat_count_ = 356 current_single_tap_repeat_count_ =
360 (1 + current_single_tap_repeat_count_) % 357 (1 + current_single_tap_repeat_count_) %
361 single_tap_repeat_interval_; 358 single_tap_repeat_interval_;
362 } else { 359 } else {
363 current_single_tap_repeat_count_ = 0; 360 current_single_tap_repeat_count_ = 0;
364 } 361 }
365 handled = listener_->OnSingleTapUp( 362 handled = listener_->OnSingleTapUp(
366 ev, 1 + current_single_tap_repeat_count_); 363 ev, 1 + current_single_tap_repeat_count_);
367 if (defer_confirm_single_tap_ && double_tap_listener_ != NULL) { 364 if (defer_confirm_single_tap_ && double_tap_listener_ != NULL) {
(...skipping 17 matching lines...) Expand all
385 } 382 }
386 383
387 previous_up_event_ = ev.Clone(); 384 previous_up_event_ = ev.Clone();
388 385
389 velocity_tracker_.Clear(); 386 velocity_tracker_.Clear();
390 is_double_tapping_ = false; 387 is_double_tapping_ = false;
391 defer_confirm_single_tap_ = false; 388 defer_confirm_single_tap_ = false;
392 timeout_handler_->StopTimeout(SHOW_PRESS); 389 timeout_handler_->StopTimeout(SHOW_PRESS);
393 timeout_handler_->StopTimeout(LONG_PRESS); 390 timeout_handler_->StopTimeout(LONG_PRESS);
394 } 391 }
392 maximum_pointer_count_ = 0;
395 break; 393 break;
396 394
397 case MotionEvent::ACTION_CANCEL: 395 case MotionEvent::ACTION_CANCEL:
398 Cancel(); 396 Cancel();
399 break; 397 break;
400 } 398 }
401 399
402 return handled; 400 return handled;
403 } 401 }
404 402
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 CHECK(previous_up_event_); 468 CHECK(previous_up_event_);
471 double_tap_listener_->OnSingleTapConfirmed(*previous_up_event_); 469 double_tap_listener_->OnSingleTapConfirmed(*previous_up_event_);
472 } else { 470 } else {
473 defer_confirm_single_tap_ = true; 471 defer_confirm_single_tap_ = true;
474 } 472 }
475 } 473 }
476 474
477 void GestureDetector::Cancel() { 475 void GestureDetector::Cancel() {
478 CancelTaps(); 476 CancelTaps();
479 velocity_tracker_.Clear(); 477 velocity_tracker_.Clear();
478 all_pointers_within_slop_regions_ = false;
480 still_down_ = false; 479 still_down_ = false;
481 } 480 }
482 481
483 void GestureDetector::CancelTaps() { 482 void GestureDetector::CancelTaps() {
484 timeout_handler_->Stop(); 483 timeout_handler_->Stop();
485 is_double_tapping_ = false; 484 is_double_tapping_ = false;
486 always_in_tap_region_ = false;
487 always_in_bigger_tap_region_ = false; 485 always_in_bigger_tap_region_ = false;
488 defer_confirm_single_tap_ = false; 486 defer_confirm_single_tap_ = false;
489 is_down_candidate_for_repeated_single_tap_ = false; 487 is_down_candidate_for_repeated_single_tap_ = false;
490 current_single_tap_repeat_count_ = 0; 488 current_single_tap_repeat_count_ = 0;
491 } 489 }
492 490
493 bool GestureDetector::IsRepeatedTap(const MotionEvent& first_down, 491 bool GestureDetector::IsRepeatedTap(const MotionEvent& first_down,
494 const MotionEvent& first_up, 492 const MotionEvent& first_up,
495 const MotionEvent& second_down) const { 493 const MotionEvent& second_down) const {
496 if (!always_in_bigger_tap_region_) 494 if (!always_in_bigger_tap_region_)
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
532 if (ratio < min_swipe_direction_component_ratio_) 530 if (ratio < min_swipe_direction_component_ratio_)
533 return false; 531 return false;
534 532
535 if (vx_abs > vy_abs) 533 if (vx_abs > vy_abs)
536 vy = 0; 534 vy = 0;
537 else 535 else
538 vx = 0; 536 vx = 0;
539 return listener_->OnSwipe(*current_down_event_, up, vx, vy); 537 return listener_->OnSwipe(*current_down_event_, up, vx, vy);
540 } 538 }
541 539
540 bool GestureDetector::IsWithinTouchSlop(const MotionEvent& ev) {
541 // If there are more than two down pointers, tapping is not possible.
542 // Slop region check is not needed.
543 if (ev.GetPointerCount() > 2)
544 return false;
545
546 const int id0 = current_down_event_->GetPointerId(0);
547 const int ev_idx0 = ev.GetPointerId(0) == id0 ? 0 : 1;
548
549 // Check if the primary pointer exceeded the slop region.
550 float dx = current_down_event_->GetX() - ev.GetX(ev_idx0);
551 float dy = current_down_event_->GetY() - ev.GetY(ev_idx0);
552 if (dx * dx + dy * dy > touch_slop_square_)
553 return false;
554
555 if (ev.GetPointerCount() == 2) {
556 // Check if the secondary pointer exceeded the slop region.
557 const int ev_idx1 = ev_idx0 == 0 ? 1 : 0;
558 const int idx1 = secondary_pointer_down_event_->GetActionIndex();
559 dx = secondary_pointer_down_event_->GetX(idx1) - ev.GetX(ev_idx1);
560 dy = secondary_pointer_down_event_->GetY(idx1) - ev.GetY(ev_idx1);
561 if (dx * dx + dy * dy > touch_slop_square_)
562 return false;
563 }
564
565 return true;
566 }
567
542 } // namespace ui 568 } // namespace ui
OLDNEW
« no previous file with comments | « ui/events/gesture_detection/gesture_detector.h ('k') | ui/events/gesture_detection/gesture_listeners.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698