| Index: ui/chromeos/touch_exploration_controller.cc
|
| diff --git a/ui/chromeos/touch_exploration_controller.cc b/ui/chromeos/touch_exploration_controller.cc
|
| index 9763cae225c242b277a510f9ac92789e9ef8c75d..55fb432be1be6b5f015e266a29ef220c0ea0c8ac 100644
|
| --- a/ui/chromeos/touch_exploration_controller.cc
|
| +++ b/ui/chromeos/touch_exploration_controller.cc
|
| @@ -31,6 +31,9 @@ const int kTouchIdUnassigned = 0;
|
| // initial_touch_id_passthrough_mapping_ a touch id anymore,
|
| // until all fingers are released.
|
| const int kTouchIdNone = -1;
|
| +
|
| +// In ChromeOS, VKEY_LWIN is synonymous for the search key.
|
| +const ui::KeyboardCode kChromeOSSearchKey = ui::VKEY_LWIN;
|
| } // namespace
|
|
|
| TouchExplorationController::TouchExplorationController(
|
| @@ -39,6 +42,7 @@ TouchExplorationController::TouchExplorationController(
|
| initial_touch_id_passthrough_mapping_(kTouchIdUnassigned),
|
| state_(NO_FINGERS_DOWN),
|
| event_handler_for_testing_(NULL),
|
| + gesture_provider_(this),
|
| prev_state_(NO_FINGERS_DOWN) {
|
| CHECK(root_window);
|
| root_window->GetHost()->GetEventSource()->AddEventRewriter(this);
|
| @@ -63,6 +67,10 @@ bool TouchExplorationController::IsInNoFingersDownStateForTesting() const {
|
| return state_ == NO_FINGERS_DOWN;
|
| }
|
|
|
| +bool TouchExplorationController::IsInGestureInProgressStateForTesting() const {
|
| + return state_ == GESTURE_IN_PROGRESS;
|
| +}
|
| +
|
| ui::EventRewriteStatus TouchExplorationController::RewriteEvent(
|
| const ui::Event& event,
|
| scoped_ptr<ui::Event>* rewritten_event) {
|
| @@ -128,6 +136,8 @@ ui::EventRewriteStatus TouchExplorationController::RewriteEvent(
|
| return InDoubleTapPressed(touch_event, rewritten_event);
|
| case TOUCH_EXPLORATION:
|
| return InTouchExploration(touch_event, rewritten_event);
|
| + case GESTURE_IN_PROGRESS:
|
| + return InGestureInProgress(touch_event, rewritten_event);
|
| case PASSTHROUGH_MINUS_ONE:
|
| return InPassthroughMinusOne(touch_event, rewritten_event);
|
| case TOUCH_EXPLORE_SECOND_PRESS:
|
| @@ -153,6 +163,8 @@ ui::EventRewriteStatus TouchExplorationController::InNoFingersDown(
|
| gesture_detector_config_.double_tap_timeout,
|
| this,
|
| &TouchExplorationController::OnTapTimerFired);
|
| + gesture_provider_.OnTouchEvent(event);
|
| + gesture_provider_.OnTouchEventAck(false);
|
| state_ = SINGLE_TAP_PRESSED;
|
| VLOG_STATE();
|
| return ui::EVENT_REWRITE_DISCARD;
|
| @@ -178,20 +190,32 @@ ui::EventRewriteStatus TouchExplorationController::InSingleTapPressed(
|
| VLOG_STATE();
|
| return EVENT_REWRITE_DISCARD;
|
| } else if (type == ui::ET_TOUCH_MOVED) {
|
| - // If the user moves far enough from the initial touch location (outside
|
| - // the "slop" region, jump to the touch exploration mode early.
|
| - // TODO(evy, lisayin): Add gesture recognition here instead -
|
| - // we should probably jump to gesture mode here if the velocity is
|
| - // high enough, and touch exploration if the velocity is lower.
|
| - float delta = (event.location() - initial_press_->location()).Length();
|
| - if (delta > gesture_detector_config_.touch_slop) {
|
| - EnterTouchToMouseMode();
|
| - state_ = TOUCH_EXPLORATION;
|
| + float delta_time =
|
| + (event.time_stamp() - initial_press_->time_stamp()).InSecondsF();
|
| + float delta_distance =
|
| + (event.location() - initial_press_->location()).Length();
|
| + float velocity = delta_distance / delta_time;
|
| + VLOG(0) << "\n Delta time: " << delta_time
|
| + << "\n Delta distance: " << delta_distance
|
| + << "\n Velocity of click: " << velocity
|
| + << "\n Minimum swipe velocity: "
|
| + << gesture_detector_config_.minimum_swipe_velocity;
|
| + if (delta_distance <= gesture_detector_config_.touch_slop)
|
| + return EVENT_REWRITE_DISCARD;
|
| +
|
| + // If the user moves fast enough and far enough
|
| + // from the initial touch location, start gesture detection.
|
| + // Otherwise, if the user moves far enough from the initial touch location
|
| + // outside the "slop" region, jump to the touch exploration mode early.
|
| + if (velocity > gesture_detector_config_.minimum_swipe_velocity) {
|
| + state_ = GESTURE_IN_PROGRESS;
|
| VLOG_STATE();
|
| - return InTouchExploration(event, rewritten_event);
|
| + return InGestureInProgress(event, rewritten_event);
|
| }
|
| -
|
| - return EVENT_REWRITE_DISCARD;
|
| + EnterTouchToMouseMode();
|
| + state_ = TOUCH_EXPLORATION;
|
| + VLOG_STATE();
|
| + return InTouchExploration(event, rewritten_event);
|
| }
|
| NOTREACHED() << "Unexpected event type received.";
|
| return ui::EVENT_REWRITE_CONTINUE;
|
| @@ -292,6 +316,27 @@ ui::EventRewriteStatus TouchExplorationController::InTouchExploration(
|
| return ui::EVENT_REWRITE_REWRITTEN;
|
| }
|
|
|
| +ui::EventRewriteStatus TouchExplorationController::InGestureInProgress(
|
| + const ui::TouchEvent& event,
|
| + scoped_ptr<ui::Event>* rewritten_event) {
|
| + ui::EventType type = event.type();
|
| + if (type == ui::ET_TOUCH_PRESSED ||
|
| + event.touch_id() != initial_press_->touch_id()) {
|
| + return ui::EVENT_REWRITE_DISCARD;
|
| + }
|
| + if (type == ui::ET_TOUCH_MOVED) {
|
| + gesture_provider_.OnTouchEvent(event);
|
| + gesture_provider_.OnTouchEventAck(false);
|
| + }
|
| + if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
|
| + gesture_provider_.OnTouchEvent(event);
|
| + gesture_provider_.OnTouchEventAck(false);
|
| + if (current_touch_ids_.size() == 0)
|
| + ResetToNoFingersDown();
|
| + }
|
| + return ui::EVENT_REWRITE_DISCARD;
|
| +}
|
| +
|
| ui::EventRewriteStatus TouchExplorationController::InPassthroughMinusOne(
|
| const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) {
|
| ui::EventType type = event.type();
|
| @@ -393,7 +438,10 @@ void TouchExplorationController::OnTapTimerFired() {
|
| last_touch_exploration_.reset(new TouchEvent(*initial_press_));
|
| return;
|
| case SINGLE_TAP_PRESSED:
|
| + case GESTURE_IN_PROGRESS:
|
| EnterTouchToMouseMode();
|
| + // Discard any pending gestures.
|
| + delete gesture_provider_.GetAndResetPendingGestures();
|
| state_ = TOUCH_EXPLORATION;
|
| VLOG_STATE();
|
| break;
|
| @@ -417,6 +465,63 @@ void TouchExplorationController::DispatchEvent(ui::Event* event) {
|
| root_window_->GetHost()->dispatcher()->OnEventFromSource(event);
|
| }
|
|
|
| +void TouchExplorationController::OnGestureEvent(ui::GestureEvent* gesture) {
|
| + CHECK(gesture->IsGestureEvent());
|
| + VLOG(0) << " \n Gesture Triggered: " << gesture->name();
|
| + if (tap_timer_.IsRunning())
|
| + tap_timer_.Stop();
|
| + if (gesture->type() == ui::ET_GESTURE_SWIPE) {
|
| + OnSwipeEvent(gesture);
|
| + return;
|
| + }
|
| +
|
| + if (current_touch_ids_.size() != 0) {
|
| + EnterTouchToMouseMode();
|
| + state_ = TOUCH_EXPLORATION;
|
| + } else {
|
| + ResetToNoFingersDown();
|
| + }
|
| +}
|
| +
|
| +void TouchExplorationController::OnSwipeEvent(ui::GestureEvent* swipe_gesture) {
|
| + // A swipe gesture contains details for the direction in which the swipe
|
| + // occurred.
|
| + GestureEventDetails event_details = swipe_gesture->details();
|
| + if (event_details.swipe_left()) {
|
| + DispatchShiftSearchKeyEvent(ui::VKEY_LEFT);
|
| + return;
|
| + } else if (event_details.swipe_right()) {
|
| + DispatchShiftSearchKeyEvent(ui::VKEY_RIGHT);
|
| + return;
|
| + } else if (event_details.swipe_up()) {
|
| + DispatchShiftSearchKeyEvent(ui::VKEY_UP);
|
| + return;
|
| + } else if (event_details.swipe_down()) {
|
| + DispatchShiftSearchKeyEvent(ui::VKEY_DOWN);
|
| + return;
|
| + }
|
| +}
|
| +
|
| +void TouchExplorationController::DispatchShiftSearchKeyEvent(
|
| + const ui::KeyboardCode direction) {
|
| + // In order to activate the shortcut shift+search+<arrow key>
|
| + // three KeyPressed events must be dispatched in succession along
|
| + // with three KeyReleased events.
|
| + DispatchEvent(new ui::KeyEvent(
|
| + ui::ET_KEY_PRESSED, ui::VKEY_SHIFT, ui::EF_SHIFT_DOWN, false));
|
| + DispatchEvent(new ui::KeyEvent(
|
| + ui::ET_KEY_PRESSED, kChromeOSSearchKey, ui::EF_SHIFT_DOWN, false));
|
| + DispatchEvent(new ui::KeyEvent(
|
| + ui::ET_KEY_PRESSED, direction, ui::EF_SHIFT_DOWN, false));
|
| +
|
| + DispatchEvent(new ui::KeyEvent(
|
| + ui::ET_KEY_RELEASED, direction, ui::EF_SHIFT_DOWN, false));
|
| + DispatchEvent(new ui::KeyEvent(
|
| + ui::ET_KEY_RELEASED, kChromeOSSearchKey, ui::EF_SHIFT_DOWN, false));
|
| + DispatchEvent(new ui::KeyEvent(
|
| + ui::ET_KEY_RELEASED, ui::VKEY_SHIFT, ui::EF_NONE, false));
|
| +}
|
| +
|
| scoped_ptr<ui::Event> TouchExplorationController::CreateMouseMoveEvent(
|
| const gfx::PointF& location,
|
| int flags) {
|
| @@ -439,6 +544,15 @@ void TouchExplorationController::EnterTouchToMouseMode() {
|
| }
|
|
|
| void TouchExplorationController::ResetToNoFingersDown() {
|
| + scoped_ptr<ScopedVector<ui::GestureEvent> > gestures;
|
| + gestures.reset(gesture_provider_.GetAndResetPendingGestures());
|
| + if (gestures != NULL) {
|
| + for (ScopedVector<GestureEvent>::iterator i = gestures->begin();
|
| + i != gestures->end();
|
| + ++i) {
|
| + OnGestureEvent(*i);
|
| + }
|
| + }
|
| state_ = NO_FINGERS_DOWN;
|
| initial_touch_id_passthrough_mapping_ = kTouchIdUnassigned;
|
| VLOG_STATE();
|
| @@ -487,6 +601,8 @@ const char* TouchExplorationController::EnumStateToString(State state) {
|
| return "DOUBLE_TAP_PRESSED";
|
| case TOUCH_EXPLORATION:
|
| return "TOUCH_EXPLORATION";
|
| + case GESTURE_IN_PROGRESS:
|
| + return "GESTURE_IN_PROGRESS";
|
| case PASSTHROUGH_MINUS_ONE:
|
| return "PASSTHROUGH_MINUS_ONE";
|
| case TOUCH_EXPLORE_SECOND_PRESS:
|
|
|