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..850e157441590b6d78f935de84f93cca73998693 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,17 +190,31 @@ 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; |
- VLOG_STATE(); |
- return InTouchExploration(event, rewritten_event); |
+ 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) { |
tdresser
2014/06/25 14:48:40
Invert this condition to reduce nesting.
if (delt
lisayin
2014/06/25 22:51:05
Done.
|
+ // If the user moves fast enough and far enough |
+ // from the initial touch location, start gesture detection |
dmazzoni
2014/06/25 05:06:02
Nit: end sentence with period.
lisayin
2014/06/25 22:51:04
Done.
|
+ // 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 InGestureInProgress(event, rewritten_event); |
+ } else { |
tdresser
2014/06/25 14:48:40
This "else" is unnecessary.
lisayin
2014/06/25 22:51:05
Done.
|
+ EnterTouchToMouseMode(); |
+ state_ = TOUCH_EXPLORATION; |
+ VLOG_STATE(); |
+ return InTouchExploration(event, rewritten_event); |
+ } |
} |
return EVENT_REWRITE_DISCARD; |
@@ -292,6 +318,26 @@ 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); |
+ } |
tdresser
2014/06/25 14:48:40
Indentation.
lisayin
2014/06/25 22:51:05
Done.
|
+ if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { |
+ gesture_provider_.OnTouchEvent(event); |
+ gesture_provider_.OnTouchEventAck(true); |
dmazzoni
2014/06/25 05:06:02
Are you sure you want to pass true here and false
tdresser
2014/06/25 14:48:40
I'm fairly certain this should be "false".
lisayin
2014/06/25 22:51:05
Done.
|
+ 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(); |
@@ -375,6 +421,7 @@ ui::EventRewriteStatus TouchExplorationController::InTouchExploreSecondPress( |
initial_press_->touch_id(), |
event.time_stamp())); |
(*rewritten_event)->set_flags(event.flags()); |
+ EnterTouchToMouseMode(); |
state_ = TOUCH_EXPLORATION; |
VLOG_STATE(); |
return ui::EVENT_REWRITE_REWRITTEN; |
@@ -393,7 +440,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 +467,64 @@ 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(); |
+ switch (gesture->type()) { |
tdresser
2014/06/25 14:48:40
Unless you're likely to support other gestures, it
lisayin
2014/06/25 22:51:04
Done.
|
+ case ET_GESTURE_SWIPE: |
+ OnSwipeEvent(gesture); |
+ return; |
+ default: |
+ if (current_touch_ids_.size() != 0) { |
tdresser
2014/06/25 14:48:40
From the style guide: "if one part of an if-else s
lisayin
2014/06/25 22:51:05
Done.
|
+ EnterTouchToMouseMode(); |
+ state_ = TOUCH_EXPLORATION; |
+ } else |
+ ResetToNoFingersDown(); |
+ break; |
+ } |
+} |
+ |
+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 +547,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); |
tdresser
2014/06/25 14:48:40
Just making sure - there's no way that OnGestureEv
dmazzoni
2014/06/25 15:39:44
As of this change, no - but in the future you shou
tdresser
2014/06/25 15:57:31
That would make things tricky.
If GetAndResetPend
tdresser
2014/06/25 16:06:12
Though depending on how you target the command to
|
+ } |
+ } |
state_ = NO_FINGERS_DOWN; |
initial_touch_id_passthrough_mapping_ = kTouchIdUnassigned; |
VLOG_STATE(); |
@@ -487,6 +604,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: |