| Index: ui/chromeos/touch_exploration_controller.cc
|
| diff --git a/ui/chromeos/touch_exploration_controller.cc b/ui/chromeos/touch_exploration_controller.cc
|
| index 96b4e436dee2cd93392d974e5773669c7b469307..8b91009ce21777f02d766b1be1f78b34714dba6d 100644
|
| --- a/ui/chromeos/touch_exploration_controller.cc
|
| +++ b/ui/chromeos/touch_exploration_controller.cc
|
| @@ -26,6 +26,10 @@ namespace {
|
| // Delay between adjustment sounds.
|
| const base::TimeDelta kSoundDelay = base::TimeDelta::FromMilliseconds(150);
|
|
|
| +// Delay before corner passthrough activates.
|
| +const base::TimeDelta kCornerPassthroughDelay =
|
| + base::TimeDelta::FromMilliseconds(700);
|
| +
|
| // In ChromeOS, VKEY_LWIN is synonymous for the search key.
|
| const ui::KeyboardCode kChromeOSSearchKey = ui::VKEY_LWIN;
|
| } // namespace
|
| @@ -77,6 +81,13 @@ ui::EventRewriteStatus TouchExplorationController::RewriteEvent(
|
| // this event under this new state.
|
| }
|
|
|
| + if (passthrough_timer_.IsRunning() &&
|
| + event.time_stamp() - initial_press_->time_stamp() >
|
| + gesture_detector_config_.longpress_timeout) {
|
| + passthrough_timer_.Stop();
|
| + OnPassthroughTimerFired();
|
| + }
|
| +
|
| const ui::EventType type = touch_event.type();
|
| const gfx::PointF& location = touch_event.location_f();
|
| const int touch_id = touch_event.touch_id();
|
| @@ -116,6 +127,12 @@ ui::EventRewriteStatus TouchExplorationController::RewriteEvent(
|
| if ((type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) &&
|
| FindEdgesWithinBounds(touch_event.location(), kLeavingScreenEdge) !=
|
| NO_EDGE) {
|
| + if (VLOG_on_)
|
| + VLOG(0) << "Leaving screen";
|
| +
|
| + // Indicates to the user that they are leaving the screen.
|
| + delegate_->PlayExitScreenEarcon();
|
| +
|
| if (current_touch_ids_.size() == 0) {
|
| SET_STATE(NO_FINGERS_DOWN);
|
| if (VLOG_on_) {
|
| @@ -156,6 +173,8 @@ ui::EventRewriteStatus TouchExplorationController::RewriteEvent(
|
| return InGestureInProgress(touch_event, rewritten_event);
|
| case TOUCH_EXPLORE_SECOND_PRESS:
|
| return InTouchExploreSecondPress(touch_event, rewritten_event);
|
| + case CORNER_PASSTHROUGH:
|
| + return InCornerPassthrough(touch_event, rewritten_event);
|
| case SLIDE_GESTURE:
|
| return InSlideGesture(touch_event, rewritten_event);
|
| case ONE_FINGER_PASSTHROUGH:
|
| @@ -177,28 +196,66 @@ ui::EventRewriteStatus TouchExplorationController::NextDispatchEvent(
|
|
|
| ui::EventRewriteStatus TouchExplorationController::InNoFingersDown(
|
| const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) {
|
| - ui::EventType type = event.type();
|
| - if (type == ui::ET_TOUCH_PRESSED) {
|
| - initial_press_.reset(new TouchEvent(event));
|
| - initial_presses_[event.touch_id()] = event.location();
|
| - last_unused_finger_event_.reset(new TouchEvent(event));
|
| - StartTapTimer();
|
| - SET_STATE(SINGLE_TAP_PRESSED);
|
| - return ui::EVENT_REWRITE_DISCARD;
|
| + const ui::EventType type = event.type();
|
| + if (type != ui::ET_TOUCH_PRESSED) {
|
| + NOTREACHED() << "Unexpected event type received: " << event.name();
|
| + return ui::EVENT_REWRITE_CONTINUE;
|
| }
|
| - NOTREACHED() << "Unexpected event type received: " << event.name();
|
| - return ui::EVENT_REWRITE_CONTINUE;
|
| +
|
| + // If the user enters the screen from the edge then send an earcon.
|
| + int edge = FindEdgesWithinBounds(event.location(), kLeavingScreenEdge);
|
| + if (edge != NO_EDGE)
|
| + delegate_->PlayEnterScreenEarcon();
|
| +
|
| + int location = FindEdgesWithinBounds(event.location(), kSlopDistanceFromEdge);
|
| + // If the press was at a corner, the user might go into corner passthrough
|
| + // instead.
|
| + bool in_a_bottom_corner =
|
| + (BOTTOM_LEFT_CORNER == location) || (BOTTOM_RIGHT_CORNER == location);
|
| + if (in_a_bottom_corner) {
|
| + passthrough_timer_.Start(
|
| + FROM_HERE,
|
| + gesture_detector_config_.longpress_timeout,
|
| + this,
|
| + &TouchExplorationController::OnPassthroughTimerFired);
|
| + }
|
| + initial_press_.reset(new TouchEvent(event));
|
| + initial_presses_[event.touch_id()] = event.location();
|
| + last_unused_finger_event_.reset(new TouchEvent(event));
|
| + StartTapTimer();
|
| + SET_STATE(SINGLE_TAP_PRESSED);
|
| + return ui::EVENT_REWRITE_DISCARD;
|
| }
|
|
|
| ui::EventRewriteStatus TouchExplorationController::InSingleTapPressed(
|
| const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) {
|
| const ui::EventType type = event.type();
|
|
|
| + int location = FindEdgesWithinBounds(event.location(), kMaxDistanceFromEdge);
|
| + bool in_a_bottom_corner =
|
| + (location == BOTTOM_LEFT_CORNER) || (location == BOTTOM_RIGHT_CORNER);
|
| + // If the event is from the initial press and the location is no longer in the
|
| + // corner, then we are not waiting for a corner passthrough anymore.
|
| + if (event.touch_id() == initial_press_->touch_id() && !in_a_bottom_corner) {
|
| + if (passthrough_timer_.IsRunning()) {
|
| + passthrough_timer_.Stop();
|
| + // Since the long press timer has been running, it is possible that the
|
| + // tap timer has timed out before the long press timer has. If the tap
|
| + // timer timeout has elapsed, then fire the tap timer.
|
| + if (event.time_stamp() - initial_press_->time_stamp() >
|
| + gesture_detector_config_.double_tap_timeout) {
|
| + OnTapTimerFired();
|
| + }
|
| + }
|
| + }
|
| +
|
| if (type == ui::ET_TOUCH_PRESSED) {
|
| initial_presses_[event.touch_id()] = event.location();
|
| SET_STATE(TWO_FINGER_TAP);
|
| return EVENT_REWRITE_DISCARD;
|
| } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
|
| + if (passthrough_timer_.IsRunning())
|
| + passthrough_timer_.Stop();
|
| if (current_touch_ids_.size() == 0 &&
|
| event.touch_id() == initial_press_->touch_id()) {
|
| SET_STATE(SINGLE_TAP_RELEASED);
|
| @@ -225,7 +282,7 @@ ui::EventRewriteStatus TouchExplorationController::InSingleTapPressed(
|
| }
|
| // Change to slide gesture if the slide occurred at the right edge.
|
| int edge = FindEdgesWithinBounds(event.location(), kMaxDistanceFromEdge);
|
| - if (edge & RIGHT_EDGE) {
|
| + if (edge & RIGHT_EDGE && edge != BOTTOM_RIGHT_CORNER) {
|
| SET_STATE(SLIDE_GESTURE);
|
| return InSlideGesture(event, rewritten_event);
|
| }
|
| @@ -394,6 +451,37 @@ ui::EventRewriteStatus TouchExplorationController::InGestureInProgress(
|
| return ui::EVENT_REWRITE_DISCARD;
|
| }
|
|
|
| +ui::EventRewriteStatus TouchExplorationController::InCornerPassthrough(
|
| + const ui::TouchEvent& event,
|
| + scoped_ptr<ui::Event>* rewritten_event) {
|
| + ui::EventType type = event.type();
|
| +
|
| + // If the first finger has left the corner, then exit passthrough.
|
| + if (event.touch_id() == initial_press_->touch_id()) {
|
| + int edges = FindEdgesWithinBounds(event.location(), kSlopDistanceFromEdge);
|
| + bool in_a_bottom_corner = (edges == BOTTOM_LEFT_CORNER) ||
|
| + (edges == BOTTOM_RIGHT_CORNER);
|
| + if (type == ui::ET_TOUCH_MOVED && in_a_bottom_corner)
|
| + return ui::EVENT_REWRITE_DISCARD;
|
| +
|
| + if (current_touch_ids_.size() == 0) {
|
| + SET_STATE(NO_FINGERS_DOWN);
|
| + return ui::EVENT_REWRITE_DISCARD;
|
| + }
|
| + SET_STATE(WAIT_FOR_NO_FINGERS);
|
| + return ui::EVENT_REWRITE_DISCARD;
|
| + }
|
| +
|
| + rewritten_event->reset(new ui::TouchEvent(
|
| + type, event.location(), event.touch_id(), event.time_stamp()));
|
| + (*rewritten_event)->set_flags(event.flags());
|
| +
|
| + if (current_touch_ids_.size() == 0)
|
| + SET_STATE(NO_FINGERS_DOWN);
|
| +
|
| + return ui::EVENT_REWRITE_REWRITTEN;
|
| +}
|
| +
|
| ui::EventRewriteStatus TouchExplorationController::InOneFingerPassthrough(
|
| const ui::TouchEvent& event,
|
| scoped_ptr<ui::Event>* rewritten_event) {
|
| @@ -465,7 +553,7 @@ ui::EventRewriteStatus TouchExplorationController::InWaitForNoFingers(
|
| }
|
|
|
| void TouchExplorationController::PlaySoundForTimer() {
|
| - delegate_->PlayVolumeAdjustSound();
|
| + delegate_->PlayVolumeAdjustEarcon();
|
| }
|
|
|
| ui::EventRewriteStatus TouchExplorationController::InSlideGesture(
|
| @@ -505,7 +593,7 @@ ui::EventRewriteStatus TouchExplorationController::InSlideGesture(
|
| kSoundDelay,
|
| this,
|
| &ui::TouchExplorationController::PlaySoundForTimer);
|
| - delegate_->PlayVolumeAdjustSound();
|
| + delegate_->PlayVolumeAdjustEarcon();
|
| }
|
|
|
| if (current_touch_ids_.size() == 0) {
|
| @@ -592,13 +680,11 @@ void TouchExplorationController::OnTapTimerFired() {
|
| return;
|
| }
|
| case SINGLE_TAP_PRESSED:
|
| - EnterTouchToMouseMode();
|
| - SET_STATE(TOUCH_EXPLORATION);
|
| - break;
|
| + if (passthrough_timer_.IsRunning())
|
| + return;
|
| case GESTURE_IN_PROGRESS:
|
| // If only one finger is down, go into touch exploration.
|
| if (current_touch_ids_.size() == 1) {
|
| - EnterTouchToMouseMode();
|
| SET_STATE(TOUCH_EXPLORATION);
|
| break;
|
| }
|
| @@ -618,6 +704,31 @@ void TouchExplorationController::OnTapTimerFired() {
|
| last_touch_exploration_.reset(new TouchEvent(*initial_press_));
|
| }
|
|
|
| +void TouchExplorationController::OnPassthroughTimerFired() {
|
| + // The passthrough timer will only fire if if the user has held a finger in
|
| + // one of the passthrough corners for the duration of the passthrough timeout.
|
| +
|
| + // Check that initial press isn't null. Also a check that if the initial
|
| + // corner press was released, then it should not be in corner passthrough.
|
| + if (!initial_press_ ||
|
| + touch_locations_.find(initial_press_->touch_id()) !=
|
| + touch_locations_.end()) {
|
| + LOG(ERROR) << "No initial press or the initial press has been released.";
|
| + }
|
| +
|
| + gfx::Point location =
|
| + ToRoundedPoint(touch_locations_[initial_press_->touch_id()]);
|
| + int corner = FindEdgesWithinBounds(location, kSlopDistanceFromEdge);
|
| + if (corner != BOTTOM_LEFT_CORNER && corner != BOTTOM_RIGHT_CORNER)
|
| + return;
|
| +
|
| + if (sound_timer_.IsRunning())
|
| + sound_timer_.Stop();
|
| + delegate_->PlayPassthroughEarcon();
|
| + SET_STATE(CORNER_PASSTHROUGH);
|
| + return;
|
| +}
|
| +
|
| void TouchExplorationController::DispatchEvent(ui::Event* event) {
|
| ui::EventDispatchDetails result ALLOW_UNUSED =
|
| root_window_->GetHost()->dispatcher()->OnEventFromSource(event);
|
| @@ -658,13 +769,13 @@ void TouchExplorationController::SideSlideControl(ui::GestureEvent* gesture) {
|
| ui::EventType type = gesture->type();
|
|
|
| if (type == ET_GESTURE_SCROLL_BEGIN) {
|
| - delegate_->PlayVolumeAdjustSound();
|
| + delegate_->PlayVolumeAdjustEarcon();
|
| }
|
|
|
| if (type == ET_GESTURE_SCROLL_END) {
|
| if (sound_timer_.IsRunning())
|
| sound_timer_.Stop();
|
| - delegate_->PlayVolumeAdjustSound();
|
| + delegate_->PlayVolumeAdjustEarcon();
|
| }
|
|
|
| // If the user is in the corner of the right side of the screen, the volume
|
| @@ -863,6 +974,7 @@ void TouchExplorationController::SetState(State new_state,
|
| case TOUCH_EXPLORATION:
|
| case TOUCH_EXPLORE_SECOND_PRESS:
|
| case ONE_FINGER_PASSTHROUGH:
|
| + case CORNER_PASSTHROUGH:
|
| case WAIT_FOR_NO_FINGERS:
|
| if (gesture_provider_.get())
|
| gesture_provider_.reset(NULL);
|
| @@ -942,6 +1054,8 @@ const char* TouchExplorationController::EnumStateToString(State state) {
|
| return "GESTURE_IN_PROGRESS";
|
| case TOUCH_EXPLORE_SECOND_PRESS:
|
| return "TOUCH_EXPLORE_SECOND_PRESS";
|
| + case CORNER_PASSTHROUGH:
|
| + return "CORNER_PASSTHROUGH";
|
| case SLIDE_GESTURE:
|
| return "SLIDE_GESTURE";
|
| case ONE_FINGER_PASSTHROUGH:
|
|
|