Chromium Code Reviews| Index: ui/chromeos/touch_exploration_controller.cc |
| diff --git a/ui/chromeos/touch_exploration_controller.cc b/ui/chromeos/touch_exploration_controller.cc |
| index 6b2584afc7f2afc4c3d6bec3c3491e1fb11ae054..40f9d385b4af4a035cc83124b52e2e038f081ee6 100644 |
| --- a/ui/chromeos/touch_exploration_controller.cc |
| +++ b/ui/chromeos/touch_exploration_controller.cc |
| @@ -6,6 +6,7 @@ |
| #include "base/logging.h" |
| #include "base/strings/string_number_conversions.h" |
| +#include "base/time/default_tick_clock.h" |
| #include "ui/aura/client/cursor_client.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_event_dispatcher.h" |
| @@ -39,6 +40,7 @@ TouchExplorationController::TouchExplorationController( |
| gesture_provider_(this), |
| prev_state_(NO_FINGERS_DOWN), |
| VLOG_on_(true), |
| + send_gesture_events_(false), |
| tick_clock_(NULL) { |
| CHECK(root_window); |
| root_window->GetHost()->GetEventSource()->AddEventRewriter(this); |
| @@ -52,6 +54,13 @@ ui::EventRewriteStatus TouchExplorationController::RewriteEvent( |
| const ui::Event& event, |
| scoped_ptr<ui::Event>* rewritten_event) { |
| if (!event.IsTouchEvent()) { |
| + if (event.IsKeyEvent()) { |
| + const ui::KeyEvent& key_event = static_cast<const ui::KeyEvent&>(event); |
| + VLOG(0) << "\nKeyboard event: " << key_event.name() |
| + << "\n Key code: " << key_event.key_code() |
| + << ", Flags: " << key_event.flags() |
| + << ", Is char: " << key_event.is_char(); |
| + } |
| return ui::EVENT_REWRITE_CONTINUE; |
| } |
| const ui::TouchEvent& touch_event = static_cast<const ui::TouchEvent&>(event); |
| @@ -69,6 +78,14 @@ ui::EventRewriteStatus TouchExplorationController::RewriteEvent( |
| // this event under this new state. |
| } |
| + // If a gesture has ended, we need to keep proccessing touch events so that |
| + // the gesture provider can keep track of how many fingers are down. |
| + if (send_gesture_events_) { |
| + gesture_provider_.OnTouchEvent(touch_event); |
| + gesture_provider_.OnTouchEventAck(false); |
| + delete gesture_provider_.GetAndResetPendingGestures(); |
| + } |
| + |
| const ui::EventType type = touch_event.type(); |
| const gfx::PointF& location = touch_event.location_f(); |
| const int touch_id = touch_event.touch_id(); |
| @@ -79,8 +96,8 @@ ui::EventRewriteStatus TouchExplorationController::RewriteEvent( |
| current_touch_ids_.push_back(touch_id); |
| touch_locations_.insert(std::pair<int, gfx::PointF>(touch_id, location)); |
| } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { |
| - // In order to avoid accidentally double tapping when moving off the edge of |
| - // the screen, the state will be rewritten to NoFingersDown. |
| + // In order to avoid accidentally double tapping when moving off the edge |
| + // of the screen, the state will be rewritten to NoFingersDown. |
| TouchEvent touch_event = static_cast<const TouchEvent&>(event); |
| if (FindEdgesWithinBounds(touch_event.location(), kLeavingScreenEdge) != |
| NO_EDGE) { |
| @@ -111,7 +128,7 @@ ui::EventRewriteStatus TouchExplorationController::RewriteEvent( |
| VLOG_STATE(); |
| VLOG_EVENT(touch_event); |
| // The rest of the processing depends on what state we're in. |
| - switch(state_) { |
| + switch (state_) { |
| case NO_FINGERS_DOWN: |
| return InNoFingersDown(touch_event, rewritten_event); |
| case SINGLE_TAP_PRESSED: |
| @@ -129,12 +146,12 @@ ui::EventRewriteStatus TouchExplorationController::RewriteEvent( |
| return InGestureInProgress(touch_event, rewritten_event); |
| case TOUCH_EXPLORE_SECOND_PRESS: |
| return InTouchExploreSecondPress(touch_event, rewritten_event); |
| - case SLIDE_GESTURE: |
| - return InSlideGesture(touch_event, rewritten_event); |
| case ONE_FINGER_PASSTHROUGH: |
| return InOneFingerPassthrough(touch_event, rewritten_event); |
| case WAIT_FOR_ONE_FINGER: |
| return InWaitForOneFinger(touch_event, rewritten_event); |
| + case SLIDE_GESTURE: |
| + return InSlideGesture(touch_event, rewritten_event); |
| } |
| NOTREACHED(); |
| return ui::EVENT_REWRITE_CONTINUE; |
| @@ -169,10 +186,10 @@ ui::EventRewriteStatus TouchExplorationController::InSingleTapPressed( |
| const ui::EventType type = event.type(); |
| if (type == ui::ET_TOUCH_PRESSED) { |
| - // TODO (evy, lisayin) : add support for multifinger swipes. |
| - // For now, we wait for there to be only one finger down again. |
| - state_ = WAIT_FOR_ONE_FINGER; |
| - return EVENT_REWRITE_DISCARD; |
| + // This is the start of a multifinger gesture. |
| + state_ = GESTURE_IN_PROGRESS; |
| + VLOG_STATE(); |
| + return InGestureInProgress(event, rewritten_event); |
| } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { |
| if (current_touch_ids_.size() == 0 && |
| event.touch_id() == initial_press_->touch_id()) { |
| @@ -232,6 +249,7 @@ TouchExplorationController::InSingleTapOrTouchExploreReleased( |
| // finger is or no fingers are down. |
| if (current_touch_ids_.size() > 1) { |
| state_ = WAIT_FOR_ONE_FINGER; |
| + VLOG_STATE(); |
| return ui::EVENT_REWRITE_DISCARD; |
| } |
| if (type == ui::ET_TOUCH_PRESSED) { |
| @@ -365,30 +383,18 @@ ui::EventRewriteStatus TouchExplorationController::InGestureInProgress( |
| const ui::TouchEvent& event, |
| scoped_ptr<ui::Event>* rewritten_event) { |
| ui::EventType type = event.type(); |
| - // If additional fingers are added before a swipe gesture has been |
| - // registered, then the state will no longer be GESTURE_IN_PROGRESS. |
| - if (type == ui::ET_TOUCH_PRESSED || |
| - event.touch_id() != initial_press_->touch_id()) { |
| - if (tap_timer_.IsRunning()) |
| - tap_timer_.Stop(); |
| - // Discard any pending gestures. |
| - delete gesture_provider_.GetAndResetPendingGestures(); |
| - state_ = WAIT_FOR_ONE_FINGER; |
| - return EVENT_REWRITE_DISCARD; |
| - } |
| - |
| - // There should not be more than one finger down. |
| - DCHECK(current_touch_ids_.size() <= 1); |
| - 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 || |
|
aboxhall
2014/07/30 00:25:15
nit: this can be simplified to
if (type != ui::ET_
evy
2014/08/04 23:06:30
Done.
|
| + type == ui::ET_TOUCH_MOVED || type == ui::ET_TOUCH_PRESSED)) { |
| + NOTREACHED() << "Unexpected event type received: " << event.name(); |
| + return ui::EVENT_REWRITE_CONTINUE; |
| } |
| - 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(); |
| - } |
| + // Send events to the gesture provider. If no gesture is registered before |
| + // the tap timer times out, the state will change to wait for one finger |
| + // and this function will stop being called. |
| + gesture_provider_.OnTouchEvent(event); |
| + gesture_provider_.OnTouchEventAck(false); |
| + if (current_touch_ids_.size() == 0) { |
| + ResetToNoFingersDown(); |
| } |
| ProcessGestureEvents(); |
| return ui::EVENT_REWRITE_DISCARD; |
| @@ -475,6 +481,7 @@ ui::EventRewriteStatus TouchExplorationController::InWaitForOneFinger( |
| NOTREACHED() << "Unexpected event type received: " << event.name(); |
| return ui::EVENT_REWRITE_CONTINUE; |
| } |
| + |
| if (current_touch_ids_.size() == 1) { |
| EnterTouchToMouseMode(); |
| state_ = TOUCH_EXPLORATION; |
| @@ -507,6 +514,7 @@ ui::EventRewriteStatus TouchExplorationController::InSlideGesture( |
| // Discard any pending gestures. |
| delete gesture_provider_.GetAndResetPendingGestures(); |
| state_ = WAIT_FOR_ONE_FINGER; |
| + VLOG_STATE(); |
| return EVENT_REWRITE_DISCARD; |
| } |
| @@ -593,8 +601,9 @@ void TouchExplorationController::OnTapTimerFired() { |
| case GESTURE_IN_PROGRESS: |
| // Discard any pending gestures. |
| delete gesture_provider_.GetAndResetPendingGestures(); |
| - EnterTouchToMouseMode(); |
| - state_ = TOUCH_EXPLORATION; |
| + // Wait for one finger before returning to touch exploration. |
| + send_gesture_events_ = true; |
| + state_ = WAIT_FOR_ONE_FINGER; |
| VLOG_STATE(); |
| break; |
| default: |
| @@ -622,10 +631,12 @@ void TouchExplorationController::OnGestureEvent( |
| if (VLOG_on_) |
| VLOG(0) << " \n Gesture Triggered: " << gesture->name(); |
| if (type == ui::ET_GESTURE_SWIPE && state_ != SLIDE_GESTURE) { |
| - if (VLOG_on_) |
| - VLOG(0) << "Swipe!"; |
| delete gesture_provider_.GetAndResetPendingGestures(); |
| OnSwipeEvent(gesture); |
| + send_gesture_events_ = true; |
| + state_ = WAIT_FOR_ONE_FINGER; |
| + VLOG_STATE(); |
| + tap_timer_.Stop(); |
| return; |
| } |
| } |
| @@ -693,24 +704,72 @@ void TouchExplorationController::SideSlideControl(ui::GestureEvent* gesture) { |
| delegate_->SetOutputLevel(int(volume)); |
| } |
| - |
| 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; |
| + int num_fingers = event_details.touch_points(); |
| + if(VLOG_on_) |
| + VLOG(0) << "\nSwipe with " << num_fingers << " fingers."; |
| + switch (num_fingers) { |
| + case 1: |
| + if (event_details.swipe_left()) { |
| + DispatchShiftSearchKeyEvent(ui::VKEY_LEFT); |
|
aboxhall
2014/07/30 00:25:15
Speculation: it might be nice to keep track of the
evy
2014/08/04 23:06:30
This is pretty cool! I'm not that familiar with ma
|
| + 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; |
| + } |
| + case 2: |
| + if (event_details.swipe_left()) { |
| + DispatchKeyWithNoFlags(VKEY_BROWSER_BACK); |
| + return; |
| + } else if (event_details.swipe_right()) { |
| + DispatchKeyWithNoFlags(VKEY_BROWSER_FORWARD); |
| + return; |
| + } else if (event_details.swipe_up()) { |
| + DispatchShiftSearchKeyEvent(ui::VKEY_A); |
| + return; |
| + } else if (event_details.swipe_down()) { |
| + DispatchShiftSearchKeyEvent(ui::VKEY_R); |
| + return; |
| + } |
| + case 3: |
| + if (event_details.swipe_up()) { |
| + DispatchKeyWithNoFlags(ui::VKEY_PRIOR); |
| + return; |
| + } else if (event_details.swipe_down()) { |
| + DispatchKeyWithNoFlags(ui::VKEY_NEXT); |
| + return; |
| + } |
| + // Left/right gestures mapping? |
| + return; |
| + case 4: |
| + if (event_details.swipe_left()) { |
| + // TODO: scroll through tabs |
| + return; |
| + } else if (event_details.swipe_right()) { |
| + // TODO: scroll through tabs |
| + return; |
| + } else if (event_details.swipe_up()) { |
| + DispatchKeyWithNoFlags(VKEY_BROWSER_HOME); |
| + return; |
| + } else if (event_details.swipe_down()) { |
| + DispatchKeyWithNoFlags(VKEY_BROWSER_REFRESH); |
| + return; |
| + } |
| } |
| + // If the user is swiping with more than the supported number of fingers, |
| + // none of these cases will be hit. |
| + // TODO: add some checks so the gesture doesn't get proccessed if there are |
| + // more fingers than supported. |
| + return; |
| } |
| int TouchExplorationController::FindEdgesWithinBounds(gfx::Point point, |
| @@ -742,19 +801,19 @@ int TouchExplorationController::FindEdgesWithinBounds(gfx::Point point, |
| } |
| void TouchExplorationController::DispatchShiftSearchKeyEvent( |
| - const ui::KeyboardCode direction) { |
| - // In order to activate the shortcut shift+search+<arrow key> |
| + const ui::KeyboardCode third_key) { |
| + // In order to activate the shortcut shift+search+<key> |
| // three KeyPressed events must be dispatched in succession along |
| // with three KeyReleased events. |
| ui::KeyEvent shift_down = ui::KeyEvent( |
| ui::ET_KEY_PRESSED, ui::VKEY_SHIFT, ui::EF_SHIFT_DOWN); |
| ui::KeyEvent search_down = ui::KeyEvent( |
| ui::ET_KEY_PRESSED, kChromeOSSearchKey, ui::EF_SHIFT_DOWN); |
| - ui::KeyEvent direction_down = |
| - ui::KeyEvent(ui::ET_KEY_PRESSED, direction, ui::EF_SHIFT_DOWN); |
| + ui::KeyEvent third_key_down = |
| + ui::KeyEvent(ui::ET_KEY_PRESSED, third_key, ui::EF_SHIFT_DOWN); |
| - ui::KeyEvent direction_up = |
| - ui::KeyEvent(ui::ET_KEY_RELEASED, direction, ui::EF_SHIFT_DOWN); |
| + ui::KeyEvent third_key_up = |
| + ui::KeyEvent(ui::ET_KEY_RELEASED, third_key, ui::EF_SHIFT_DOWN); |
| ui::KeyEvent search_up = ui::KeyEvent( |
| ui::ET_KEY_RELEASED, kChromeOSSearchKey, ui::EF_SHIFT_DOWN); |
| ui::KeyEvent shift_up = |
| @@ -762,12 +821,26 @@ void TouchExplorationController::DispatchShiftSearchKeyEvent( |
| DispatchEvent(&shift_down); |
| DispatchEvent(&search_down); |
| - DispatchEvent(&direction_down); |
| - DispatchEvent(&direction_up); |
| + DispatchEvent(&third_key_down); |
| + DispatchEvent(&third_key_up); |
| DispatchEvent(&search_up); |
| DispatchEvent(&shift_up); |
| } |
| +void TouchExplorationController::DispatchKeyWithNoFlags( |
| + const ui::KeyboardCode key) { |
| + ui::KeyEvent key_down = ui::KeyEvent(ui::ET_KEY_PRESSED, key, ui::EF_NONE); |
| + ui::KeyEvent key_up = ui::KeyEvent(ui::ET_KEY_RELEASED, key, ui::EF_NONE); |
| + DispatchEvent(&key_down); |
| + DispatchEvent(&key_up); |
| + if(VLOG_on_) { |
| + VLOG(0) << "\nKey down: key code : " << key_down.key_code() |
| + << ", flags: " << key_down.flags() |
| + << "\nKey up: key code : " << key_up.key_code() |
| + << ", flags: " << key_up.flags(); |
| + } |
| +} |
| + |
| scoped_ptr<ui::Event> TouchExplorationController::CreateMouseMoveEvent( |
| const gfx::PointF& location, |
| int flags) { |
| @@ -811,6 +884,7 @@ void TouchExplorationController::ResetToNoFingersDown() { |
| VLOG_STATE(); |
| if (tap_timer_.IsRunning()) |
| tap_timer_.Stop(); |
| + send_gesture_events_ = false; |
| } |
| void TouchExplorationController::VlogState(const char* function_name) { |
| @@ -874,12 +948,12 @@ const char* TouchExplorationController::EnumStateToString(State state) { |
| return "GESTURE_IN_PROGRESS"; |
| case TOUCH_EXPLORE_SECOND_PRESS: |
| return "TOUCH_EXPLORE_SECOND_PRESS"; |
| - case SLIDE_GESTURE: |
| - return "SLIDE_GESTURE"; |
| case ONE_FINGER_PASSTHROUGH: |
| return "ONE_FINGER_PASSTHROUGH"; |
| case WAIT_FOR_ONE_FINGER: |
| return "WAIT_FOR_ONE_FINGER"; |
| + case SLIDE_GESTURE: |
| + return "SLIDE_GESTURE"; |
| } |
| return "Not a state"; |
| } |