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