1010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// found in the LICENSE file.
4010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
5010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/chromeos/touch_exploration_controller.h"
6010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
7010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/logging.h"
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
96e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/time/default_tick_clock.h"
10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/aura/client/cursor_client.h"
11010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/aura/window.h"
12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/aura/window_event_dispatcher.h"
13010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/aura/window_tree_host.h"
14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/events/event.h"
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/events/event_processor.h"
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/events/event_utils.h"
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/gfx/geometry/rect.h"
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#define SET_STATE(state) SetState(state, __func__)
20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define VLOG_EVENT(event) if (VLOG_IS_ON(0)) VlogEvent(event, __func__)
21010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
22010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)namespace ui {
23010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace {
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Delay between adjustment sounds.
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const base::TimeDelta kSoundDelay = base::TimeDelta::FromMilliseconds(150);
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Delay before corner passthrough activates.
306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const base::TimeDelta kCornerPassthroughDelay =
316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    base::TimeDelta::FromMilliseconds(700);
326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// In ChromeOS, VKEY_LWIN is synonymous for the search key.
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst ui::KeyboardCode kChromeOSSearchKey = ui::VKEY_LWIN;
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
37010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TouchExplorationController::TouchExplorationController(
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    aura::Window* root_window,
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    TouchExplorationControllerDelegate* delegate)
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    : root_window_(root_window),
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      delegate_(delegate),
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      state_(NO_FINGERS_DOWN),
436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      gesture_provider_(new GestureProviderAura(this)),
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      prev_state_(NO_FINGERS_DOWN),
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      VLOG_on_(true),
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      tick_clock_(NULL) {
47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  CHECK(root_window);
48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  root_window->GetHost()->GetEventSource()->AddEventRewriter(this);
496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  InitializeSwipeGestureMaps();
50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
51010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
52010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TouchExplorationController::~TouchExplorationController() {
53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  root_window_->GetHost()->GetEventSource()->RemoveEventRewriter(this);
54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)ui::EventRewriteStatus TouchExplorationController::RewriteEvent(
57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const ui::Event& event,
58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    scoped_ptr<ui::Event>* rewritten_event) {
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!event.IsTouchEvent()) {
606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (event.IsKeyEvent()) {
616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      const ui::KeyEvent& key_event = static_cast<const ui::KeyEvent&>(event);
626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      VLOG(0) << "\nKeyboard event: " << key_event.name()
636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)              << "\n Key code: " << key_event.key_code()
646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)              << ", Flags: " << key_event.flags()
656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)              << ", Is char: " << key_event.is_char();
666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
67010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return ui::EVENT_REWRITE_CONTINUE;
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const ui::TouchEvent& touch_event = static_cast<const ui::TouchEvent&>(event);
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // If the tap timer should have fired by now but hasn't, run it now and
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // stop the timer. This is important so that behavior is consistent with
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // the timestamps of the events, and not dependent on the granularity of
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // the timer.
75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (tap_timer_.IsRunning() &&
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      touch_event.time_stamp() - initial_press_->time_stamp() >
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          gesture_detector_config_.double_tap_timeout) {
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    tap_timer_.Stop();
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    OnTapTimerFired();
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Note: this may change the state. We should now continue and process
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // this event under this new state.
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (passthrough_timer_.IsRunning() &&
856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      event.time_stamp() - initial_press_->time_stamp() >
866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          gesture_detector_config_.longpress_timeout) {
876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    passthrough_timer_.Stop();
886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    OnPassthroughTimerFired();
896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const ui::EventType type = touch_event.type();
92010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const gfx::PointF& location = touch_event.location_f();
93010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const int touch_id = touch_event.touch_id();
94010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Always update touch ids and touch locations, so we can use those
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // no matter what state we're in.
97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (type == ui::ET_TOUCH_PRESSED) {
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    current_touch_ids_.push_back(touch_id);
99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    touch_locations_.insert(std::pair<int, gfx::PointF>(touch_id, location));
100010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<int>::iterator it = std::find(
102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        current_touch_ids_.begin(), current_touch_ids_.end(), touch_id);
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Can happen if touch exploration is enabled while fingers were down.
105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (it == current_touch_ids_.end())
106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return ui::EVENT_REWRITE_CONTINUE;
107010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    current_touch_ids_.erase(it);
109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    touch_locations_.erase(touch_id);
110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else if (type == ui::ET_TOUCH_MOVED) {
111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<int>::iterator it = std::find(
112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        current_touch_ids_.begin(), current_touch_ids_.end(), touch_id);
113010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Can happen if touch exploration is enabled while fingers were down.
115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (it == current_touch_ids_.end())
116010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return ui::EVENT_REWRITE_CONTINUE;
117010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    touch_locations_[*it] = location;
1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else {
1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    NOTREACHED() << "Unexpected event type received: " << event.name();
1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return ui::EVENT_REWRITE_CONTINUE;
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  VLOG_EVENT(touch_event);
1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // In order to avoid accidentally double tapping when moving off the edge
1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // of the screen, the state will be rewritten to NoFingersDown.
1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if ((type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) &&
1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      FindEdgesWithinBounds(touch_event.location(), kLeavingScreenEdge) !=
1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          NO_EDGE) {
1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (VLOG_on_)
1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      VLOG(0) << "Leaving screen";
1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Indicates to the user that they are leaving the screen.
1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    delegate_->PlayExitScreenEarcon();
1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (current_touch_ids_.size() == 0) {
1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(NO_FINGERS_DOWN);
1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (VLOG_on_) {
1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        VLOG(0) << "Reset to no fingers in Rewrite event because the touch  "
1406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                   "release or cancel was on the edge of the screen.";
1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      }
1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return ui::EVENT_REWRITE_DISCARD;
1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // If the user is in a gesture state, or if there is a possiblity that the
1476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // user will enter it in the future, we send the event to the gesture
1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // provider so it can keep track of the state of the fingers. When the user
1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // leaves one of these states, SET_STATE will set the gesture provider to
1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // NULL.
1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (gesture_provider_.get()) {
1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    gesture_provider_->OnTouchEvent(touch_event);
1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    gesture_provider_->OnTouchEventAck(false);
1546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ProcessGestureEvents();
1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // The rest of the processing depends on what state we're in.
1586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  switch (state_) {
159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case NO_FINGERS_DOWN:
160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return InNoFingersDown(touch_event, rewritten_event);
161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SINGLE_TAP_PRESSED:
162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return InSingleTapPressed(touch_event, rewritten_event);
163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SINGLE_TAP_RELEASED:
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case TOUCH_EXPLORE_RELEASED:
16503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return InSingleTapOrTouchExploreReleased(touch_event, rewritten_event);
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case DOUBLE_TAP_PENDING:
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return InDoubleTapPending(touch_event, rewritten_event);
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case TOUCH_RELEASE_PENDING:
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return InTouchReleasePending(touch_event, rewritten_event);
170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case TOUCH_EXPLORATION:
171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return InTouchExploration(touch_event, rewritten_event);
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case GESTURE_IN_PROGRESS:
173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return InGestureInProgress(touch_event, rewritten_event);
174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case TOUCH_EXPLORE_SECOND_PRESS:
175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return InTouchExploreSecondPress(touch_event, rewritten_event);
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case SLIDE_GESTURE:
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return InSlideGesture(touch_event, rewritten_event);
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case ONE_FINGER_PASSTHROUGH:
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return InOneFingerPassthrough(touch_event, rewritten_event);
1806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case CORNER_PASSTHROUGH:
1816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return InCornerPassthrough(touch_event, rewritten_event);
1826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case WAIT_FOR_NO_FINGERS:
1836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return InWaitForNoFingers(touch_event, rewritten_event);
1846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case TWO_FINGER_TAP:
1856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return InTwoFingerTap(touch_event, rewritten_event);
186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  NOTREACHED();
188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return ui::EVENT_REWRITE_CONTINUE;
189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)ui::EventRewriteStatus TouchExplorationController::NextDispatchEvent(
192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ui::Event& last_event, scoped_ptr<ui::Event>* new_event) {
193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  NOTREACHED();
194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return ui::EVENT_REWRITE_CONTINUE;
195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)ui::EventRewriteStatus TouchExplorationController::InNoFingersDown(
198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) {
199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ui::EventType type = event.type();
2006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (type != ui::ET_TOUCH_PRESSED) {
2016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    NOTREACHED() << "Unexpected event type received: " << event.name();
2026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return ui::EVENT_REWRITE_CONTINUE;
203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
2046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // If the user enters the screen from the edge then send an earcon.
2066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  int edge = FindEdgesWithinBounds(event.location(), kLeavingScreenEdge);
2076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (edge != NO_EDGE)
2086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    delegate_->PlayEnterScreenEarcon();
2096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  int location = FindEdgesWithinBounds(event.location(), kSlopDistanceFromEdge);
2116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // If the press was at a corner, the user might go into corner passthrough
2126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // instead.
2136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  bool in_a_bottom_corner =
2146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      (BOTTOM_LEFT_CORNER == location) || (BOTTOM_RIGHT_CORNER == location);
2156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (in_a_bottom_corner) {
2166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    passthrough_timer_.Start(
2176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        FROM_HERE,
2186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        gesture_detector_config_.longpress_timeout,
2196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        this,
2206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        &TouchExplorationController::OnPassthroughTimerFired);
2216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
2226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  initial_press_.reset(new TouchEvent(event));
2236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  initial_presses_[event.touch_id()] = event.location();
2246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  last_unused_finger_event_.reset(new TouchEvent(event));
2256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  StartTapTimer();
2266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  SET_STATE(SINGLE_TAP_PRESSED);
2276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return ui::EVENT_REWRITE_DISCARD;
228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
229f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
230f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)ui::EventRewriteStatus TouchExplorationController::InSingleTapPressed(
231f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) {
232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ui::EventType type = event.type();
233f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
2346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  int location = FindEdgesWithinBounds(event.location(), kMaxDistanceFromEdge);
2356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  bool in_a_bottom_corner =
2366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      (location == BOTTOM_LEFT_CORNER) || (location == BOTTOM_RIGHT_CORNER);
2376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // If the event is from the initial press and the location is no longer in the
2386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // corner, then we are not waiting for a corner passthrough anymore.
2396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (event.touch_id() == initial_press_->touch_id() && !in_a_bottom_corner) {
2406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (passthrough_timer_.IsRunning()) {
2416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      passthrough_timer_.Stop();
2426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // Since the long press timer has been running, it is possible that the
2436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // tap timer has timed out before the long press timer has. If the tap
2446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // timer timeout has elapsed, then fire the tap timer.
2456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (event.time_stamp() - initial_press_->time_stamp() >
2466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          gesture_detector_config_.double_tap_timeout) {
2476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        OnTapTimerFired();
2486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      }
2496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
2506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
2516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (type == ui::ET_TOUCH_PRESSED) {
2536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    initial_presses_[event.touch_id()] = event.location();
2546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(TWO_FINGER_TAP);
2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return EVENT_REWRITE_DISCARD;
256f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
2576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (passthrough_timer_.IsRunning())
2586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      passthrough_timer_.Stop();
2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (current_touch_ids_.size() == 0 &&
2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        event.touch_id() == initial_press_->touch_id()) {
2616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(SINGLE_TAP_RELEASED);
2625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else if (current_touch_ids_.size() == 0) {
2636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(NO_FINGERS_DOWN);
2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EVENT_REWRITE_DISCARD;
266f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else if (type == ui::ET_TOUCH_MOVED) {
267116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    float distance = (event.location() - initial_press_->location()).Length();
268116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // If the user does not move far enough from the original position, then the
269116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // resulting movement should not be considered to be a deliberate gesture or
270116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // touch exploration.
271116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (distance <= gesture_detector_config_.touch_slop)
272116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return EVENT_REWRITE_DISCARD;
273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    float delta_time =
275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        (event.time_stamp() - initial_press_->time_stamp()).InSecondsF();
276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    float velocity = distance / delta_time;
2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (VLOG_on_) {
2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      VLOG(0) << "\n Delta time: " << delta_time << "\n Distance: " << distance
2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              << "\n Velocity of click: " << velocity
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              << "\n Minimum swipe velocity: "
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              << gesture_detector_config_.minimum_swipe_velocity;
2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Change to slide gesture if the slide occurred at the right edge.
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int edge = FindEdgesWithinBounds(event.location(), kMaxDistanceFromEdge);
2856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (edge & RIGHT_EDGE && edge != BOTTOM_RIGHT_CORNER) {
2866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(SLIDE_GESTURE);
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return InSlideGesture(event, rewritten_event);
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // If the user moves fast enough from the initial touch location, start
291116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // gesture detection. Otherwise, jump to the touch exploration mode early.
292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (velocity > gesture_detector_config_.minimum_swipe_velocity) {
2936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(GESTURE_IN_PROGRESS);
294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return InGestureInProgress(event, rewritten_event);
295010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    EnterTouchToMouseMode();
2976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(TOUCH_EXPLORATION);
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return InTouchExploration(event, rewritten_event);
299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
3006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  NOTREACHED();
301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return ui::EVENT_REWRITE_CONTINUE;
302f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
303f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
304116680a4aac90f2aa7413d9095a592090648e557Ben Murdochui::EventRewriteStatus
30503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)TouchExplorationController::InSingleTapOrTouchExploreReleased(
306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const ui::TouchEvent& event,
307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<ui::Event>* rewritten_event) {
308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ui::EventType type = event.type();
3096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // If there is more than one finger down, then discard to wait until no
3106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // fingers are down.
311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (current_touch_ids_.size() > 1) {
3126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(WAIT_FOR_NO_FINGERS);
313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return ui::EVENT_REWRITE_DISCARD;
314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (type == ui::ET_TOUCH_PRESSED) {
31603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // If there is no touch exploration yet, we can't send a click, so discard.
3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!last_touch_exploration_) {
3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      tap_timer_.Stop();
3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return ui::EVENT_REWRITE_DISCARD;
3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
321f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // This is the second tap in a double-tap (or double tap-hold).
32203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // We set the tap timer. If it fires before the user lifts their finger,
32303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // one-finger passthrough begins. Otherwise, there is a touch press and
32403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // release at the location of the last touch exploration.
3256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(DOUBLE_TAP_PENDING);
3266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // The old tap timer (from the initial click) is stopped if it is still
32703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // going, and the new one is set.
3286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    tap_timer_.Stop();
32903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    StartTapTimer();
3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // This will update as the finger moves before a possible passthrough, and
3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // will determine the offset.
3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    last_unused_finger_event_.reset(new ui::TouchEvent(event));
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return ui::EVENT_REWRITE_DISCARD;
33403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  } else if (type == ui::ET_TOUCH_RELEASED && !last_touch_exploration_) {
33503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // If the previous press was discarded, we need to also handle its
33603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // release.
33703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (current_touch_ids_.size() == 0) {
33803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      SET_STATE(NO_FINGERS_DOWN);
33903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return ui::EVENT_REWRITE_DISCARD;
3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else if (type == ui::ET_TOUCH_MOVED) {
342116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return ui::EVENT_REWRITE_DISCARD;
343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
3446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  NOTREACHED();
345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return ui::EVENT_REWRITE_CONTINUE;
346f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
347f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ui::EventRewriteStatus TouchExplorationController::InDoubleTapPending(
3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const ui::TouchEvent& event,
3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_ptr<ui::Event>* rewritten_event) {
351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ui::EventType type = event.type();
352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (type == ui::ET_TOUCH_PRESSED) {
353f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return ui::EVENT_REWRITE_DISCARD;
3545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else if (type == ui::ET_TOUCH_MOVED) {
3555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // If the user moves far enough from the initial touch location (outside
3565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // the "slop" region, jump to passthrough mode early.
3575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    float delta = (event.location() - initial_press_->location()).Length();
3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (delta > gesture_detector_config_.touch_slop) {
35903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      tap_timer_.Stop();
36003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      OnTapTimerFired();
3615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
3625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return EVENT_REWRITE_DISCARD;
363f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
364f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (current_touch_ids_.size() != 0)
365f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return EVENT_REWRITE_DISCARD;
366f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
3675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_ptr<ui::TouchEvent> touch_press;
3685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    touch_press.reset(new ui::TouchEvent(ui::ET_TOUCH_PRESSED,
3695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                         last_touch_exploration_->location(),
3705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                         initial_press_->touch_id(),
3715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                         event.time_stamp()));
3725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DispatchEvent(touch_press.get());
3735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
374f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    rewritten_event->reset(
375f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        new ui::TouchEvent(ui::ET_TOUCH_RELEASED,
376f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           last_touch_exploration_->location(),
3776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                           initial_press_->touch_id(),
378f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           event.time_stamp()));
379f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    (*rewritten_event)->set_flags(event.flags());
3806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(NO_FINGERS_DOWN);
381010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return ui::EVENT_REWRITE_REWRITTEN;
3825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  NOTREACHED();
3845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return ui::EVENT_REWRITE_CONTINUE;
3855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ui::EventRewriteStatus TouchExplorationController::InTouchReleasePending(
3885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const ui::TouchEvent& event,
3895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_ptr<ui::Event>* rewritten_event) {
3905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const ui::EventType type = event.type();
3915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (type == ui::ET_TOUCH_PRESSED || type == ui::ET_TOUCH_MOVED) {
392f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return ui::EVENT_REWRITE_DISCARD;
3935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
3945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (current_touch_ids_.size() != 0)
3955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return EVENT_REWRITE_DISCARD;
3965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    rewritten_event->reset(
3985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        new ui::TouchEvent(ui::ET_TOUCH_RELEASED,
3995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           last_touch_exploration_->location(),
4005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           initial_press_->touch_id(),
4015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           event.time_stamp()));
4025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    (*rewritten_event)->set_flags(event.flags());
4036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(NO_FINGERS_DOWN);
4045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return ui::EVENT_REWRITE_REWRITTEN;
405f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
4066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  NOTREACHED();
407f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return ui::EVENT_REWRITE_CONTINUE;
408f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
409f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
410f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)ui::EventRewriteStatus TouchExplorationController::InTouchExploration(
411116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const ui::TouchEvent& event,
412116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<ui::Event>* rewritten_event) {
413f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ui::EventType type = event.type();
414f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (type == ui::ET_TOUCH_PRESSED) {
415f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Handle split-tap.
416f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    initial_press_.reset(new TouchEvent(event));
4176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    tap_timer_.Stop();
418f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    rewritten_event->reset(
419f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        new ui::TouchEvent(ui::ET_TOUCH_PRESSED,
420f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           last_touch_exploration_->location(),
421f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           event.touch_id(),
422f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           event.time_stamp()));
423f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    (*rewritten_event)->set_flags(event.flags());
4246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(TOUCH_EXPLORE_SECOND_PRESS);
425f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return ui::EVENT_REWRITE_REWRITTEN;
426f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
427116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    initial_press_.reset(new TouchEvent(event));
4285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    StartTapTimer();
4296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(TOUCH_EXPLORE_RELEASED);
430f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else if (type != ui::ET_TOUCH_MOVED) {
4316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    NOTREACHED();
432f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return ui::EVENT_REWRITE_CONTINUE;
433f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
434f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
435f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Rewrite as a mouse-move event.
436f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  *rewritten_event = CreateMouseMoveEvent(event.location(), event.flags());
437f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  last_touch_exploration_.reset(new TouchEvent(event));
438f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return ui::EVENT_REWRITE_REWRITTEN;
439f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
440f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
441116680a4aac90f2aa7413d9095a592090648e557Ben Murdochui::EventRewriteStatus TouchExplorationController::InGestureInProgress(
442116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const ui::TouchEvent& event,
443116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<ui::Event>* rewritten_event) {
4446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // The events were sent to the gesture provider in RewriteEvent already.
4456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // If no gesture is registered before the tap timer times out, the state
4466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // will change to "wait for no fingers down" or "touch exploration" depending
4476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // on the number of fingers down, and this function will stop being called.
4486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (current_touch_ids_.size() == 0) {
4496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(NO_FINGERS_DOWN);
450116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
4516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return ui::EVENT_REWRITE_DISCARD;
4526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
4536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)ui::EventRewriteStatus TouchExplorationController::InCornerPassthrough(
4556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const ui::TouchEvent& event,
4566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    scoped_ptr<ui::Event>* rewritten_event) {
4576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ui::EventType type = event.type();
4586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // If the first finger has left the corner, then exit passthrough.
4606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (event.touch_id() == initial_press_->touch_id()) {
4616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    int edges = FindEdgesWithinBounds(event.location(), kSlopDistanceFromEdge);
4626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    bool in_a_bottom_corner = (edges == BOTTOM_LEFT_CORNER) ||
4636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                              (edges == BOTTOM_RIGHT_CORNER);
4646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (type == ui::ET_TOUCH_MOVED && in_a_bottom_corner)
4656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return ui::EVENT_REWRITE_DISCARD;
466f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
4675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (current_touch_ids_.size() == 0) {
4686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(NO_FINGERS_DOWN);
4696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return ui::EVENT_REWRITE_DISCARD;
4705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(WAIT_FOR_NO_FINGERS);
4726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return ui::EVENT_REWRITE_DISCARD;
473f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
4746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  rewritten_event->reset(new ui::TouchEvent(
4766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      type, event.location(), event.touch_id(), event.time_stamp()));
4776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  (*rewritten_event)->set_flags(event.flags());
4786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (current_touch_ids_.size() == 0)
4806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(NO_FINGERS_DOWN);
4816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return ui::EVENT_REWRITE_REWRITTEN;
483116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
484116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
4855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ui::EventRewriteStatus TouchExplorationController::InOneFingerPassthrough(
486116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const ui::TouchEvent& event,
487116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<ui::Event>* rewritten_event) {
4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (event.touch_id() != initial_press_->touch_id()) {
4895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (current_touch_ids_.size() == 0) {
4906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(NO_FINGERS_DOWN);
4915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return ui::EVENT_REWRITE_DISCARD;
4935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  rewritten_event->reset(
4955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new ui::TouchEvent(event.type(),
4965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                         event.location() - passthrough_offset_,
4975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                         event.touch_id(),
4985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                         event.time_stamp()));
499f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
500116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  (*rewritten_event)->set_flags(event.flags());
501116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (current_touch_ids_.size() == 0) {
5026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(NO_FINGERS_DOWN);
503116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
504116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return ui::EVENT_REWRITE_REWRITTEN;
505f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
506f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
507f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)ui::EventRewriteStatus TouchExplorationController::InTouchExploreSecondPress(
508f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ui::TouchEvent& event,
509f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    scoped_ptr<ui::Event>* rewritten_event) {
510f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ui::EventType type = event.type();
511f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  gfx::PointF location = event.location_f();
512f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (type == ui::ET_TOUCH_PRESSED) {
5136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // A third finger being pressed means that a split tap can no longer go
5146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // through. The user enters the wait state, Since there has already been
5156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // a press dispatched when split tap began, the touch needs to be
5166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // cancelled.
5176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    rewritten_event->reset(
5186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        new ui::TouchEvent(ui::ET_TOUCH_CANCELLED,
5196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                           last_touch_exploration_->location(),
5206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                           initial_press_->touch_id(),
5216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                           event.time_stamp()));
5226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    (*rewritten_event)->set_flags(event.flags());
5236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(WAIT_FOR_NO_FINGERS);
5246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return ui::EVENT_REWRITE_REWRITTEN;
525f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else if (type == ui::ET_TOUCH_MOVED) {
5266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // If the fingers have moved too far from their original locations,
5276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // the user can no longer split tap.
5286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ui::TouchEvent* original_touch;
5296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (event.touch_id() == last_touch_exploration_->touch_id())
5306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      original_touch = last_touch_exploration_.get();
5316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    else if (event.touch_id() == initial_press_->touch_id())
5326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      original_touch = initial_press_.get();
5336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    else {
5346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      NOTREACHED();
5356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(WAIT_FOR_NO_FINGERS);
5366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return ui::EVENT_REWRITE_DISCARD;
5376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
5386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Check the distance between the current finger location and the original
5396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // location. The slop for this is a bit more generous since keeping two
5406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // fingers in place is a bit harder. If the user has left the slop, the
5416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // split tap press (which was previous dispatched) is lifted with a touch
5426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // cancelled, and the user enters the wait state.
5436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if ((event.location() - original_touch->location()).Length() >
5446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        GetSplitTapTouchSlop()) {
5456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      rewritten_event->reset(
5466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          new ui::TouchEvent(ui::ET_TOUCH_CANCELLED,
5476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                             last_touch_exploration_->location(),
5486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                             initial_press_->touch_id(),
5496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                             event.time_stamp()));
5506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      (*rewritten_event)->set_flags(event.flags());
5516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(WAIT_FOR_NO_FINGERS);
5526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return ui::EVENT_REWRITE_REWRITTEN;
5536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
554f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return ui::EVENT_REWRITE_DISCARD;
555f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
556f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // If the touch exploration finger is lifted, there is no option to return
557f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // to touch explore anymore. The remaining finger acts as a pending
558f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // tap or long tap for the last touch explore location.
559f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (event.touch_id() == last_touch_exploration_->touch_id()){
5606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(TOUCH_RELEASE_PENDING);
561f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return EVENT_REWRITE_DISCARD;
562f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
563f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
564f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Continue to release the touch only if the touch explore finger is the
565f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // only finger remaining.
566f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (current_touch_ids_.size() != 1)
567f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return EVENT_REWRITE_DISCARD;
568f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
569f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Rewrite at location of last touch exploration.
570f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    rewritten_event->reset(
571f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        new ui::TouchEvent(ui::ET_TOUCH_RELEASED,
572f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           last_touch_exploration_->location(),
573f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           initial_press_->touch_id(),
574f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           event.time_stamp()));
575f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    (*rewritten_event)->set_flags(event.flags());
5766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(TOUCH_EXPLORATION);
577116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    EnterTouchToMouseMode();
578f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return ui::EVENT_REWRITE_REWRITTEN;
579010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
5806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  NOTREACHED();
581010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return ui::EVENT_REWRITE_CONTINUE;
582010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
583010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
5846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)ui::EventRewriteStatus TouchExplorationController::InWaitForNoFingers(
585116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const ui::TouchEvent& event,
586116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<ui::Event>* rewritten_event) {
5876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (current_touch_ids_.size() == 0)
5886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(NO_FINGERS_DOWN);
589116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return EVENT_REWRITE_DISCARD;
590116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
591f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
5925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void TouchExplorationController::PlaySoundForTimer() {
5936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  delegate_->PlayVolumeAdjustEarcon();
5945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
5955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ui::EventRewriteStatus TouchExplorationController::InSlideGesture(
5975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const ui::TouchEvent& event,
5985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_ptr<ui::Event>* rewritten_event) {
5995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // The timer should not fire when sliding.
6006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  tap_timer_.Stop();
6015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ui::EventType type = event.type();
6035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // If additional fingers are added before a swipe gesture has been registered,
6045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // then wait until all fingers have been lifted.
6055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (type == ui::ET_TOUCH_PRESSED ||
6065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      event.touch_id() != initial_press_->touch_id()) {
6075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (sound_timer_.IsRunning())
6085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      sound_timer_.Stop();
6096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(WAIT_FOR_NO_FINGERS);
6105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return EVENT_REWRITE_DISCARD;
6115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
6125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // There should not be more than one finger down.
6146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DCHECK(current_touch_ids_.size() <= 1);
6156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
6165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Allows user to return to the edge to adjust the sound if they have left the
6175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // boundaries.
6185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int edge = FindEdgesWithinBounds(event.location(), kSlopDistanceFromEdge);
6195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!(edge & RIGHT_EDGE) && (type != ui::ET_TOUCH_RELEASED)) {
6205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (sound_timer_.IsRunning()) {
6215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      sound_timer_.Stop();
6225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
6235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return EVENT_REWRITE_DISCARD;
6245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
6255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // This can occur if the user leaves the screen edge and then returns to it to
6275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // continue adjusting the sound.
6285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!sound_timer_.IsRunning()) {
6295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    sound_timer_.Start(FROM_HERE,
6305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       kSoundDelay,
6315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       this,
6325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       &ui::TouchExplorationController::PlaySoundForTimer);
6336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    delegate_->PlayVolumeAdjustEarcon();
6345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
6355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (current_touch_ids_.size() == 0) {
6376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(NO_FINGERS_DOWN);
6385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
6396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return ui::EVENT_REWRITE_DISCARD;
6406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
6416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
6426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)ui::EventRewriteStatus TouchExplorationController::InTwoFingerTap(
6436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const ui::TouchEvent& event,
6446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    scoped_ptr<ui::Event>* rewritten_event) {
6456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ui::EventType type = event.type();
6466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (type == ui::ET_TOUCH_PRESSED) {
6476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // This is now a three finger gesture.
6486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(GESTURE_IN_PROGRESS);
6496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return ui::EVENT_REWRITE_DISCARD;
6506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
6516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
6526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (type == ui::ET_TOUCH_MOVED) {
6536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Determine if it was a swipe.
6546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    gfx::Point original_location = initial_presses_[event.touch_id()];
6556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    float distance = (event.location() - original_location).Length();
6566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // If the user moves too far from the original position, consider the
6576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // movement a swipe.
6586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (distance > gesture_detector_config_.touch_slop) {
6596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(GESTURE_IN_PROGRESS);
6605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
6615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return ui::EVENT_REWRITE_DISCARD;
6625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
6635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (current_touch_ids_.size() != 0)
6656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return ui::EVENT_REWRITE_DISCARD;
6666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
6676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (type == ui::ET_TOUCH_RELEASED) {
6686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // In ChromeVox, pressing control will stop ChromeVox from speaking.
6696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ui::KeyEvent control_down(
6706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, ui::EF_CONTROL_DOWN);
6716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ui::KeyEvent control_up(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL, ui::EF_NONE);
6726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
6736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    DispatchEvent(&control_down);
6746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    DispatchEvent(&control_up);
6756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SET_STATE(NO_FINGERS_DOWN);
6766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return ui::EVENT_REWRITE_DISCARD;
6776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
6785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return ui::EVENT_REWRITE_DISCARD;
6795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
6805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)base::TimeDelta TouchExplorationController::Now() {
6825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (tick_clock_) {
6835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // This is the same as what EventTimeForNow() does, but here we do it
6845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // with a clock that can be replaced with a simulated clock for tests.
6855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return base::TimeDelta::FromInternalValue(
6865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        tick_clock_->NowTicks().ToInternalValue());
6875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
6885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return ui::EventTimeForNow();
6895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
6905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void TouchExplorationController::StartTapTimer() {
6925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  tap_timer_.Start(FROM_HERE,
6935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                   gesture_detector_config_.double_tap_timeout,
6945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                   this,
6955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                   &TouchExplorationController::OnTapTimerFired);
6965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
6975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
698116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TouchExplorationController::OnTapTimerFired() {
699116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  switch (state_) {
700116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case SINGLE_TAP_RELEASED:
7016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(NO_FINGERS_DOWN);
702116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      break;
703116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case TOUCH_EXPLORE_RELEASED:
7046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(NO_FINGERS_DOWN);
705116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      last_touch_exploration_.reset(new TouchEvent(*initial_press_));
706116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return;
70703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    case DOUBLE_TAP_PENDING: {
70803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      SET_STATE(ONE_FINGER_PASSTHROUGH);
70903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      passthrough_offset_ = last_unused_finger_event_->location() -
71003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            last_touch_exploration_->location();
71103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      scoped_ptr<ui::TouchEvent> passthrough_press(
71203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          new ui::TouchEvent(ui::ET_TOUCH_PRESSED,
71303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                             last_touch_exploration_->location(),
71403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                             last_unused_finger_event_->touch_id(),
71503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                             Now()));
71603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      DispatchEvent(passthrough_press.get());
71703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return;
71803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
7196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case SINGLE_TAP_PRESSED:
7206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (passthrough_timer_.IsRunning())
7216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return;
7226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case GESTURE_IN_PROGRESS:
7236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // If only one finger is down, go into touch exploration.
7246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (current_touch_ids_.size() == 1) {
7256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        EnterTouchToMouseMode();
7266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        SET_STATE(TOUCH_EXPLORATION);
7276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        break;
7286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      }
7296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // Otherwise wait for all fingers to be lifted.
7306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(WAIT_FOR_NO_FINGERS);
7316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return;
7326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case TWO_FINGER_TAP:
7336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      SET_STATE(WAIT_FOR_NO_FINGERS);
7346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      break;
7356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    default:
7366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return;
7376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
7386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EnterTouchToMouseMode();
7396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  scoped_ptr<ui::Event> mouse_move =
7406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      CreateMouseMoveEvent(initial_press_->location(), initial_press_->flags());
7416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DispatchEvent(mouse_move.get());
7426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  last_touch_exploration_.reset(new TouchEvent(*initial_press_));
7436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
7446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
7456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void TouchExplorationController::OnPassthroughTimerFired() {
74603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // The passthrough timer will only fire if if the user has held a finger in
74703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // one of the passthrough corners for the duration of the passthrough timeout.
7486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
74903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Check that initial press isn't null. Also a check that if the initial
75003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // corner press was released, then it should not be in corner passthrough.
75103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!initial_press_ ||
75203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      touch_locations_.find(initial_press_->touch_id()) !=
75303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          touch_locations_.end()) {
75403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "No initial press or the initial press has been released.";
755116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
75603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
75703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  gfx::Point location =
75803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      ToRoundedPoint(touch_locations_[initial_press_->touch_id()]);
75903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  int corner = FindEdgesWithinBounds(location, kSlopDistanceFromEdge);
76003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (corner != BOTTOM_LEFT_CORNER && corner != BOTTOM_RIGHT_CORNER)
76103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return;
76203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
7636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (sound_timer_.IsRunning())
7646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    sound_timer_.Stop();
7656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  delegate_->PlayPassthroughEarcon();
76603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  SET_STATE(CORNER_PASSTHROUGH);
76703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return;
7685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
769f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
770f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void TouchExplorationController::DispatchEvent(ui::Event* event) {
771f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ui::EventDispatchDetails result ALLOW_UNUSED =
772f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      root_window_->GetHost()->dispatcher()->OnEventFromSource(event);
773010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
774010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
7756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// This is an override for a function that is only called for timer-based events
7766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// like long press. Events that are created synchronously as a result of
7776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// certain touch events are added to the vector accessible via
7786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// GetAndResetPendingGestures(). We only care about swipes (which are created
7796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// synchronously), so we ignore this callback.
7806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void TouchExplorationController::OnGestureEvent(ui::GestureEvent* gesture) {
781116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
782116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
783116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TouchExplorationController::ProcessGestureEvents() {
784116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<ScopedVector<ui::GestureEvent> > gestures(
7856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      gesture_provider_->GetAndResetPendingGestures());
786116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (gestures) {
787116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for (ScopedVector<GestureEvent>::iterator i = gestures->begin();
788116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         i != gestures->end();
789116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         ++i) {
7906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if ((*i)->type() == ui::ET_GESTURE_SWIPE &&
7916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          state_ == GESTURE_IN_PROGRESS) {
7926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        OnSwipeEvent(*i);
7936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        // The tap timer to leave gesture state is ended, and we now wait for
7946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        // all fingers to be released.
7956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        tap_timer_.Stop();
7966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        SET_STATE(WAIT_FOR_NO_FINGERS);
7976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return;
7986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      }
7996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (state_ == SLIDE_GESTURE && (*i)->IsScrollGestureEvent()) {
8005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        SideSlideControl(*i);
8016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      }
802116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
803116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
804116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
805116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
8065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void TouchExplorationController::SideSlideControl(ui::GestureEvent* gesture) {
8075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ui::EventType type = gesture->type();
8085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (type == ET_GESTURE_SCROLL_BEGIN) {
8106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    delegate_->PlayVolumeAdjustEarcon();
8115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
8125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (type == ET_GESTURE_SCROLL_END) {
8145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (sound_timer_.IsRunning())
8155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      sound_timer_.Stop();
8166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    delegate_->PlayVolumeAdjustEarcon();
8175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
8185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // If the user is in the corner of the right side of the screen, the volume
8205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // will be automatically set to 100% or muted depending on which corner they
8215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // are in. Otherwise, the user will be able to adjust the volume by sliding
8225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // their finger along the right side of the screen. Volume is relative to
8235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // where they are on the right side of the screen.
8245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  gfx::Point location = gesture->location();
8255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int edge = FindEdgesWithinBounds(location, kSlopDistanceFromEdge);
8265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!(edge & RIGHT_EDGE))
8275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
8285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (edge & TOP_EDGE) {
8305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    delegate_->SetOutputLevel(100);
8315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
8325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
8335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (edge & BOTTOM_EDGE) {
8345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    delegate_->SetOutputLevel(0);
8355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
8365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
8375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  location = gesture->location();
8395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  root_window_->GetHost()->ConvertPointFromNativeScreen(&location);
8405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  float volume_adjust_height =
8415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      root_window_->bounds().height() - 2 * kMaxDistanceFromEdge;
8425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  float ratio = (location.y() - kMaxDistanceFromEdge) / volume_adjust_height;
8435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  float volume = 100 - 100 * ratio;
8445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (VLOG_on_) {
8455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    VLOG(0) << "\n Volume = " << volume
8465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            << "\n Location = " << location.ToString()
8475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            << "\n Bounds = " << root_window_->bounds().right();
8485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
8495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  delegate_->SetOutputLevel(int(volume));
8505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
8515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
852116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TouchExplorationController::OnSwipeEvent(ui::GestureEvent* swipe_gesture) {
853116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // A swipe gesture contains details for the direction in which the swipe
8546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // occurred. TODO(evy) : Research which swipe results users most want and
8556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // remap these swipes to the best events. Hopefully in the near future
8566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // there will also be a menu for users to pick custom mappings.
857116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  GestureEventDetails event_details = swipe_gesture->details();
8586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  int num_fingers = event_details.touch_points();
8596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if(VLOG_on_)
8606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    VLOG(0) << "\nSwipe with " << num_fingers << " fingers.";
8616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
8626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (num_fingers > 4)
863116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
8646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
8656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (event_details.swipe_left() &&
8666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      !left_swipe_gestures_[num_fingers].is_null()) {
8676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    left_swipe_gestures_[num_fingers].Run();
8686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else if (event_details.swipe_right() &&
8696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)             !right_swipe_gestures_[num_fingers].is_null()) {
8706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    right_swipe_gestures_[num_fingers].Run();
8716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else if (event_details.swipe_up() &&
8726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)             !up_swipe_gestures_[num_fingers].is_null()) {
8736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    up_swipe_gestures_[num_fingers].Run();
8746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else if (event_details.swipe_down() &&
8756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)             !down_swipe_gestures_[num_fingers].is_null()) {
8766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    down_swipe_gestures_[num_fingers].Run();
877116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
878116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
879116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
8805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)int TouchExplorationController::FindEdgesWithinBounds(gfx::Point point,
8815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                      float bounds) {
8825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Since GetBoundsInScreen is in DIPs but point is not, then point needs to be
8835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // converted.
8845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  root_window_->GetHost()->ConvertPointFromNativeScreen(&point);
8855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  gfx::Rect window = root_window_->GetBoundsInScreen();
8865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  float left_edge_limit = window.x() + bounds;
8885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  float right_edge_limit = window.right() - bounds;
8895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  float top_edge_limit = window.y() + bounds;
8905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  float bottom_edge_limit = window.bottom() - bounds;
8915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Bitwise manipulation in order to determine where on the screen the point
8935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // lies. If more than one bit is turned on, then it is a corner where the two
8945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // bit/edges intersect. Otherwise, if no bits are turned on, the point must be
8955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // in the center of the screen.
8965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int result = NO_EDGE;
8975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (point.x() < left_edge_limit)
8985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    result |= LEFT_EDGE;
8995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (point.x() > right_edge_limit)
9005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    result |= RIGHT_EDGE;
9015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (point.y() < top_edge_limit)
9025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    result |= TOP_EDGE;
9035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (point.y() > bottom_edge_limit)
9045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    result |= BOTTOM_EDGE;
9055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return result;
9065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
9075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
908116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TouchExplorationController::DispatchShiftSearchKeyEvent(
9096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const ui::KeyboardCode third_key) {
910116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // In order to activate the shortcut shift+search+<arrow key>
911116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // three KeyPressed events must be dispatched in succession along
912116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // with three KeyReleased events.
9136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
9146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ui::KeyEvent shift_down(
9155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ui::ET_KEY_PRESSED, ui::VKEY_SHIFT, ui::EF_SHIFT_DOWN);
9166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ui::KeyEvent search_down(
9175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ui::ET_KEY_PRESSED, kChromeOSSearchKey, ui::EF_SHIFT_DOWN);
9186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ui::KeyEvent third_key_down(ui::ET_KEY_PRESSED, third_key, ui::EF_SHIFT_DOWN);
919116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
9206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ui::KeyEvent third_key_up(ui::ET_KEY_RELEASED, third_key, ui::EF_SHIFT_DOWN);
9216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ui::KeyEvent search_up(
9225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ui::ET_KEY_RELEASED, kChromeOSSearchKey, ui::EF_SHIFT_DOWN);
9236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ui ::KeyEvent shift_up(ui::ET_KEY_RELEASED, ui::VKEY_SHIFT, ui::EF_NONE);
924116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
925116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DispatchEvent(&shift_down);
926116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DispatchEvent(&search_down);
9276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DispatchEvent(&third_key_down);
9286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DispatchEvent(&third_key_up);
929116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DispatchEvent(&search_up);
930116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DispatchEvent(&shift_up);
931116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
932116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
9336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)base::Closure TouchExplorationController::BindShiftSearchKeyEvent(
9346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const ui::KeyboardCode third_key) {
9356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return base::Bind(&TouchExplorationController::DispatchShiftSearchKeyEvent,
9366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                    base::Unretained(this),
9376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                    third_key);
9386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
9396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
9406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void TouchExplorationController::DispatchKeyWithFlags(
9416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const ui::KeyboardCode key,
9426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    int flags) {
9436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ui::KeyEvent key_down(ui::ET_KEY_PRESSED, key, flags);
9446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ui::KeyEvent key_up(ui::ET_KEY_RELEASED, key, flags);
9456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DispatchEvent(&key_down);
9466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DispatchEvent(&key_up);
9476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if(VLOG_on_) {
9486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    VLOG(0) << "\nKey down: key code : " << key_down.key_code()
9496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            << ", flags: " << key_down.flags()
9506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            << "\nKey up: key code : " << key_up.key_code()
9516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            << ", flags: " << key_up.flags();
9526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
9536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
9546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
9556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)base::Closure TouchExplorationController::BindKeyEventWithFlags(
9566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const ui::KeyboardCode key,
9576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    int flags) {
9586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return base::Bind(&TouchExplorationController::DispatchKeyWithFlags,
9596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                    base::Unretained(this),
9606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                    key,
9616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                    flags);
9626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
9636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
964010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)scoped_ptr<ui::Event> TouchExplorationController::CreateMouseMoveEvent(
965010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const gfx::PointF& location,
966010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    int flags) {
9675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // The "synthesized" flag should be set on all events that don't have a
9685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // backing native event.
9695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  flags |= ui::EF_IS_SYNTHESIZED;
9705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
9715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // This flag is used to identify mouse move events that were generated from
9725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // touch exploration in Chrome code.
9735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  flags |= ui::EF_TOUCH_ACCESSIBILITY;
9745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
9755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // TODO(dmazzoni) http://crbug.com/391008 - get rid of this hack.
9765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // This is a short-term workaround for the limitation that we're using
9775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // the ChromeVox content script to process touch exploration events, but
9785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // ChromeVox needs a way to distinguish between a real mouse move and a
9795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // mouse move generated from touch exploration, so we have touch exploration
9805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // pretend that the command key was down (which becomes the "meta" key in
9815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // JavaScript). We can remove this hack when the ChromeVox content script
9825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // goes away and native accessibility code sends a touch exploration
9835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // event to the new ChromeVox background page via the automation api.
9845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  flags |= ui::EF_COMMAND_DOWN;
9855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
986010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return scoped_ptr<ui::Event>(
9875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new ui::MouseEvent(ui::ET_MOUSE_MOVED, location, location, flags, 0));
988010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
989010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
990010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void TouchExplorationController::EnterTouchToMouseMode() {
991010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  aura::client::CursorClient* cursor_client =
992010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      aura::client::GetCursorClient(root_window_);
993010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (cursor_client && !cursor_client->IsMouseEventsEnabled())
994010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    cursor_client->EnableMouseEvents();
995010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (cursor_client && cursor_client->IsCursorVisible())
996010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    cursor_client->HideCursor();
997010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
998010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
9996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void TouchExplorationController::SetState(State new_state,
10006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                          const char* function_name) {
10016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  state_ = new_state;
10026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  VlogState(function_name);
10036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // These are the states the user can be in that will never result in a
10046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // gesture before the user returns to NO_FINGERS_DOWN. Therefore, if the
10056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // gesture provider still exists, it's reset to NULL until the user returns
10066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // to NO_FINGERS_DOWN.
10076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  switch (new_state) {
10086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case SINGLE_TAP_RELEASED:
10096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case TOUCH_EXPLORE_RELEASED:
10106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case DOUBLE_TAP_PENDING:
10116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case TOUCH_RELEASE_PENDING:
10126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case TOUCH_EXPLORATION:
10136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case TOUCH_EXPLORE_SECOND_PRESS:
10146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case ONE_FINGER_PASSTHROUGH:
10156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case CORNER_PASSTHROUGH:
10166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case WAIT_FOR_NO_FINGERS:
10176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (gesture_provider_.get())
10186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        gesture_provider_.reset(NULL);
10196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      break;
10206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case NO_FINGERS_DOWN:
10216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      gesture_provider_.reset(new GestureProviderAura(this));
10226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (sound_timer_.IsRunning())
10236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        sound_timer_.Stop();
10246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      tap_timer_.Stop();
10256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      break;
10266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case SINGLE_TAP_PRESSED:
10276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case GESTURE_IN_PROGRESS:
10286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case SLIDE_GESTURE:
10296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case TWO_FINGER_TAP:
10306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      break;
10316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1032f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
1033f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1034f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void TouchExplorationController::VlogState(const char* function_name) {
1035116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!VLOG_on_)
1036116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
1037f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (prev_state_ == state_)
1038f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return;
1039f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  prev_state_ = state_;
1040f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const char* state_string = EnumStateToString(state_);
1041f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  VLOG(0) << "\n Function name: " << function_name
1042f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          << "\n State: " << state_string;
1043f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
1044f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1045f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void TouchExplorationController::VlogEvent(const ui::TouchEvent& touch_event,
1046f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                           const char* function_name) {
1047116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!VLOG_on_)
1048116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
1049116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1050116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (prev_event_ != NULL &&
1051116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      prev_event_->type() == touch_event.type() &&
1052116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      prev_event_->touch_id() == touch_event.touch_id()){
1053116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
1054f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
1055116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // The above statement prevents events of the same type and id from being
1056116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // printed in a row. However, if two fingers are down, they would both be
1057116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // moving and alternating printing move events unless we check for this.
1058116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (prev_event_ != NULL &&
1059116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      prev_event_->type() == ET_TOUCH_MOVED &&
1060116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      touch_event.type() == ET_TOUCH_MOVED){
1061116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
1062116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
10636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1064116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::string& type = touch_event.name();
1065116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const gfx::PointF& location = touch_event.location_f();
1066116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const int touch_id = touch_event.touch_id();
1067116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1068116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  VLOG(0) << "\n Function name: " << function_name
1069116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          << "\n Event Type: " << type
1070116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          << "\n Location: " << location.ToString()
1071116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          << "\n Touch ID: " << touch_id;
1072116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  prev_event_.reset(new TouchEvent(touch_event));
1073f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
1074f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1075f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const char* TouchExplorationController::EnumStateToString(State state) {
1076f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  switch (state) {
1077f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case NO_FINGERS_DOWN:
1078f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return "NO_FINGERS_DOWN";
1079f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SINGLE_TAP_PRESSED:
1080f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return "SINGLE_TAP_PRESSED";
1081f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SINGLE_TAP_RELEASED:
1082f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return "SINGLE_TAP_RELEASED";
1083116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case TOUCH_EXPLORE_RELEASED:
1084116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return "TOUCH_EXPLORE_RELEASED";
10855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case DOUBLE_TAP_PENDING:
10865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return "DOUBLE_TAP_PENDING";
10875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case TOUCH_RELEASE_PENDING:
10885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return "TOUCH_RELEASE_PENDING";
1089f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case TOUCH_EXPLORATION:
1090f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return "TOUCH_EXPLORATION";
1091116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case GESTURE_IN_PROGRESS:
1092116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return "GESTURE_IN_PROGRESS";
1093f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case TOUCH_EXPLORE_SECOND_PRESS:
1094f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return "TOUCH_EXPLORE_SECOND_PRESS";
10956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case CORNER_PASSTHROUGH:
10966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return "CORNER_PASSTHROUGH";
10975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case SLIDE_GESTURE:
10985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return "SLIDE_GESTURE";
10995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case ONE_FINGER_PASSTHROUGH:
11005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return "ONE_FINGER_PASSTHROUGH";
11016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case WAIT_FOR_NO_FINGERS:
11026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return "WAIT_FOR_NO_FINGERS";
11036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    case TWO_FINGER_TAP:
11046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return "TWO_FINGER_TAP";
1105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
1106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return "Not a state";
1107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
1108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
11096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// TODO(evy, lisayin) : Just call abstracted methods on the delegate (e.g.
11106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Swipe(Direction direction, int num_fingers)), and add the DispatchXYZ
11116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// methods to the delegate. Avoid the middle step of dispatching keys at all,
11126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// and simply have ChromeVox/ChromeOS complete the required action.
11136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
11146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void TouchExplorationController::InitializeSwipeGestureMaps() {
11156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Gestures with one finger are used for navigation.
11166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  left_swipe_gestures_[1] = BindShiftSearchKeyEvent(ui::VKEY_LEFT);
11176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  right_swipe_gestures_[1] = BindShiftSearchKeyEvent(ui::VKEY_RIGHT);
11186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  up_swipe_gestures_[1] = BindShiftSearchKeyEvent(ui::VKEY_UP);
11196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  down_swipe_gestures_[1] = BindShiftSearchKeyEvent(ui::VKEY_DOWN);
11206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
11216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Gestures with two fingers.
11226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  left_swipe_gestures_[2] =
11236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      BindKeyEventWithFlags(ui::VKEY_BROWSER_BACK, ui::EF_NONE);
11246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  right_swipe_gestures_[2] =
11256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      BindKeyEventWithFlags(ui::VKEY_BROWSER_FORWARD, ui::EF_NONE);
11266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Jump to top.
11276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  up_swipe_gestures_[2] = BindShiftSearchKeyEvent(ui::VKEY_A);
11286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Read from here.
11296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  down_swipe_gestures_[2] = BindShiftSearchKeyEvent(ui::VKEY_R);
11306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
11316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Gestures with three fingers switch tabs left/right and scroll up/down.
11326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  left_swipe_gestures_[3] = BindKeyEventWithFlags(
11336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      ui::VKEY_TAB, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
11346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  right_swipe_gestures_[3] =
11356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      BindKeyEventWithFlags(ui::VKEY_TAB, ui::EF_CONTROL_DOWN);
11366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  up_swipe_gestures_[3] = BindKeyEventWithFlags(ui::VKEY_NEXT, ui::EF_NONE);
11376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  down_swipe_gestures_[3] = BindKeyEventWithFlags(ui::VKEY_PRIOR, ui::EF_NONE);
11386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
11396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Gestures with four fingers should probably eventually be used for rare
11406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // needs that are hard to access through menus.
11416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Note that brightness levels are here because they can be important for low
11426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // vision users. However, none of these mappings are permanent.
11436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  left_swipe_gestures_[4] =
11446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      BindKeyEventWithFlags(ui::VKEY_BRIGHTNESS_DOWN, ui::EF_NONE);
11456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  right_swipe_gestures_[4] =
11466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      BindKeyEventWithFlags(VKEY_BRIGHTNESS_UP, ui::EF_NONE);
11476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  up_swipe_gestures_[4] = BindKeyEventWithFlags(VKEY_BROWSER_HOME, ui::EF_NONE);
11486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  down_swipe_gestures_[4] =
11496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      BindKeyEventWithFlags(VKEY_BROWSER_REFRESH, ui::EF_NONE);
11506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
11516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
11526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const float TouchExplorationController::GetSplitTapTouchSlop() {
11536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return gesture_detector_config_.touch_slop * 3;
11546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
11556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1156010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}  // namespace ui
1157