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 #include "ui/chromeos/touch_exploration_controller.h" | 5 #include "ui/chromeos/touch_exploration_controller.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/strings/string_number_conversions.h" | 8 #include "base/strings/string_number_conversions.h" |
9 #include "base/time/default_tick_clock.h" | 9 #include "base/time/default_tick_clock.h" |
10 #include "ui/aura/client/cursor_client.h" | 10 #include "ui/aura/client/cursor_client.h" |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 ProcessGestureEvents(); | 154 ProcessGestureEvents(); |
155 } | 155 } |
156 | 156 |
157 // The rest of the processing depends on what state we're in. | 157 // The rest of the processing depends on what state we're in. |
158 switch (state_) { | 158 switch (state_) { |
159 case NO_FINGERS_DOWN: | 159 case NO_FINGERS_DOWN: |
160 return InNoFingersDown(touch_event, rewritten_event); | 160 return InNoFingersDown(touch_event, rewritten_event); |
161 case SINGLE_TAP_PRESSED: | 161 case SINGLE_TAP_PRESSED: |
162 return InSingleTapPressed(touch_event, rewritten_event); | 162 return InSingleTapPressed(touch_event, rewritten_event); |
163 case SINGLE_TAP_RELEASED: | 163 case SINGLE_TAP_RELEASED: |
164 return InSingleTapReleased(touch_event, rewritten_event); | |
165 case TOUCH_EXPLORE_RELEASED: | 164 case TOUCH_EXPLORE_RELEASED: |
166 return InTouchExploreReleased(touch_event, rewritten_event); | 165 return InSingleTapOrTouchExploreReleased(touch_event, rewritten_event); |
167 case DOUBLE_TAP_PENDING: | 166 case DOUBLE_TAP_PENDING: |
168 return InDoubleTapPending(touch_event, rewritten_event); | 167 return InDoubleTapPending(touch_event, rewritten_event); |
169 case TOUCH_RELEASE_PENDING: | 168 case TOUCH_RELEASE_PENDING: |
170 return InTouchReleasePending(touch_event, rewritten_event); | 169 return InTouchReleasePending(touch_event, rewritten_event); |
171 case TOUCH_EXPLORATION: | 170 case TOUCH_EXPLORATION: |
172 return InTouchExploration(touch_event, rewritten_event); | 171 return InTouchExploration(touch_event, rewritten_event); |
173 case GESTURE_IN_PROGRESS: | 172 case GESTURE_IN_PROGRESS: |
174 return InGestureInProgress(touch_event, rewritten_event); | 173 return InGestureInProgress(touch_event, rewritten_event); |
175 case TOUCH_EXPLORE_SECOND_PRESS: | 174 case TOUCH_EXPLORE_SECOND_PRESS: |
176 return InTouchExploreSecondPress(touch_event, rewritten_event); | 175 return InTouchExploreSecondPress(touch_event, rewritten_event); |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
296 } | 295 } |
297 EnterTouchToMouseMode(); | 296 EnterTouchToMouseMode(); |
298 SET_STATE(TOUCH_EXPLORATION); | 297 SET_STATE(TOUCH_EXPLORATION); |
299 return InTouchExploration(event, rewritten_event); | 298 return InTouchExploration(event, rewritten_event); |
300 } | 299 } |
301 NOTREACHED(); | 300 NOTREACHED(); |
302 return ui::EVENT_REWRITE_CONTINUE; | 301 return ui::EVENT_REWRITE_CONTINUE; |
303 } | 302 } |
304 | 303 |
305 ui::EventRewriteStatus | 304 ui::EventRewriteStatus |
306 TouchExplorationController::InSingleTapReleased( | 305 TouchExplorationController::InSingleTapOrTouchExploreReleased( |
307 const ui::TouchEvent& event, | 306 const ui::TouchEvent& event, |
308 scoped_ptr<ui::Event>* rewritten_event) { | 307 scoped_ptr<ui::Event>* rewritten_event) { |
309 const ui::EventType type = event.type(); | 308 const ui::EventType type = event.type(); |
310 // If there is more than one finger down, then discard to wait until no | 309 // If there is more than one finger down, then discard to wait until no |
311 // fingers are down. | 310 // fingers are down. |
312 if (current_touch_ids_.size() > 1) { | 311 if (current_touch_ids_.size() > 1) { |
313 SET_STATE(WAIT_FOR_NO_FINGERS); | 312 SET_STATE(WAIT_FOR_NO_FINGERS); |
314 return ui::EVENT_REWRITE_DISCARD; | 313 return ui::EVENT_REWRITE_DISCARD; |
315 } | 314 } |
316 if (type == ui::ET_TOUCH_PRESSED) { | 315 if (type == ui::ET_TOUCH_PRESSED) { |
317 // If there is no touch exploration yet, we can't send a click, so discard | 316 // If there is no touch exploration yet, we can't send a click, so discard. |
318 // and wait for no fingers. | |
319 if (!last_touch_exploration_) { | 317 if (!last_touch_exploration_) { |
320 tap_timer_.Stop(); | 318 tap_timer_.Stop(); |
321 SET_STATE(WAIT_FOR_NO_FINGERS); | |
322 return ui::EVENT_REWRITE_DISCARD; | 319 return ui::EVENT_REWRITE_DISCARD; |
323 } | 320 } |
324 // This is the second tap in a double-tap (or double tap-hold). | 321 // This is the second tap in a double-tap (or double tap-hold). |
325 // We set the passthrough timer. If it fires before the user lifts their | 322 // We set the tap timer. If it fires before the user lifts their finger, |
326 // finger, one-finger passthrough begins. Otherwise, there is a touch | 323 // one-finger passthrough begins. Otherwise, there is a touch press and |
327 // press and release at the location of the last touch exploration. | 324 // release at the location of the last touch exploration. |
328 SET_STATE(DOUBLE_TAP_PENDING); | 325 SET_STATE(DOUBLE_TAP_PENDING); |
329 // Initial press now holds the intial double tap press - this event. | |
330 initial_press_.reset(new ui::TouchEvent(event)); | |
331 // The old tap timer (from the initial click) is stopped if it is still | 326 // The old tap timer (from the initial click) is stopped if it is still |
332 // going, and the passthrough timer is set. | 327 // going, and the new one is set. |
333 tap_timer_.Stop(); | 328 tap_timer_.Stop(); |
334 passthrough_timer_.Start( | 329 StartTapTimer(); |
335 FROM_HERE, | |
336 gesture_detector_config_.longpress_timeout, | |
337 this, | |
338 &TouchExplorationController::OnPassthroughTimerFired); | |
339 // This will update as the finger moves before a possible passthrough, and | 330 // This will update as the finger moves before a possible passthrough, and |
340 // will determine the offset. | 331 // will determine the offset. |
341 last_unused_finger_event_.reset(new ui::TouchEvent(event)); | 332 last_unused_finger_event_.reset(new ui::TouchEvent(event)); |
342 return ui::EVENT_REWRITE_DISCARD; | 333 return ui::EVENT_REWRITE_DISCARD; |
| 334 } else if (type == ui::ET_TOUCH_RELEASED && !last_touch_exploration_) { |
| 335 // If the previous press was discarded, we need to also handle its |
| 336 // release. |
| 337 if (current_touch_ids_.size() == 0) { |
| 338 SET_STATE(NO_FINGERS_DOWN); |
| 339 } |
| 340 return ui::EVENT_REWRITE_DISCARD; |
343 } else if (type == ui::ET_TOUCH_MOVED) { | 341 } else if (type == ui::ET_TOUCH_MOVED) { |
344 return ui::EVENT_REWRITE_DISCARD; | 342 return ui::EVENT_REWRITE_DISCARD; |
345 } | 343 } |
346 NOTREACHED(); | |
347 return ui::EVENT_REWRITE_CONTINUE; | |
348 } | |
349 | |
350 ui::EventRewriteStatus | |
351 TouchExplorationController::InTouchExploreReleased( | |
352 const ui::TouchEvent& event, | |
353 scoped_ptr<ui::Event>* rewritten_event) { | |
354 const ui::EventType type = event.type(); | |
355 // If there is more than one finger down, then discard to wait until no | |
356 // fingers are down. | |
357 if (current_touch_ids_.size() > 1) { | |
358 SET_STATE(WAIT_FOR_NO_FINGERS); | |
359 return ui::EVENT_REWRITE_DISCARD; | |
360 } | |
361 if (type == ui::ET_TOUCH_PRESSED) { | |
362 // This is the initial "press" (location, time, and touch id) of a single | |
363 // tap click. | |
364 initial_press_.reset(new ui::TouchEvent(event)); | |
365 rewritten_event->reset( | |
366 new ui::TouchEvent(ui::ET_TOUCH_PRESSED, | |
367 last_touch_exploration_->location(), | |
368 initial_press_->touch_id(), | |
369 event.time_stamp())); | |
370 (*rewritten_event)->set_flags(event.flags()); | |
371 SET_STATE(TOUCH_RELEASE_PENDING); | |
372 return ui::EVENT_REWRITE_REWRITTEN; | |
373 } else if (type == ui::ET_TOUCH_MOVED) { | |
374 return ui::EVENT_REWRITE_DISCARD; | |
375 } | |
376 NOTREACHED(); | 344 NOTREACHED(); |
377 return ui::EVENT_REWRITE_CONTINUE; | 345 return ui::EVENT_REWRITE_CONTINUE; |
378 } | 346 } |
379 | 347 |
380 ui::EventRewriteStatus TouchExplorationController::InDoubleTapPending( | 348 ui::EventRewriteStatus TouchExplorationController::InDoubleTapPending( |
381 const ui::TouchEvent& event, | 349 const ui::TouchEvent& event, |
382 scoped_ptr<ui::Event>* rewritten_event) { | 350 scoped_ptr<ui::Event>* rewritten_event) { |
383 const ui::EventType type = event.type(); | 351 const ui::EventType type = event.type(); |
384 if (type == ui::ET_TOUCH_PRESSED) { | 352 if (type == ui::ET_TOUCH_PRESSED) { |
385 return ui::EVENT_REWRITE_DISCARD; | 353 return ui::EVENT_REWRITE_DISCARD; |
386 } else if (type == ui::ET_TOUCH_MOVED) { | 354 } else if (type == ui::ET_TOUCH_MOVED) { |
387 // If the user moves far enough from the initial touch location (outside | 355 // If the user moves far enough from the initial touch location (outside |
388 // the "slop" region, jump to passthrough mode early. | 356 // the "slop" region, jump to passthrough mode early. |
389 float delta = (event.location() - initial_press_->location()).Length(); | 357 float delta = (event.location() - initial_press_->location()).Length(); |
390 if (delta > gesture_detector_config_.touch_slop) { | 358 if (delta > gesture_detector_config_.touch_slop) { |
391 passthrough_timer_.Stop(); | 359 tap_timer_.Stop(); |
392 if (VLOG_on_) | 360 OnTapTimerFired(); |
393 VLOG(0) << "Finger left slop and is entering passthrough"; | |
394 OnPassthroughTimerFired(); | |
395 } | 361 } |
396 return EVENT_REWRITE_DISCARD; | 362 return EVENT_REWRITE_DISCARD; |
397 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { | 363 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { |
398 if (current_touch_ids_.size() != 0) | 364 if (current_touch_ids_.size() != 0) |
399 return EVENT_REWRITE_DISCARD; | 365 return EVENT_REWRITE_DISCARD; |
400 | 366 |
401 // Now it is recognized that the user was doing a double tap to click. | |
402 // The passthrough timer is stopped and a touch press and release are | |
403 // dispatched. | |
404 passthrough_timer_.Stop(); | |
405 | |
406 scoped_ptr<ui::TouchEvent> touch_press; | 367 scoped_ptr<ui::TouchEvent> touch_press; |
407 touch_press.reset(new ui::TouchEvent(ui::ET_TOUCH_PRESSED, | 368 touch_press.reset(new ui::TouchEvent(ui::ET_TOUCH_PRESSED, |
408 last_touch_exploration_->location(), | 369 last_touch_exploration_->location(), |
409 initial_press_->touch_id(), | 370 initial_press_->touch_id(), |
410 event.time_stamp())); | 371 event.time_stamp())); |
411 DispatchEvent(touch_press.get()); | 372 DispatchEvent(touch_press.get()); |
412 | 373 |
413 rewritten_event->reset( | 374 rewritten_event->reset( |
414 new ui::TouchEvent(ui::ET_TOUCH_RELEASED, | 375 new ui::TouchEvent(ui::ET_TOUCH_RELEASED, |
415 last_touch_exploration_->location(), | 376 last_touch_exploration_->location(), |
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
736 | 697 |
737 void TouchExplorationController::OnTapTimerFired() { | 698 void TouchExplorationController::OnTapTimerFired() { |
738 switch (state_) { | 699 switch (state_) { |
739 case SINGLE_TAP_RELEASED: | 700 case SINGLE_TAP_RELEASED: |
740 SET_STATE(NO_FINGERS_DOWN); | 701 SET_STATE(NO_FINGERS_DOWN); |
741 break; | 702 break; |
742 case TOUCH_EXPLORE_RELEASED: | 703 case TOUCH_EXPLORE_RELEASED: |
743 SET_STATE(NO_FINGERS_DOWN); | 704 SET_STATE(NO_FINGERS_DOWN); |
744 last_touch_exploration_.reset(new TouchEvent(*initial_press_)); | 705 last_touch_exploration_.reset(new TouchEvent(*initial_press_)); |
745 return; | 706 return; |
| 707 case DOUBLE_TAP_PENDING: { |
| 708 SET_STATE(ONE_FINGER_PASSTHROUGH); |
| 709 passthrough_offset_ = last_unused_finger_event_->location() - |
| 710 last_touch_exploration_->location(); |
| 711 scoped_ptr<ui::TouchEvent> passthrough_press( |
| 712 new ui::TouchEvent(ui::ET_TOUCH_PRESSED, |
| 713 last_touch_exploration_->location(), |
| 714 last_unused_finger_event_->touch_id(), |
| 715 Now())); |
| 716 DispatchEvent(passthrough_press.get()); |
| 717 return; |
| 718 } |
746 case SINGLE_TAP_PRESSED: | 719 case SINGLE_TAP_PRESSED: |
747 if (passthrough_timer_.IsRunning()) | 720 if (passthrough_timer_.IsRunning()) |
748 return; | 721 return; |
749 case GESTURE_IN_PROGRESS: | 722 case GESTURE_IN_PROGRESS: |
750 // If only one finger is down, go into touch exploration. | 723 // If only one finger is down, go into touch exploration. |
751 if (current_touch_ids_.size() == 1) { | 724 if (current_touch_ids_.size() == 1) { |
752 EnterTouchToMouseMode(); | 725 EnterTouchToMouseMode(); |
753 SET_STATE(TOUCH_EXPLORATION); | 726 SET_STATE(TOUCH_EXPLORATION); |
754 break; | 727 break; |
755 } | 728 } |
756 // Otherwise wait for all fingers to be lifted. | 729 // Otherwise wait for all fingers to be lifted. |
757 SET_STATE(WAIT_FOR_NO_FINGERS); | 730 SET_STATE(WAIT_FOR_NO_FINGERS); |
758 return; | 731 return; |
759 case TWO_FINGER_TAP: | 732 case TWO_FINGER_TAP: |
760 SET_STATE(WAIT_FOR_NO_FINGERS); | 733 SET_STATE(WAIT_FOR_NO_FINGERS); |
761 break; | 734 break; |
762 default: | 735 default: |
763 NOTREACHED() << "tap timer fired in unrecognized state: " | |
764 << EnumStateToString(state_); | |
765 return; | 736 return; |
766 } | 737 } |
767 EnterTouchToMouseMode(); | 738 EnterTouchToMouseMode(); |
768 scoped_ptr<ui::Event> mouse_move = | 739 scoped_ptr<ui::Event> mouse_move = |
769 CreateMouseMoveEvent(initial_press_->location(), initial_press_->flags()); | 740 CreateMouseMoveEvent(initial_press_->location(), initial_press_->flags()); |
770 DispatchEvent(mouse_move.get()); | 741 DispatchEvent(mouse_move.get()); |
771 last_touch_exploration_.reset(new TouchEvent(*initial_press_)); | 742 last_touch_exploration_.reset(new TouchEvent(*initial_press_)); |
772 } | 743 } |
773 | 744 |
774 void TouchExplorationController::OnPassthroughTimerFired() { | 745 void TouchExplorationController::OnPassthroughTimerFired() { |
775 switch (state_) { | 746 // The passthrough timer will only fire if if the user has held a finger in |
776 case SINGLE_TAP_PRESSED: | 747 // one of the passthrough corners for the duration of the passthrough timeout. |
777 case TOUCH_EXPLORATION: | |
778 case GESTURE_IN_PROGRESS: { | |
779 // The timer will only fire in this state if if the user has held a finger | |
780 // in one of the passthrough corners for the duration of the passthrough | |
781 // timeout. | |
782 | 748 |
783 // Check that initial press isn't null. Also a check that if the initial | 749 // Check that initial press isn't null. Also a check that if the initial |
784 // corner press was released, then it should not be in corner passthrough. | 750 // corner press was released, then it should not be in corner passthrough. |
785 if (!initial_press_ || | 751 if (!initial_press_ || |
786 touch_locations_.find(initial_press_->touch_id()) != | 752 touch_locations_.find(initial_press_->touch_id()) != |
787 touch_locations_.end()) { | 753 touch_locations_.end()) { |
788 LOG(ERROR) | 754 LOG(ERROR) << "No initial press or the initial press has been released."; |
789 << "No initial press or the initial press has been released."; | 755 } |
790 } | |
791 | 756 |
792 gfx::Point location = | 757 gfx::Point location = |
793 ToRoundedPoint(touch_locations_[initial_press_->touch_id()]); | 758 ToRoundedPoint(touch_locations_[initial_press_->touch_id()]); |
794 int corner = FindEdgesWithinBounds(location, kSlopDistanceFromEdge); | 759 int corner = FindEdgesWithinBounds(location, kSlopDistanceFromEdge); |
795 if (corner != BOTTOM_LEFT_CORNER && corner != BOTTOM_RIGHT_CORNER) | 760 if (corner != BOTTOM_LEFT_CORNER && corner != BOTTOM_RIGHT_CORNER) |
796 return; | 761 return; |
797 | 762 |
798 SET_STATE(CORNER_PASSTHROUGH); | |
799 break; | |
800 } | |
801 case DOUBLE_TAP_PENDING: { | |
802 // Enter one finger passthrough mode. | |
803 SET_STATE(ONE_FINGER_PASSTHROUGH); | |
804 passthrough_offset_ = last_unused_finger_event_->location() - | |
805 last_touch_exploration_->location(); | |
806 scoped_ptr<ui::TouchEvent> passthrough_press( | |
807 new ui::TouchEvent(ui::ET_TOUCH_PRESSED, | |
808 last_touch_exploration_->location(), | |
809 last_unused_finger_event_->touch_id(), | |
810 Now())); | |
811 DispatchEvent(passthrough_press.get()); | |
812 break; | |
813 } | |
814 default: | |
815 NOTREACHED() << "passthrough timer fired in unrecognized state" | |
816 << EnumStateToString(state_); | |
817 return; | |
818 } | |
819 if (sound_timer_.IsRunning()) | 763 if (sound_timer_.IsRunning()) |
820 sound_timer_.Stop(); | 764 sound_timer_.Stop(); |
821 delegate_->PlayPassthroughEarcon(); | 765 delegate_->PlayPassthroughEarcon(); |
| 766 SET_STATE(CORNER_PASSTHROUGH); |
| 767 return; |
822 } | 768 } |
823 | 769 |
824 void TouchExplorationController::DispatchEvent(ui::Event* event) { | 770 void TouchExplorationController::DispatchEvent(ui::Event* event) { |
825 ui::EventDispatchDetails result ALLOW_UNUSED = | 771 ui::EventDispatchDetails result ALLOW_UNUSED = |
826 root_window_->GetHost()->dispatcher()->OnEventFromSource(event); | 772 root_window_->GetHost()->dispatcher()->OnEventFromSource(event); |
827 } | 773 } |
828 | 774 |
829 // This is an override for a function that is only called for timer-based events | 775 // This is an override for a function that is only called for timer-based events |
830 // like long press. Events that are created synchronously as a result of | 776 // like long press. Events that are created synchronously as a result of |
831 // certain touch events are added to the vector accessible via | 777 // certain touch events are added to the vector accessible via |
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1201 up_swipe_gestures_[4] = BindKeyEventWithFlags(VKEY_BROWSER_HOME, ui::EF_NONE); | 1147 up_swipe_gestures_[4] = BindKeyEventWithFlags(VKEY_BROWSER_HOME, ui::EF_NONE); |
1202 down_swipe_gestures_[4] = | 1148 down_swipe_gestures_[4] = |
1203 BindKeyEventWithFlags(VKEY_BROWSER_REFRESH, ui::EF_NONE); | 1149 BindKeyEventWithFlags(VKEY_BROWSER_REFRESH, ui::EF_NONE); |
1204 } | 1150 } |
1205 | 1151 |
1206 const float TouchExplorationController::GetSplitTapTouchSlop() { | 1152 const float TouchExplorationController::GetSplitTapTouchSlop() { |
1207 return gesture_detector_config_.touch_slop * 3; | 1153 return gesture_detector_config_.touch_slop * 3; |
1208 } | 1154 } |
1209 | 1155 |
1210 } // namespace ui | 1156 } // namespace ui |
OLD | NEW |