| Index: ui/chromeos/touch_exploration_controller.cc
|
| diff --git a/ui/chromeos/touch_exploration_controller.cc b/ui/chromeos/touch_exploration_controller.cc
|
| index 0a63014062c19cbb9580426b5854b23c3a2008b7..1f5e50d329030a38ef9673cc4bfcd13372dfb0f0 100644
|
| --- a/ui/chromeos/touch_exploration_controller.cc
|
| +++ b/ui/chromeos/touch_exploration_controller.cc
|
| @@ -23,6 +23,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(500);
|
| +
|
| // In ChromeOS, VKEY_LWIN is synonymous for the search key.
|
| const ui::KeyboardCode kChromeOSSearchKey = ui::VKEY_LWIN;
|
| } // namespace
|
| @@ -36,7 +40,8 @@ TouchExplorationController::TouchExplorationController(
|
| event_handler_for_testing_(NULL),
|
| gesture_provider_(this),
|
| prev_state_(NO_FINGERS_DOWN),
|
| - VLOG_on_(true) {
|
| + VLOG_on_(true),
|
| + waiting_for_corner_passthrough_(false) {
|
| CHECK(root_window);
|
| root_window->GetHost()->GetEventSource()->AddEventRewriter(this);
|
| }
|
| @@ -73,6 +78,13 @@ ui::EventRewriteStatus TouchExplorationController::RewriteEvent(
|
| // this event under this new state.
|
| }
|
|
|
| + if (long_press_timer_.IsRunning() &&
|
| + event.time_stamp() - initial_press_->time_stamp() >
|
| + gesture_detector_config_.longpress_timeout) {
|
| + long_press_timer_.Stop();
|
| + OnLongPressTimerFired();
|
| + }
|
| +
|
| const ui::EventType type = touch_event.type();
|
| const gfx::PointF& location = touch_event.location_f();
|
| const int touch_id = touch_event.touch_id();
|
| @@ -132,6 +144,8 @@ ui::EventRewriteStatus TouchExplorationController::RewriteEvent(
|
| return InTouchExploreSecondPress(touch_event, rewritten_event);
|
| case TWO_TO_ONE_FINGER:
|
| return InTwoToOneFinger(touch_event, rewritten_event);
|
| + case CORNER_PASSTHROUGH:
|
| + return InCornerPassthrough(touch_event, rewritten_event);
|
| case PASSTHROUGH:
|
| return InPassthrough(touch_event, rewritten_event);
|
| case WAIT_FOR_RELEASE:
|
| @@ -152,29 +166,63 @@ ui::EventRewriteStatus TouchExplorationController::NextDispatchEvent(
|
| ui::EventRewriteStatus TouchExplorationController::InNoFingersDown(
|
| const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) {
|
| const ui::EventType type = event.type();
|
| - if (type == ui::ET_TOUCH_PRESSED) {
|
| - initial_press_.reset(new TouchEvent(event));
|
| - last_unused_finger_event_.reset(new TouchEvent(event));
|
| - tap_timer_.Start(FROM_HERE,
|
| - gesture_detector_config_.double_tap_timeout,
|
| - this,
|
| - &TouchExplorationController::OnTapTimerFired);
|
| - gesture_provider_.OnTouchEvent(event);
|
| - gesture_provider_.OnTouchEventAck(false);
|
| - ProcessGestureEvents();
|
| - state_ = SINGLE_TAP_PRESSED;
|
| - VLOG_STATE();
|
| - return ui::EVENT_REWRITE_DISCARD;
|
| + 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;
|
| + int location = FindEdgesWithinBounds(event.location(), kSlopDistanceFromEdge);
|
| + base::TimeDelta timeout;
|
| +
|
| + // 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) {
|
| + VLOG(0) << "Location: " << location;
|
| + long_press_timer_.Start(FROM_HERE,
|
| + gesture_detector_config_.longpress_timeout,
|
| + this,
|
| + &TouchExplorationController::OnLongPressTimerFired);
|
| + waiting_for_corner_passthrough_ = true;
|
| + } else {
|
| + waiting_for_corner_passthrough_ = false;
|
| + }
|
| + tap_timer_.Start(FROM_HERE,
|
| + gesture_detector_config_.double_tap_timeout,
|
| + this,
|
| + &TouchExplorationController::OnTapTimerFired);
|
| + initial_press_.reset(new TouchEvent(event));
|
| + last_unused_finger_event_.reset(new TouchEvent(event));
|
| + gesture_provider_.OnTouchEvent(event);
|
| + gesture_provider_.OnTouchEventAck(false);
|
| + ProcessGestureEvents();
|
| + state_ = SINGLE_TAP_PRESSED;
|
| + VLOG_STATE();
|
| + 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) {
|
| + waiting_for_corner_passthrough_ = false;
|
| + if (long_press_timer_.IsRunning()) {
|
| + long_press_timer_.Stop();
|
| + if (event.time_stamp() - initial_press_->time_stamp() >
|
| + gesture_detector_config_.double_tap_timeout) {
|
| + OnTapTimerFired();
|
| + }
|
| + }
|
| + }
|
| +
|
| if (type == ui::ET_TOUCH_PRESSED) {
|
| + waiting_for_corner_passthrough_ = false;
|
| // Adding a second finger within the timeout period switches to
|
| // passing through every event from the second finger and none form the
|
| // first. The event from the first finger is still saved in initial_press_.
|
| @@ -402,7 +450,7 @@ ui::EventRewriteStatus TouchExplorationController::InTwoToOneFinger(
|
| // If a third finger is pressed, we are now going into passthrough mode
|
| // and now need to dispatch the first finger into a press, as well as the
|
| // recent press.
|
| - if (current_touch_ids_.size() == 3){
|
| + if (current_touch_ids_.size() == 3) {
|
| state_ = PASSTHROUGH;
|
| scoped_ptr<ui::TouchEvent> first_finger_press;
|
| first_finger_press.reset(
|
| @@ -441,6 +489,41 @@ ui::EventRewriteStatus TouchExplorationController::InTwoToOneFinger(
|
| return ui::EVENT_REWRITE_CONTINUE;
|
| }
|
|
|
| +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) {
|
| + ResetToNoFingersDown();
|
| + return ui::EVENT_REWRITE_DISCARD;
|
| + }
|
| +
|
| + waiting_for_corner_passthrough_ = false;
|
| + VLOG(0) << "Waiting for corner passthrough is false";
|
| + state_ = WAIT_FOR_RELEASE;
|
| + VLOG_STATE();
|
| + 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)
|
| + ResetToNoFingersDown();
|
| +
|
| + return ui::EVENT_REWRITE_REWRITTEN;
|
| +}
|
| +
|
| ui::EventRewriteStatus TouchExplorationController::InPassthrough(
|
| const ui::TouchEvent& event,
|
| scoped_ptr<ui::Event>* rewritten_event) {
|
| @@ -508,6 +591,7 @@ ui::EventRewriteStatus TouchExplorationController::InTouchExploreSecondPress(
|
| ui::EventRewriteStatus TouchExplorationController::InWaitForRelease(
|
| const ui::TouchEvent& event,
|
| scoped_ptr<ui::Event>* rewritten_event) {
|
| + waiting_for_corner_passthrough_ = false;
|
| ui::EventType type = event.type();
|
| if (!(type == ui::ET_TOUCH_PRESSED || type == ui::ET_TOUCH_MOVED ||
|
| type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED)) {
|
| @@ -595,6 +679,8 @@ void TouchExplorationController::OnTapTimerFired() {
|
| last_touch_exploration_.reset(new TouchEvent(*initial_press_));
|
| return;
|
| case SINGLE_TAP_PRESSED:
|
| + if (waiting_for_corner_passthrough_)
|
| + return;
|
| case GESTURE_IN_PROGRESS:
|
| // Discard any pending gestures.
|
| delete gesture_provider_.GetAndResetPendingGestures();
|
| @@ -611,6 +697,16 @@ void TouchExplorationController::OnTapTimerFired() {
|
| last_touch_exploration_.reset(new TouchEvent(*initial_press_));
|
| }
|
|
|
| +void TouchExplorationController::OnLongPressTimerFired() {
|
| + if (waiting_for_corner_passthrough_) {
|
| + delegate_->PlayEarCon();
|
| + delete gesture_provider_.GetAndResetPendingGestures();
|
| + state_ = CORNER_PASSTHROUGH;
|
| + VLOG_STATE();
|
| + return;
|
| + }
|
| +}
|
| +
|
| void TouchExplorationController::DispatchEvent(ui::Event* event) {
|
| if (event_handler_for_testing_) {
|
| event_handler_for_testing_->OnEvent(event);
|
| @@ -805,6 +901,7 @@ void TouchExplorationController::EnterTouchToMouseMode() {
|
| }
|
|
|
| void TouchExplorationController::ResetToNoFingersDown() {
|
| + waiting_for_corner_passthrough_ = false;
|
| ProcessGestureEvents();
|
| if (sound_timer_.IsRunning())
|
| sound_timer_.Stop();
|
| @@ -875,6 +972,8 @@ const char* TouchExplorationController::EnumStateToString(State state) {
|
| return "TOUCH_EXPLORE_SECOND_PRESS";
|
| case TWO_TO_ONE_FINGER:
|
| return "TWO_TO_ONE_FINGER";
|
| + case CORNER_PASSTHROUGH:
|
| + return "CORNER_PASSTHROUGH";
|
| case PASSTHROUGH:
|
| return "PASSTHROUGH";
|
| case WAIT_FOR_RELEASE:
|
|
|