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" | |
8 #include "base/strings/string_number_conversions.h" | 7 #include "base/strings/string_number_conversions.h" |
9 #include "ui/aura/client/cursor_client.h" | 8 #include "ui/aura/client/cursor_client.h" |
10 #include "ui/aura/window.h" | 9 #include "ui/aura/window.h" |
11 #include "ui/aura/window_event_dispatcher.h" | 10 #include "ui/aura/window_event_dispatcher.h" |
12 #include "ui/aura/window_tree_host.h" | 11 #include "ui/aura/window_tree_host.h" |
13 #include "ui/events/event.h" | 12 #include "ui/events/event.h" |
14 #include "ui/events/event_processor.h" | 13 #include "ui/events/event_processor.h" |
| 14 #include "ui/gfx/geometry/rect.h" |
15 | 15 |
16 #define VLOG_STATE() if (VLOG_IS_ON(0)) VlogState(__func__) | 16 #define VLOG_STATE() if (VLOG_IS_ON(0)) VlogState(__func__) |
17 #define VLOG_EVENT(event) if (VLOG_IS_ON(0)) VlogEvent(event, __func__) | 17 #define VLOG_EVENT(event) if (VLOG_IS_ON(0)) VlogEvent(event, __func__) |
18 | 18 |
19 namespace ui { | 19 namespace ui { |
20 | 20 |
21 namespace { | 21 namespace { |
| 22 |
| 23 // Delay between adjustment sounds. |
| 24 const base::TimeDelta kSoundDelay = base::TimeDelta::FromMilliseconds(150); |
| 25 |
| 26 // Within these bounds, the release event generated will reset the state to |
| 27 // NoFingersDown. |
| 28 const float kLeavingScreenEdge = 6; |
| 29 |
| 30 // Swipe/scroll gestures within these bounds (in dips) will change preset |
| 31 // settings. |
| 32 const float kMaxDistanceFromEdge = 75; |
| 33 |
| 34 // After a slide gesture has been triggered, if the finger is still within these |
| 35 // bounds (in DIPs), the preset settings will still change. |
| 36 const float kSlopDistanceFromEdge = kMaxDistanceFromEdge + 40; |
| 37 |
22 // In ChromeOS, VKEY_LWIN is synonymous for the search key. | 38 // In ChromeOS, VKEY_LWIN is synonymous for the search key. |
23 const ui::KeyboardCode kChromeOSSearchKey = ui::VKEY_LWIN; | 39 const ui::KeyboardCode kChromeOSSearchKey = ui::VKEY_LWIN; |
24 } // namespace | 40 } // namespace |
25 | 41 |
26 TouchExplorationController::TouchExplorationController( | 42 TouchExplorationController::TouchExplorationController( |
27 aura::Window* root_window) | 43 aura::Window* root_window, |
| 44 TouchExplorationControllerDelegate* delegate) |
28 : root_window_(root_window), | 45 : root_window_(root_window), |
| 46 delegate_(delegate), |
29 state_(NO_FINGERS_DOWN), | 47 state_(NO_FINGERS_DOWN), |
30 event_handler_for_testing_(NULL), | 48 event_handler_for_testing_(NULL), |
31 gesture_provider_(this), | 49 gesture_provider_(this), |
32 prev_state_(NO_FINGERS_DOWN), | 50 prev_state_(NO_FINGERS_DOWN), |
33 VLOG_on_(true) { | 51 VLOG_on_(true) { |
34 CHECK(root_window); | 52 CHECK(root_window); |
35 root_window->GetHost()->GetEventSource()->AddEventRewriter(this); | 53 root_window->GetHost()->GetEventSource()->AddEventRewriter(this); |
36 } | 54 } |
37 | 55 |
38 | 56 |
(...skipping 21 matching lines...) Expand all Loading... |
60 | 78 |
61 bool TouchExplorationController::IsInNoFingersDownStateForTesting() const { | 79 bool TouchExplorationController::IsInNoFingersDownStateForTesting() const { |
62 return state_ == NO_FINGERS_DOWN; | 80 return state_ == NO_FINGERS_DOWN; |
63 } | 81 } |
64 | 82 |
65 bool TouchExplorationController::IsInGestureInProgressStateForTesting() const { | 83 bool TouchExplorationController::IsInGestureInProgressStateForTesting() const { |
66 return state_ == GESTURE_IN_PROGRESS; | 84 return state_ == GESTURE_IN_PROGRESS; |
67 } | 85 } |
68 | 86 |
69 void TouchExplorationController::SuppressVLOGsForTesting(bool suppress) { | 87 void TouchExplorationController::SuppressVLOGsForTesting(bool suppress) { |
70 VLOG_on_ = !suppress; | 88 VLOG_on_ = !suppress; |
| 89 } |
| 90 |
| 91 gfx::Rect TouchExplorationController::BoundsOfRootWindowInDIPForTesting() { |
| 92 return root_window_->GetBoundsInScreen(); |
| 93 } |
| 94 |
| 95 bool TouchExplorationController::IsInSlideGestureStateForTesting() const { |
| 96 return state_ == SLIDE_GESTURE; |
71 } | 97 } |
72 | 98 |
73 ui::EventRewriteStatus TouchExplorationController::RewriteEvent( | 99 ui::EventRewriteStatus TouchExplorationController::RewriteEvent( |
74 const ui::Event& event, | 100 const ui::Event& event, |
75 scoped_ptr<ui::Event>* rewritten_event) { | 101 scoped_ptr<ui::Event>* rewritten_event) { |
76 if (!event.IsTouchEvent()) { | 102 if (!event.IsTouchEvent()) { |
77 if (event.IsKeyEvent()) { | 103 if (event.IsKeyEvent()) { |
78 const ui::KeyEvent& key_event = static_cast<const ui::KeyEvent&>(event); | 104 const ui::KeyEvent& key_event = static_cast<const ui::KeyEvent&>(event); |
79 VLOG(0) << "\nKeyboard event: " << key_event.name() | 105 VLOG(0) << "\nKeyboard event: " << key_event.name() |
80 << "\n Key code: " << key_event.key_code() | 106 << "\n Key code: " << key_event.key_code() |
(...skipping 20 matching lines...) Expand all Loading... |
101 const ui::EventType type = touch_event.type(); | 127 const ui::EventType type = touch_event.type(); |
102 const gfx::PointF& location = touch_event.location_f(); | 128 const gfx::PointF& location = touch_event.location_f(); |
103 const int touch_id = touch_event.touch_id(); | 129 const int touch_id = touch_event.touch_id(); |
104 | 130 |
105 // Always update touch ids and touch locations, so we can use those | 131 // Always update touch ids and touch locations, so we can use those |
106 // no matter what state we're in. | 132 // no matter what state we're in. |
107 if (type == ui::ET_TOUCH_PRESSED) { | 133 if (type == ui::ET_TOUCH_PRESSED) { |
108 current_touch_ids_.push_back(touch_id); | 134 current_touch_ids_.push_back(touch_id); |
109 touch_locations_.insert(std::pair<int, gfx::PointF>(touch_id, location)); | 135 touch_locations_.insert(std::pair<int, gfx::PointF>(touch_id, location)); |
110 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { | 136 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { |
| 137 // In order to avoid accidentally double tapping when moving off the edge of |
| 138 // the screen, the state will be rewritten to NoFingersDown. |
| 139 TouchEvent touch_event = static_cast<const TouchEvent&>(event); |
| 140 if (WithinBoundsOfEdge(touch_event.location(), kLeavingScreenEdge) != |
| 141 SCREEN_CENTER) { |
| 142 if (current_touch_ids_.size() == 0) |
| 143 ResetToNoFingersDown(); |
| 144 else |
| 145 state_ = WAIT_FOR_RELEASE; |
| 146 } |
| 147 |
111 std::vector<int>::iterator it = std::find( | 148 std::vector<int>::iterator it = std::find( |
112 current_touch_ids_.begin(), current_touch_ids_.end(), touch_id); | 149 current_touch_ids_.begin(), current_touch_ids_.end(), touch_id); |
113 | 150 |
114 // Can happen if touch exploration is enabled while fingers were down. | 151 // Can happen if touch exploration is enabled while fingers were down. |
115 if (it == current_touch_ids_.end()) | 152 if (it == current_touch_ids_.end()) |
116 return ui::EVENT_REWRITE_CONTINUE; | 153 return ui::EVENT_REWRITE_CONTINUE; |
117 | 154 |
118 current_touch_ids_.erase(it); | 155 current_touch_ids_.erase(it); |
119 touch_locations_.erase(touch_id); | 156 touch_locations_.erase(touch_id); |
120 } else if (type == ui::ET_TOUCH_MOVED) { | 157 } else if (type == ui::ET_TOUCH_MOVED) { |
(...skipping 24 matching lines...) Expand all Loading... |
145 case GESTURE_IN_PROGRESS: | 182 case GESTURE_IN_PROGRESS: |
146 return InGestureInProgress(touch_event, rewritten_event); | 183 return InGestureInProgress(touch_event, rewritten_event); |
147 case TOUCH_EXPLORE_SECOND_PRESS: | 184 case TOUCH_EXPLORE_SECOND_PRESS: |
148 return InTouchExploreSecondPress(touch_event, rewritten_event); | 185 return InTouchExploreSecondPress(touch_event, rewritten_event); |
149 case TWO_TO_ONE_FINGER: | 186 case TWO_TO_ONE_FINGER: |
150 return InTwoToOneFinger(touch_event, rewritten_event); | 187 return InTwoToOneFinger(touch_event, rewritten_event); |
151 case PASSTHROUGH: | 188 case PASSTHROUGH: |
152 return InPassthrough(touch_event, rewritten_event); | 189 return InPassthrough(touch_event, rewritten_event); |
153 case WAIT_FOR_RELEASE: | 190 case WAIT_FOR_RELEASE: |
154 return InWaitForRelease(touch_event, rewritten_event); | 191 return InWaitForRelease(touch_event, rewritten_event); |
| 192 case SLIDE_GESTURE: |
| 193 return InSlideGesture(touch_event, rewritten_event); |
155 } | 194 } |
156 NOTREACHED(); | 195 NOTREACHED(); |
157 return ui::EVENT_REWRITE_CONTINUE; | 196 return ui::EVENT_REWRITE_CONTINUE; |
158 } | 197 } |
159 | 198 |
160 ui::EventRewriteStatus TouchExplorationController::NextDispatchEvent( | 199 ui::EventRewriteStatus TouchExplorationController::NextDispatchEvent( |
161 const ui::Event& last_event, scoped_ptr<ui::Event>* new_event) { | 200 const ui::Event& last_event, scoped_ptr<ui::Event>* new_event) { |
162 NOTREACHED(); | 201 NOTREACHED(); |
163 return ui::EVENT_REWRITE_CONTINUE; | 202 return ui::EVENT_REWRITE_CONTINUE; |
164 } | 203 } |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 | 254 |
216 float delta_time = | 255 float delta_time = |
217 (event.time_stamp() - initial_press_->time_stamp()).InSecondsF(); | 256 (event.time_stamp() - initial_press_->time_stamp()).InSecondsF(); |
218 float velocity = distance / delta_time; | 257 float velocity = distance / delta_time; |
219 VLOG(0) << "\n Delta time: " << delta_time | 258 VLOG(0) << "\n Delta time: " << delta_time |
220 << "\n Distance: " << distance | 259 << "\n Distance: " << distance |
221 << "\n Velocity of click: " << velocity | 260 << "\n Velocity of click: " << velocity |
222 << "\n Minimum swipe velocity: " | 261 << "\n Minimum swipe velocity: " |
223 << gesture_detector_config_.minimum_swipe_velocity; | 262 << gesture_detector_config_.minimum_swipe_velocity; |
224 | 263 |
| 264 // Change to slide gesture if the slide occurred at the right edge. |
| 265 int where = WithinBoundsOfEdge(event.location(), kMaxDistanceFromEdge); |
| 266 if (where & RIGHT_EDGE) { |
| 267 state_ = SLIDE_GESTURE; |
| 268 VLOG_STATE(); |
| 269 return InSlideGesture(event, rewritten_event); |
| 270 } |
| 271 |
225 // If the user moves fast enough from the initial touch location, start | 272 // If the user moves fast enough from the initial touch location, start |
226 // gesture detection. Otherwise, jump to the touch exploration mode early. | 273 // gesture detection. Otherwise, jump to the touch exploration mode early. |
227 if (velocity > gesture_detector_config_.minimum_swipe_velocity) { | 274 if (velocity > gesture_detector_config_.minimum_swipe_velocity) { |
228 state_ = GESTURE_IN_PROGRESS; | 275 state_ = GESTURE_IN_PROGRESS; |
229 VLOG_STATE(); | 276 VLOG_STATE(); |
230 return InGestureInProgress(event, rewritten_event); | 277 return InGestureInProgress(event, rewritten_event); |
231 } | 278 } |
232 EnterTouchToMouseMode(); | 279 EnterTouchToMouseMode(); |
233 state_ = TOUCH_EXPLORATION; | 280 state_ = TOUCH_EXPLORATION; |
234 VLOG_STATE(); | 281 VLOG_STATE(); |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 if (current_touch_ids_.size() != 1) | 542 if (current_touch_ids_.size() != 1) |
496 return EVENT_REWRITE_DISCARD; | 543 return EVENT_REWRITE_DISCARD; |
497 | 544 |
498 // Rewrite at location of last touch exploration. | 545 // Rewrite at location of last touch exploration. |
499 rewritten_event->reset( | 546 rewritten_event->reset( |
500 new ui::TouchEvent(ui::ET_TOUCH_RELEASED, | 547 new ui::TouchEvent(ui::ET_TOUCH_RELEASED, |
501 last_touch_exploration_->location(), | 548 last_touch_exploration_->location(), |
502 initial_press_->touch_id(), | 549 initial_press_->touch_id(), |
503 event.time_stamp())); | 550 event.time_stamp())); |
504 (*rewritten_event)->set_flags(event.flags()); | 551 (*rewritten_event)->set_flags(event.flags()); |
| 552 EnterTouchToMouseMode(); |
505 state_ = TOUCH_EXPLORATION; | 553 state_ = TOUCH_EXPLORATION; |
506 EnterTouchToMouseMode(); | 554 EnterTouchToMouseMode(); |
507 VLOG_STATE(); | 555 VLOG_STATE(); |
508 return ui::EVENT_REWRITE_REWRITTEN; | 556 return ui::EVENT_REWRITE_REWRITTEN; |
509 } | 557 } |
510 NOTREACHED() << "Unexpected event type received: " << event.name(); | 558 NOTREACHED() << "Unexpected event type received: " << event.name(); |
511 return ui::EVENT_REWRITE_CONTINUE; | 559 return ui::EVENT_REWRITE_CONTINUE; |
512 } | 560 } |
513 | 561 |
514 ui::EventRewriteStatus TouchExplorationController::InWaitForRelease( | 562 ui::EventRewriteStatus TouchExplorationController::InWaitForRelease( |
515 const ui::TouchEvent& event, | 563 const ui::TouchEvent& event, |
516 scoped_ptr<ui::Event>* rewritten_event) { | 564 scoped_ptr<ui::Event>* rewritten_event) { |
517 ui::EventType type = event.type(); | 565 ui::EventType type = event.type(); |
518 if (!(type == ui::ET_TOUCH_PRESSED || type == ui::ET_TOUCH_MOVED || | 566 if (!(type == ui::ET_TOUCH_PRESSED || type == ui::ET_TOUCH_MOVED || |
519 type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED)) { | 567 type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED)) { |
520 NOTREACHED() << "Unexpected event type received: " << event.name(); | 568 NOTREACHED() << "Unexpected event type received: " << event.name(); |
521 return ui::EVENT_REWRITE_CONTINUE; | 569 return ui::EVENT_REWRITE_CONTINUE; |
522 } | 570 } |
523 if (current_touch_ids_.size() == 0) { | 571 if (current_touch_ids_.size() == 0) { |
524 state_ = NO_FINGERS_DOWN; | 572 state_ = NO_FINGERS_DOWN; |
525 VLOG_STATE(); | 573 VLOG_STATE(); |
526 ResetToNoFingersDown(); | 574 ResetToNoFingersDown(); |
527 } | 575 } |
528 return EVENT_REWRITE_DISCARD; | 576 return EVENT_REWRITE_DISCARD; |
529 } | 577 } |
530 | 578 |
| 579 void TouchExplorationController::PlaySoundForTimer() { |
| 580 delegate_->PlayVolumeAdjustSound(); |
| 581 } |
| 582 |
| 583 ui::EventRewriteStatus TouchExplorationController::InSlideGesture( |
| 584 const ui::TouchEvent& event, |
| 585 scoped_ptr<ui::Event>* rewritten_event) { |
| 586 // The timer should not fire when sliding. |
| 587 if (tap_timer_.IsRunning()) |
| 588 tap_timer_.Stop(); |
| 589 |
| 590 ui::EventType type = event.type(); |
| 591 // If additional fingers are added before a swipe gesture has been registered, |
| 592 // then wait until all fingers have been lifted. |
| 593 if (type == ui::ET_TOUCH_PRESSED || |
| 594 event.touch_id() != initial_press_->touch_id()) { |
| 595 if (sound_timer_.IsRunning()) |
| 596 sound_timer_.Stop(); |
| 597 // Discard any pending gestures. |
| 598 ignore_result(gesture_provider_.GetAndResetPendingGestures()); |
| 599 state_ = WAIT_FOR_RELEASE; |
| 600 return EVENT_REWRITE_DISCARD; |
| 601 } |
| 602 |
| 603 // Allows user to return to the edge to adjust the sound if they have left the |
| 604 // boundaries. |
| 605 int where = WithinBoundsOfEdge(event.location(), kSlopDistanceFromEdge); |
| 606 if (!(where & RIGHT_EDGE) && (type != ui::ET_TOUCH_RELEASED)) { |
| 607 if (sound_timer_.IsRunning()) { |
| 608 sound_timer_.Stop(); |
| 609 } |
| 610 return EVENT_REWRITE_DISCARD; |
| 611 } |
| 612 |
| 613 // This can occur if the user leaves the screen edge and then returns to it to |
| 614 // continue adjusting the sound. |
| 615 if (!sound_timer_.IsRunning()) { |
| 616 sound_timer_.Start(FROM_HERE, |
| 617 kSoundDelay, |
| 618 this, |
| 619 &ui::TouchExplorationController::PlaySoundForTimer); |
| 620 delegate_->PlayVolumeAdjustSound(); |
| 621 } |
| 622 |
| 623 // There should not be more than one finger down. |
| 624 DCHECK(current_touch_ids_.size() <= 1); |
| 625 if (type == ui::ET_TOUCH_MOVED) { |
| 626 gesture_provider_.OnTouchEvent(event); |
| 627 gesture_provider_.OnTouchEventAck(false); |
| 628 } |
| 629 if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { |
| 630 gesture_provider_.OnTouchEvent(event); |
| 631 gesture_provider_.OnTouchEventAck(false); |
| 632 ignore_result(gesture_provider_.GetAndResetPendingGestures()); |
| 633 if (current_touch_ids_.size() == 0) |
| 634 ResetToNoFingersDown(); |
| 635 return ui::EVENT_REWRITE_DISCARD; |
| 636 } |
| 637 |
| 638 ProcessGestureEvents(); |
| 639 return ui::EVENT_REWRITE_DISCARD; |
| 640 } |
| 641 |
531 void TouchExplorationController::OnTapTimerFired() { | 642 void TouchExplorationController::OnTapTimerFired() { |
532 switch (state_) { | 643 switch (state_) { |
533 case SINGLE_TAP_RELEASED: | 644 case SINGLE_TAP_RELEASED: |
534 ResetToNoFingersDown(); | 645 ResetToNoFingersDown(); |
535 break; | 646 break; |
536 case TOUCH_EXPLORE_RELEASED: | 647 case TOUCH_EXPLORE_RELEASED: |
537 ResetToNoFingersDown(); | 648 ResetToNoFingersDown(); |
538 last_touch_exploration_.reset(new TouchEvent(*initial_press_)); | 649 last_touch_exploration_.reset(new TouchEvent(*initial_press_)); |
539 return; | 650 return; |
540 case SINGLE_TAP_PRESSED: | 651 case SINGLE_TAP_PRESSED: |
541 case GESTURE_IN_PROGRESS: | 652 case GESTURE_IN_PROGRESS: |
542 // Discard any pending gestures. | 653 // Discard any pending gestures. |
543 ignore_result(gesture_provider_.GetAndResetPendingGestures()); | 654 ignore_result(gesture_provider_.GetAndResetPendingGestures()); |
544 EnterTouchToMouseMode(); | 655 EnterTouchToMouseMode(); |
545 state_ = TOUCH_EXPLORATION; | 656 state_ = TOUCH_EXPLORATION; |
546 VLOG_STATE(); | 657 VLOG_STATE(); |
547 break; | 658 break; |
548 default: | 659 default: |
549 return; | 660 return; |
550 } | 661 } |
551 scoped_ptr<ui::Event> mouse_move = | 662 scoped_ptr<ui::Event> mouse_move = |
552 CreateMouseMoveEvent(initial_press_->location(), initial_press_->flags()); | 663 CreateMouseMoveEvent(initial_press_->location(), initial_press_->flags()); |
553 DispatchEvent(mouse_move.get()); | 664 DispatchEvent(mouse_move.get()); |
554 last_touch_exploration_.reset(new TouchEvent(*initial_press_)); | 665 last_touch_exploration_.reset(new TouchEvent(*initial_press_)); |
555 } | 666 } |
556 | 667 |
557 void TouchExplorationController::DispatchEvent(ui::Event* event) { | 668 void TouchExplorationController::DispatchEvent(ui::Event* event) { |
558 if (event_handler_for_testing_) { | 669 if (event_handler_for_testing_) { |
559 event_handler_for_testing_->OnEvent(event); | 670 event_handler_for_testing_->OnEvent(event); |
560 return; | 671 return; |
561 } | 672 } |
562 ui::EventDispatchDetails result ALLOW_UNUSED = | 673 ui::EventDispatchDetails result ALLOW_UNUSED = |
563 root_window_->GetHost()->dispatcher()->OnEventFromSource(event); | 674 root_window_->GetHost()->dispatcher()->OnEventFromSource(event); |
564 } | 675 } |
565 | 676 |
566 void TouchExplorationController::OnGestureEvent(ui::GestureEvent* gesture) { | 677 void TouchExplorationController::OnGestureEvent( |
| 678 ui::GestureEvent* gesture) { |
567 CHECK(gesture->IsGestureEvent()); | 679 CHECK(gesture->IsGestureEvent()); |
| 680 ui::EventType type = gesture->type(); |
568 VLOG(0) << " \n Gesture Triggered: " << gesture->name(); | 681 VLOG(0) << " \n Gesture Triggered: " << gesture->name(); |
569 if (gesture->type() == ui::ET_GESTURE_SWIPE) { | 682 if (type == ui::ET_GESTURE_SWIPE && state_ != SLIDE_GESTURE) { |
570 if (tap_timer_.IsRunning()) | 683 VLOG(0) << "Swipe!"; |
571 tap_timer_.Stop(); | 684 ignore_result(gesture_provider_.GetAndResetPendingGestures()); |
572 OnSwipeEvent(gesture); | 685 OnSwipeEvent(gesture); |
573 return; | 686 return; |
574 } | 687 } |
575 } | 688 } |
576 | 689 |
577 void TouchExplorationController::ProcessGestureEvents() { | 690 void TouchExplorationController::ProcessGestureEvents() { |
578 scoped_ptr<ScopedVector<ui::GestureEvent> > gestures( | 691 scoped_ptr<ScopedVector<ui::GestureEvent> > gestures( |
579 gesture_provider_.GetAndResetPendingGestures()); | 692 gesture_provider_.GetAndResetPendingGestures()); |
580 if (gestures) { | 693 if (gestures) { |
581 for (ScopedVector<GestureEvent>::iterator i = gestures->begin(); | 694 for (ScopedVector<GestureEvent>::iterator i = gestures->begin(); |
582 i != gestures->end(); | 695 i != gestures->end(); |
583 ++i) { | 696 ++i) { |
584 OnGestureEvent(*i); | 697 if (state_ == SLIDE_GESTURE) |
| 698 SideSlideControl(*i); |
| 699 else |
| 700 OnGestureEvent(*i); |
585 } | 701 } |
586 } | 702 } |
587 } | 703 } |
588 | 704 |
| 705 void TouchExplorationController::SideSlideControl(ui::GestureEvent* gesture) { |
| 706 ui::EventType type = gesture->type(); |
| 707 if (!gesture->IsScrollGestureEvent()) |
| 708 return; |
| 709 |
| 710 if (type == ET_GESTURE_SCROLL_BEGIN) { |
| 711 delegate_->PlayVolumeAdjustSound(); |
| 712 } |
| 713 |
| 714 if (type == ET_GESTURE_SCROLL_END) { |
| 715 if (sound_timer_.IsRunning()) |
| 716 sound_timer_.Stop(); |
| 717 delegate_->PlayVolumeAdjustSound(); |
| 718 } |
| 719 |
| 720 // If the user is in the corner of the right side of the screen, the volume |
| 721 // will be automatically set to 100% or muted depending on which corner they |
| 722 // are in. Otherwise, the user will be able to adjust the volume by sliding |
| 723 // their finger along the right side of the screen. Volume is relative to |
| 724 // where they are on the right side of the screen. |
| 725 gfx::Point location = gesture->location(); |
| 726 int where = WithinBoundsOfEdge(location, kSlopDistanceFromEdge); |
| 727 if (!(where & RIGHT_EDGE)) |
| 728 return; |
| 729 |
| 730 if (where == RIGHT_EDGE) { |
| 731 location = gesture->location(); |
| 732 root_window_->GetHost()->ConvertPointFromNativeScreen(&location); |
| 733 float volume_adjust_height = |
| 734 root_window_->bounds().height() - 2 * kMaxDistanceFromEdge; |
| 735 float ratio = (location.y() - kMaxDistanceFromEdge) / volume_adjust_height; |
| 736 float volume = 100 - 100 * ratio; |
| 737 VLOG(0) << "\n Volume = " << volume |
| 738 << "\n Location = " << location.ToString() |
| 739 << "\n Bounds = " << root_window_->bounds().right(); |
| 740 |
| 741 delegate_->SetOutputLevel(int(volume)); |
| 742 return; |
| 743 } |
| 744 else if (where & TOP_EDGE) { |
| 745 delegate_->SetOutputLevel(100); |
| 746 return; |
| 747 } else if (where & BOTTOM_EDGE) { |
| 748 delegate_->SetOutputLevel(0); |
| 749 return; |
| 750 } |
| 751 NOTREACHED() << "Invalid location " << where; |
| 752 } |
| 753 |
| 754 |
589 void TouchExplorationController::OnSwipeEvent(ui::GestureEvent* swipe_gesture) { | 755 void TouchExplorationController::OnSwipeEvent(ui::GestureEvent* swipe_gesture) { |
590 // A swipe gesture contains details for the direction in which the swipe | 756 // A swipe gesture contains details for the direction in which the swipe |
591 // occurred. | 757 // occurred. |
592 GestureEventDetails event_details = swipe_gesture->details(); | 758 GestureEventDetails event_details = swipe_gesture->details(); |
593 if (event_details.swipe_left()) { | 759 if (event_details.swipe_left()) { |
594 DispatchShiftSearchKeyEvent(ui::VKEY_LEFT); | 760 DispatchShiftSearchKeyEvent(ui::VKEY_LEFT); |
595 return; | 761 return; |
596 } else if (event_details.swipe_right()) { | 762 } else if (event_details.swipe_right()) { |
597 DispatchShiftSearchKeyEvent(ui::VKEY_RIGHT); | 763 DispatchShiftSearchKeyEvent(ui::VKEY_RIGHT); |
598 return; | 764 return; |
599 } else if (event_details.swipe_up()) { | 765 } else if (event_details.swipe_up()) { |
600 DispatchShiftSearchKeyEvent(ui::VKEY_UP); | 766 DispatchShiftSearchKeyEvent(ui::VKEY_UP); |
601 return; | 767 return; |
602 } else if (event_details.swipe_down()) { | 768 } else if (event_details.swipe_down()) { |
603 DispatchShiftSearchKeyEvent(ui::VKEY_DOWN); | 769 DispatchShiftSearchKeyEvent(ui::VKEY_DOWN); |
604 return; | 770 return; |
605 } | 771 } |
606 } | 772 } |
607 | 773 |
| 774 int TouchExplorationController::WithinBoundsOfEdge(gfx::Point point, |
| 775 float bounds) { |
| 776 // Since GetBoundsInScreen is in DIPs but point is not, then point needs to be |
| 777 // converted. |
| 778 root_window_->GetHost()->ConvertPointFromNativeScreen(&point); |
| 779 gfx::Rect window = root_window_->GetBoundsInScreen(); |
| 780 |
| 781 float left_edge_limit = window.x() + bounds; |
| 782 float right_edge_limit = window.right() - bounds; |
| 783 float top_edge_limit = window.y() + bounds; |
| 784 float bottom_edge_limit = window.bottom() - bounds; |
| 785 |
| 786 // Bitwise manipulation in order to determine where on the screen the point |
| 787 // lies. If more than one bit is turned on, then it is a corner where the two |
| 788 // bit/edges intersect. Otherwise, if no bits are turned on, the point must be |
| 789 // in the center of the screen. |
| 790 int result = SCREEN_CENTER; |
| 791 if (point.x() < left_edge_limit) |
| 792 result |= LEFT_EDGE; |
| 793 if (point.x() > right_edge_limit) |
| 794 result |= RIGHT_EDGE; |
| 795 if (point.y() < top_edge_limit) |
| 796 result |= TOP_EDGE; |
| 797 if (point.y() > bottom_edge_limit) |
| 798 result |= BOTTOM_EDGE; |
| 799 return result; |
| 800 } |
| 801 |
608 void TouchExplorationController::DispatchShiftSearchKeyEvent( | 802 void TouchExplorationController::DispatchShiftSearchKeyEvent( |
609 const ui::KeyboardCode direction) { | 803 const ui::KeyboardCode direction) { |
610 // In order to activate the shortcut shift+search+<arrow key> | 804 // In order to activate the shortcut shift+search+<arrow key> |
611 // three KeyPressed events must be dispatched in succession along | 805 // three KeyPressed events must be dispatched in succession along |
612 // with three KeyReleased events. | 806 // with three KeyReleased events. |
613 ui::KeyEvent shift_down = ui::KeyEvent( | 807 ui::KeyEvent shift_down = ui::KeyEvent( |
614 ui::ET_KEY_PRESSED, ui::VKEY_SHIFT, ui::EF_SHIFT_DOWN, false); | 808 ui::ET_KEY_PRESSED, ui::VKEY_SHIFT, ui::EF_SHIFT_DOWN, false); |
615 ui::KeyEvent search_down = ui::KeyEvent( | 809 ui::KeyEvent search_down = ui::KeyEvent( |
616 ui::ET_KEY_PRESSED, kChromeOSSearchKey, ui::EF_SHIFT_DOWN, false); | 810 ui::ET_KEY_PRESSED, kChromeOSSearchKey, ui::EF_SHIFT_DOWN, false); |
617 ui::KeyEvent direction_down = | 811 ui::KeyEvent direction_down = |
(...skipping 29 matching lines...) Expand all Loading... |
647 void TouchExplorationController::EnterTouchToMouseMode() { | 841 void TouchExplorationController::EnterTouchToMouseMode() { |
648 aura::client::CursorClient* cursor_client = | 842 aura::client::CursorClient* cursor_client = |
649 aura::client::GetCursorClient(root_window_); | 843 aura::client::GetCursorClient(root_window_); |
650 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) | 844 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) |
651 cursor_client->EnableMouseEvents(); | 845 cursor_client->EnableMouseEvents(); |
652 if (cursor_client && cursor_client->IsCursorVisible()) | 846 if (cursor_client && cursor_client->IsCursorVisible()) |
653 cursor_client->HideCursor(); | 847 cursor_client->HideCursor(); |
654 } | 848 } |
655 | 849 |
656 void TouchExplorationController::ResetToNoFingersDown() { | 850 void TouchExplorationController::ResetToNoFingersDown() { |
| 851 ProcessGestureEvents(); |
| 852 if (sound_timer_.IsRunning()) |
| 853 sound_timer_.Stop(); |
657 state_ = NO_FINGERS_DOWN; | 854 state_ = NO_FINGERS_DOWN; |
658 VLOG_STATE(); | 855 VLOG_STATE(); |
659 if (tap_timer_.IsRunning()) | 856 if (tap_timer_.IsRunning()) |
660 tap_timer_.Stop(); | 857 tap_timer_.Stop(); |
661 } | 858 } |
662 | 859 |
663 void TouchExplorationController::VlogState(const char* function_name) { | 860 void TouchExplorationController::VlogState(const char* function_name) { |
664 if (!VLOG_on_) | 861 if (!VLOG_on_) |
665 return; | 862 return; |
666 if (prev_state_ == state_) | 863 if (prev_state_ == state_) |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
718 case GESTURE_IN_PROGRESS: | 915 case GESTURE_IN_PROGRESS: |
719 return "GESTURE_IN_PROGRESS"; | 916 return "GESTURE_IN_PROGRESS"; |
720 case TOUCH_EXPLORE_SECOND_PRESS: | 917 case TOUCH_EXPLORE_SECOND_PRESS: |
721 return "TOUCH_EXPLORE_SECOND_PRESS"; | 918 return "TOUCH_EXPLORE_SECOND_PRESS"; |
722 case TWO_TO_ONE_FINGER: | 919 case TWO_TO_ONE_FINGER: |
723 return "TWO_TO_ONE_FINGER"; | 920 return "TWO_TO_ONE_FINGER"; |
724 case PASSTHROUGH: | 921 case PASSTHROUGH: |
725 return "PASSTHROUGH"; | 922 return "PASSTHROUGH"; |
726 case WAIT_FOR_RELEASE: | 923 case WAIT_FOR_RELEASE: |
727 return "WAIT_FOR_RELEASE"; | 924 return "WAIT_FOR_RELEASE"; |
| 925 case SLIDE_GESTURE: |
| 926 return "SLIDE_GESTURE"; |
728 } | 927 } |
729 return "Not a state"; | 928 return "Not a state"; |
730 } | 929 } |
731 | 930 |
732 } // namespace ui | 931 } // namespace ui |
OLD | NEW |