Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(118)

Side by Side Diff: ui/chromeos/touch_exploration_controller.cc

Issue 330763007: Swipe Gestures for Accessibility (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@gesture-vlogs
Patch Set: Time Out added for Gestures Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/chromeos/touch_exploration_controller.h" 5 #include "ui/chromeos/touch_exploration_controller.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/strings/string_number_conversions.h" 8 #include "base/strings/string_number_conversions.h"
9 #include "ui/aura/client/cursor_client.h" 9 #include "ui/aura/client/cursor_client.h"
10 #include "ui/aura/window.h" 10 #include "ui/aura/window.h"
(...skipping 21 matching lines...) Expand all
32 // until all fingers are released. 32 // until all fingers are released.
33 const int kTouchIdNone = -1; 33 const int kTouchIdNone = -1;
34 } // namespace 34 } // namespace
35 35
36 TouchExplorationController::TouchExplorationController( 36 TouchExplorationController::TouchExplorationController(
37 aura::Window* root_window) 37 aura::Window* root_window)
38 : root_window_(root_window), 38 : root_window_(root_window),
39 initial_touch_id_passthrough_mapping_(kTouchIdUnassigned), 39 initial_touch_id_passthrough_mapping_(kTouchIdUnassigned),
40 state_(NO_FINGERS_DOWN), 40 state_(NO_FINGERS_DOWN),
41 event_handler_for_testing_(NULL), 41 event_handler_for_testing_(NULL),
42 gesture_provider_(this),
42 prev_state_(NO_FINGERS_DOWN) { 43 prev_state_(NO_FINGERS_DOWN) {
43 CHECK(root_window); 44 CHECK(root_window);
44 root_window->GetHost()->GetEventSource()->AddEventRewriter(this); 45 root_window->GetHost()->GetEventSource()->AddEventRewriter(this);
45 } 46 }
46 47
47 TouchExplorationController::~TouchExplorationController() { 48 TouchExplorationController::~TouchExplorationController() {
48 root_window_->GetHost()->GetEventSource()->RemoveEventRewriter(this); 49 root_window_->GetHost()->GetEventSource()->RemoveEventRewriter(this);
49 } 50 }
50 51
51 void TouchExplorationController::CallTapTimerNowForTesting() { 52 void TouchExplorationController::CallTapTimerNowForTesting() {
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 case NO_FINGERS_DOWN: 121 case NO_FINGERS_DOWN:
121 return InNoFingersDown(touch_event, rewritten_event); 122 return InNoFingersDown(touch_event, rewritten_event);
122 case SINGLE_TAP_PRESSED: 123 case SINGLE_TAP_PRESSED:
123 return InSingleTapPressed(touch_event, rewritten_event); 124 return InSingleTapPressed(touch_event, rewritten_event);
124 case SINGLE_TAP_RELEASED: 125 case SINGLE_TAP_RELEASED:
125 return InSingleTapReleased(touch_event, rewritten_event); 126 return InSingleTapReleased(touch_event, rewritten_event);
126 case DOUBLE_TAP_PRESSED: 127 case DOUBLE_TAP_PRESSED:
127 return InDoubleTapPressed(touch_event, rewritten_event); 128 return InDoubleTapPressed(touch_event, rewritten_event);
128 case TOUCH_EXPLORATION: 129 case TOUCH_EXPLORATION:
129 return InTouchExploration(touch_event, rewritten_event); 130 return InTouchExploration(touch_event, rewritten_event);
131 case GESTURE_IN_PROGRESS:
132 return InGestureInProgress(touch_event, rewritten_event);
130 case PASSTHROUGH_MINUS_ONE: 133 case PASSTHROUGH_MINUS_ONE:
131 return InPassthroughMinusOne(touch_event, rewritten_event); 134 return InPassthroughMinusOne(touch_event, rewritten_event);
132 case TOUCH_EXPLORE_SECOND_PRESS: 135 case TOUCH_EXPLORE_SECOND_PRESS:
133 return InTouchExploreSecondPress(touch_event, rewritten_event); 136 return InTouchExploreSecondPress(touch_event, rewritten_event);
134 } 137 }
135 138
136 NOTREACHED(); 139 NOTREACHED();
137 return ui::EVENT_REWRITE_CONTINUE; 140 return ui::EVENT_REWRITE_CONTINUE;
138 } 141 }
139 142
140 ui::EventRewriteStatus TouchExplorationController::NextDispatchEvent( 143 ui::EventRewriteStatus TouchExplorationController::NextDispatchEvent(
141 const ui::Event& last_event, scoped_ptr<ui::Event>* new_event) { 144 const ui::Event& last_event, scoped_ptr<ui::Event>* new_event) {
142 NOTREACHED(); 145 NOTREACHED();
143 return ui::EVENT_REWRITE_CONTINUE; 146 return ui::EVENT_REWRITE_CONTINUE;
144 } 147 }
145 148
146 ui::EventRewriteStatus TouchExplorationController::InNoFingersDown( 149 ui::EventRewriteStatus TouchExplorationController::InNoFingersDown(
147 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { 150 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) {
148 const ui::EventType type = event.type(); 151 const ui::EventType type = event.type();
149 if (type == ui::ET_TOUCH_PRESSED) { 152 if (type == ui::ET_TOUCH_PRESSED) {
150 initial_press_.reset(new TouchEvent(event)); 153 initial_press_.reset(new TouchEvent(event));
151 tap_timer_.Start(FROM_HERE, 154 tap_timer_.Start(FROM_HERE,
152 gesture_detector_config_.double_tap_timeout, 155 gesture_detector_config_.double_tap_timeout,
153 this, 156 this,
154 &TouchExplorationController::OnTapTimerFired); 157 &TouchExplorationController::OnTapTimerFired);
158 gesture_provider_.OnTouchEvent(event);
159 gesture_provider_.OnTouchEventAck(false);
155 state_ = SINGLE_TAP_PRESSED; 160 state_ = SINGLE_TAP_PRESSED;
156 VLOG_STATE(); 161 VLOG_STATE();
157 return ui::EVENT_REWRITE_DISCARD; 162 return ui::EVENT_REWRITE_DISCARD;
158 } 163 }
159 164
160 NOTREACHED(); 165 NOTREACHED();
161 return ui::EVENT_REWRITE_CONTINUE; 166 return ui::EVENT_REWRITE_CONTINUE;
162 } 167 }
163 168
164 ui::EventRewriteStatus TouchExplorationController::InSingleTapPressed( 169 ui::EventRewriteStatus TouchExplorationController::InSingleTapPressed(
165 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { 170 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) {
166 const ui::EventType type = event.type(); 171 const ui::EventType type = event.type();
167 172
168 if (type == ui::ET_TOUCH_PRESSED) { 173 if (type == ui::ET_TOUCH_PRESSED) {
169 // Adding a second finger within the timeout period switches to 174 // Adding a second finger within the timeout period switches to
170 // passthrough. 175 // passthrough.
171 state_ = PASSTHROUGH_MINUS_ONE; 176 state_ = PASSTHROUGH_MINUS_ONE;
172 return InPassthroughMinusOne(event, rewritten_event); 177 return InPassthroughMinusOne(event, rewritten_event);
173 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { 178 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
174 DCHECK_EQ(0U, current_touch_ids_.size()); 179 DCHECK_EQ(0U, current_touch_ids_.size());
175 state_ = SINGLE_TAP_RELEASED; 180 state_ = SINGLE_TAP_RELEASED;
176 VLOG_STATE(); 181 VLOG_STATE();
177 return EVENT_REWRITE_DISCARD; 182 return EVENT_REWRITE_DISCARD;
178 } else if (type == ui::ET_TOUCH_MOVED) { 183 } else if (type == ui::ET_TOUCH_MOVED) {
179 // If the user moves far enough from the initial touch location (outside 184 float delta_time =
180 // the "slop" region, jump to the touch exploration mode early. 185 (event.time_stamp() - initial_press_->time_stamp()).InSecondsF();
181 // TODO(evy, lisayin): Add gesture recognition here instead - 186 float delta_distance =
182 // we should probably jump to gesture mode here if the velocity is 187 (event.location() - initial_press_->location()).Length();
183 // high enough, and touch exploration if the velocity is lower. 188 float velocity = delta_distance / delta_time;
184 float delta = (event.location() - initial_press_->location()).Length(); 189 VLOG(0) << "\n Delta time: " << delta_time
185 if (delta > gesture_detector_config_.touch_slop) { 190 << "\n Delta distance: " << delta_distance
186 EnterTouchToMouseMode(); 191 << "\n Velocity of click: " << velocity
187 state_ = TOUCH_EXPLORATION; 192 << "\n Minimum swipe velocity: "
188 VLOG_STATE(); 193 << gesture_detector_config_.minimum_swipe_velocity;
189 return InTouchExploration(event, rewritten_event); 194 if (delta_distance > gesture_detector_config_.touch_slop) {
195 // If the user moves fast enough and far enough
dmazzoni 2014/06/23 15:50:44 Nit: indent the comment to match inside the block.
196 // from the initial touch location, start gesture detection
197 if (velocity > gesture_detector_config_.minimum_swipe_velocity) {
198 state_ = GESTURE_IN_PROGRESS;
199 VLOG_STATE();
200 return InGestureInProgress(event, rewritten_event);
201 }
202 // Otherwise, if the user moves far enough from the initial touch location
dmazzoni 2014/06/23 15:50:44 Nit: don't put comments in-between the final } of
203 // outside the "slop" region, jump to the touch exploration mode early.
204 else {
205 EnterTouchToMouseMode();
206 state_ = TOUCH_EXPLORATION;
207 VLOG_STATE();
208 return InTouchExploration(event, rewritten_event);
209 }
190 } 210 }
191
192 return EVENT_REWRITE_DISCARD; 211 return EVENT_REWRITE_DISCARD;
193 } 212 }
194 NOTREACHED() << "Unexpected event type received."; 213 NOTREACHED() << "Unexpected event type received.";
195 return ui::EVENT_REWRITE_CONTINUE; 214 return ui::EVENT_REWRITE_CONTINUE;
196 } 215 }
197 216
198 ui::EventRewriteStatus TouchExplorationController::InSingleTapReleased( 217 ui::EventRewriteStatus TouchExplorationController::InSingleTapReleased(
199 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { 218 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) {
200 const ui::EventType type = event.type(); 219 const ui::EventType type = event.type();
201 if (type == ui::ET_TOUCH_PRESSED) { 220 if (type == ui::ET_TOUCH_PRESSED) {
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 NOTREACHED() << "Unexpected event type received."; 295 NOTREACHED() << "Unexpected event type received.";
277 return ui::EVENT_REWRITE_CONTINUE; 296 return ui::EVENT_REWRITE_CONTINUE;
278 } 297 }
279 298
280 // Rewrite as a mouse-move event. 299 // Rewrite as a mouse-move event.
281 *rewritten_event = CreateMouseMoveEvent(event.location(), event.flags()); 300 *rewritten_event = CreateMouseMoveEvent(event.location(), event.flags());
282 last_touch_exploration_.reset(new TouchEvent(event)); 301 last_touch_exploration_.reset(new TouchEvent(event));
283 return ui::EVENT_REWRITE_REWRITTEN; 302 return ui::EVENT_REWRITE_REWRITTEN;
284 } 303 }
285 304
305 ui::EventRewriteStatus TouchExplorationController::InGestureInProgress(
306 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) {
307 ui::EventType type = event.type();
308 gfx::PointF location = event.location_f();
309 if (type == ui::ET_TOUCH_PRESSED) {
310 return EVENT_REWRITE_DISCARD;
311 }
312 if (type == ui::ET_TOUCH_MOVED) {
313 gesture_provider_.OnTouchEvent(event);
dmazzoni 2014/06/23 15:50:44 If you're throwing away "pressed" events for any f
lisayin 2014/06/23 16:48:43 Just to clarify, I should check the id of the even
314 gesture_provider_.OnTouchEventAck(false);
315 }
316 if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
317 gesture_provider_.OnTouchEvent(event);
318 gesture_provider_.OnTouchEventAck(true);
319 if (current_touch_ids_.size() == 0)
320 ResetToNoFingersDown();
321 }
322 return ui::EVENT_REWRITE_DISCARD;
323 }
324
286 ui::EventRewriteStatus TouchExplorationController::InPassthroughMinusOne( 325 ui::EventRewriteStatus TouchExplorationController::InPassthroughMinusOne(
287 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { 326 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) {
288 ui::EventType type = event.type(); 327 ui::EventType type = event.type();
289 gfx::PointF location = event.location_f(); 328 gfx::PointF location = event.location_f();
290 329
291 if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { 330 if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
292 if (current_touch_ids_.size() == 0) 331 if (current_touch_ids_.size() == 0)
293 ResetToNoFingersDown(); 332 ResetToNoFingersDown();
294 333
295 if (initial_touch_id_passthrough_mapping_ == kTouchIdUnassigned) { 334 if (initial_touch_id_passthrough_mapping_ == kTouchIdUnassigned) {
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 (*rewritten_event)->set_flags(event.flags()); 407 (*rewritten_event)->set_flags(event.flags());
369 state_ = TOUCH_EXPLORATION; 408 state_ = TOUCH_EXPLORATION;
370 VLOG_STATE(); 409 VLOG_STATE();
371 return ui::EVENT_REWRITE_REWRITTEN; 410 return ui::EVENT_REWRITE_REWRITTEN;
372 } 411 }
373 NOTREACHED() << "Unexpected event type received."; 412 NOTREACHED() << "Unexpected event type received.";
374 return ui::EVENT_REWRITE_CONTINUE; 413 return ui::EVENT_REWRITE_CONTINUE;
375 } 414 }
376 415
377 void TouchExplorationController::OnTapTimerFired() { 416 void TouchExplorationController::OnTapTimerFired() {
378 if (state_ != SINGLE_TAP_RELEASED && state_ != SINGLE_TAP_PRESSED) 417 if (state_ != SINGLE_TAP_RELEASED && state_ != SINGLE_TAP_PRESSED &&
dmazzoni 2014/06/23 15:50:44 Nit: for readability, when there are multiple line
418 state_ != GESTURE_IN_PROGRESS)
379 return; 419 return;
380 420
381 if (state_ == SINGLE_TAP_RELEASED) { 421 if (state_ == SINGLE_TAP_RELEASED) {
382 ResetToNoFingersDown(); 422 ResetToNoFingersDown();
383 } else { 423 } else {
384 EnterTouchToMouseMode(); 424 EnterTouchToMouseMode();
425 // Discard any pending gestures
426 delete gesture_provider_.GetAndResetPendingGestures();
385 state_ = TOUCH_EXPLORATION; 427 state_ = TOUCH_EXPLORATION;
386 VLOG_STATE(); 428 VLOG_STATE();
387 } 429 }
388 430
389 scoped_ptr<ui::Event> mouse_move = CreateMouseMoveEvent( 431 scoped_ptr<ui::Event> mouse_move = CreateMouseMoveEvent(
390 initial_press_->location(), initial_press_->flags()); 432 initial_press_->location(), initial_press_->flags());
391 DispatchEvent(mouse_move.get()); 433 DispatchEvent(mouse_move.get());
392 last_touch_exploration_.reset(new TouchEvent(*initial_press_)); 434 last_touch_exploration_.reset(new TouchEvent(*initial_press_));
393 } 435 }
394 436
395 void TouchExplorationController::DispatchEvent(ui::Event* event) { 437 void TouchExplorationController::DispatchEvent(ui::Event* event) {
396 if (event_handler_for_testing_) { 438 if (event_handler_for_testing_) {
397 event_handler_for_testing_->OnEvent(event); 439 event_handler_for_testing_->OnEvent(event);
398 return; 440 return;
399 } 441 }
400 442
401 ui::EventDispatchDetails result ALLOW_UNUSED = 443 ui::EventDispatchDetails result ALLOW_UNUSED =
402 root_window_->GetHost()->dispatcher()->OnEventFromSource(event); 444 root_window_->GetHost()->dispatcher()->OnEventFromSource(event);
403 } 445 }
404 446
447 void TouchExplorationController::OnGestureEvent(ui::GestureEvent* gesture) {
448 CHECK(gesture->IsGestureEvent());
449 VLOG(0) << " \n Gesture Triggered: " << gesture->name();
450 }
451
405 scoped_ptr<ui::Event> TouchExplorationController::CreateMouseMoveEvent( 452 scoped_ptr<ui::Event> TouchExplorationController::CreateMouseMoveEvent(
406 const gfx::PointF& location, 453 const gfx::PointF& location,
407 int flags) { 454 int flags) {
408 return scoped_ptr<ui::Event>( 455 return scoped_ptr<ui::Event>(
409 new ui::MouseEvent( 456 new ui::MouseEvent(
410 ui::ET_MOUSE_MOVED, 457 ui::ET_MOUSE_MOVED,
411 location, 458 location,
412 location, 459 location,
413 flags | ui::EF_IS_SYNTHESIZED | ui::EF_TOUCH_ACCESSIBILITY, 460 flags | ui::EF_IS_SYNTHESIZED | ui::EF_TOUCH_ACCESSIBILITY,
414 0)); 461 0));
415 } 462 }
416 463
417 void TouchExplorationController::EnterTouchToMouseMode() { 464 void TouchExplorationController::EnterTouchToMouseMode() {
418 aura::client::CursorClient* cursor_client = 465 aura::client::CursorClient* cursor_client =
419 aura::client::GetCursorClient(root_window_); 466 aura::client::GetCursorClient(root_window_);
420 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) 467 if (cursor_client && !cursor_client->IsMouseEventsEnabled())
421 cursor_client->EnableMouseEvents(); 468 cursor_client->EnableMouseEvents();
422 if (cursor_client && cursor_client->IsCursorVisible()) 469 if (cursor_client && cursor_client->IsCursorVisible())
423 cursor_client->HideCursor(); 470 cursor_client->HideCursor();
424 } 471 }
425 472
426 void TouchExplorationController::ResetToNoFingersDown() { 473 void TouchExplorationController::ResetToNoFingersDown() {
474 scoped_ptr<ScopedVector<ui::GestureEvent> > gestures;
475 gestures.reset(gesture_provider_.GetAndResetPendingGestures());
476 if (gestures != NULL) {
477 for (ScopedVector<GestureEvent>::iterator i = gestures->begin();
478 i != gestures->end();
479 ++i) {
480 OnGestureEvent(*i);
481 }
482 }
427 state_ = NO_FINGERS_DOWN; 483 state_ = NO_FINGERS_DOWN;
428 initial_touch_id_passthrough_mapping_ = kTouchIdUnassigned; 484 initial_touch_id_passthrough_mapping_ = kTouchIdUnassigned;
429 VLOG_STATE(); 485 VLOG_STATE();
430 if (tap_timer_.IsRunning()) 486 if (tap_timer_.IsRunning())
431 tap_timer_.Stop(); 487 tap_timer_.Stop();
432 } 488 }
433 489
434 void TouchExplorationController::VlogState(const char* function_name) { 490 void TouchExplorationController::VlogState(const char* function_name) {
435 if (prev_state_ == state_) 491 if (prev_state_ == state_)
436 return; 492 return;
(...skipping 26 matching lines...) Expand all
463 case NO_FINGERS_DOWN: 519 case NO_FINGERS_DOWN:
464 return "NO_FINGERS_DOWN"; 520 return "NO_FINGERS_DOWN";
465 case SINGLE_TAP_PRESSED: 521 case SINGLE_TAP_PRESSED:
466 return "SINGLE_TAP_PRESSED"; 522 return "SINGLE_TAP_PRESSED";
467 case SINGLE_TAP_RELEASED: 523 case SINGLE_TAP_RELEASED:
468 return "SINGLE_TAP_RELEASED"; 524 return "SINGLE_TAP_RELEASED";
469 case DOUBLE_TAP_PRESSED: 525 case DOUBLE_TAP_PRESSED:
470 return "DOUBLE_TAP_PRESSED"; 526 return "DOUBLE_TAP_PRESSED";
471 case TOUCH_EXPLORATION: 527 case TOUCH_EXPLORATION:
472 return "TOUCH_EXPLORATION"; 528 return "TOUCH_EXPLORATION";
529 case GESTURE_IN_PROGRESS:
530 return "GESTURE_IN_PROGRESS";
473 case PASSTHROUGH_MINUS_ONE: 531 case PASSTHROUGH_MINUS_ONE:
474 return "PASSTHROUGH_MINUS_ONE"; 532 return "PASSTHROUGH_MINUS_ONE";
475 case TOUCH_EXPLORE_SECOND_PRESS: 533 case TOUCH_EXPLORE_SECOND_PRESS:
476 return "TOUCH_EXPLORE_SECOND_PRESS"; 534 return "TOUCH_EXPLORE_SECOND_PRESS";
477 } 535 }
478 return "Not a state"; 536 return "Not a state";
479 } 537 }
480 538
481 std::string TouchExplorationController::EnumEventTypeToString( 539 std::string TouchExplorationController::EnumEventTypeToString(
482 ui::EventType type) { 540 ui::EventType type) {
483 // Add more cases later. For now, these are the most frequently seen 541 // Add more cases later. For now, these are the most frequently seen
484 // event types. 542 // event types.
485 switch (type) { 543 switch (type) {
486 case ET_TOUCH_RELEASED: 544 case ET_TOUCH_RELEASED:
487 return "ET_TOUCH_RELEASED"; 545 return "ET_TOUCH_RELEASED";
488 case ET_TOUCH_PRESSED: 546 case ET_TOUCH_PRESSED:
489 return "ET_TOUCH_PRESSED"; 547 return "ET_TOUCH_PRESSED";
490 case ET_TOUCH_MOVED: 548 case ET_TOUCH_MOVED:
491 return "ET_TOUCH_MOVED"; 549 return "ET_TOUCH_MOVED";
492 case ET_TOUCH_CANCELLED: 550 case ET_TOUCH_CANCELLED:
493 return "ET_TOUCH_CANCELLED"; 551 return "ET_TOUCH_CANCELLED";
494 default: 552 default:
495 return base::IntToString(type); 553 return base::IntToString(type);
496 } 554 }
497 } 555 }
498 556
499 } // namespace ui 557 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698