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