1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_
6#define UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_
7
8#include "base/timer/timer.h"
9#include "base/values.h"
10#include "ui/chromeos/ui_chromeos_export.h"
11#include "ui/events/event.h"
12#include "ui/events/event_rewriter.h"
13#include "ui/events/gesture_detection/gesture_detector.h"
14#include "ui/gfx/geometry/point.h"
15
16namespace aura {
17class Window;
18}
19
20namespace ui {
21
22class Event;
23class EventHandler;
24class TouchEvent;
25
26// TouchExplorationController is used in tandem with "Spoken Feedback" to
27// make the touch UI accessible.
28//
29// ** Short version **
30//
31// At a high-level, single-finger events are used for accessibility -
32// exploring the screen gets turned into mouse moves (which can then be
33// spoken by an accessibility service running), a double-tap simulates a
34// click, and gestures can be used to send high-level accessibility commands.
35// When two or more fingers are pressed initially, from then on the events
36// are passed through, but with the initial finger removed - so if you swipe
37// down with two fingers, the running app will see a one-finger swipe.
38//
39// ** Long version **
40//
41// Here are the details of the implementation:
42//
43// When the first touch is pressed, a 300 ms grace period timer starts.
44//
45// If the user keeps their finger down for more than 300 ms and doesn't
46// perform a supported accessibility gesture in that time (e.g. swipe right),
47// they enter touch exploration mode, and all movements are translated into
48// synthesized mouse move events.
49//
50// Also, if the user moves their single finger outside a certain slop region
51// (without performing a gesture), they enter touch exploration mode earlier
52// than 300 ms.
53//
54// If the user taps and releases their finger, after 300 ms from the initial
55// touch, a single mouse move is fired.
56//
57// If the user double-taps, the second tap is passed through, allowing the
58// user to click - however, the double-tap location is changed to the location
59// of the last successful touch exploration - that allows the user to explore
60// anywhere on the screen, hear its description, then double-tap anywhere
61// to activate it.
62//
63// If the user enters touch exploration mode, they can click without lifting
64// their touch exploration finger by tapping anywhere else on the screen with
65// a second finger, while the touch exploration finger is still pressed.
66//
67// If the user adds a second finger during the grace period, they enter
68// passthrough mode. In this mode, the first finger is ignored but all
69// additional touch events are mostly passed through unmodified. So a
70// two-finger scroll gets passed through as a one-finger scroll. However,
71// once in passthrough mode, if one finger is released, the remaining fingers
72// continue to pass through events, allowing the user to start a scroll
73// with two fingers but finish it with one. Sometimes this requires rewriting
74// the touch ids.
75//
76// Once either touch exploration or passthrough mode has been activated,
77// it remains in that mode until all fingers have been released.
78//
79// The caller is expected to retain ownership of instances of this class and
80// destroy them before |root_window| is destroyed.
81class UI_CHROMEOS_EXPORT TouchExplorationController :
82    public ui::EventRewriter {
83 public:
84  explicit TouchExplorationController(aura::Window* root_window);
85  virtual ~TouchExplorationController();
86
87  void CallTapTimerNowForTesting();
88  void SetEventHandlerForTesting(ui::EventHandler* event_handler_for_testing);
89  bool IsInNoFingersDownStateForTesting() const;
90
91 private:
92  // Overridden from ui::EventRewriter
93  virtual ui::EventRewriteStatus RewriteEvent(
94      const ui::Event& event,
95      scoped_ptr<ui::Event>* rewritten_event) OVERRIDE;
96  virtual ui::EventRewriteStatus NextDispatchEvent(
97      const ui::Event& last_event, scoped_ptr<ui::Event>* new_event) OVERRIDE;
98
99  // Event handlers based on the current state - see State, below.
100  ui::EventRewriteStatus InNoFingersDown(
101      const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
102  ui::EventRewriteStatus InSingleTapPressed(
103      const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
104  ui::EventRewriteStatus InSingleTapReleased(
105      const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
106  ui::EventRewriteStatus InDoubleTapPressed(
107      const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
108  ui::EventRewriteStatus InTouchExploration(
109      const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
110  ui::EventRewriteStatus InPassthroughMinusOne(
111      const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
112  ui::EventRewriteStatus InTouchExploreSecondPress(
113      const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
114  // This timer is started every time we get the first press event, and
115  // it fires after the double-click timeout elapses (300 ms by default).
116  // If the user taps and releases within 300 ms and doesn't press again,
117  // we treat that as a single mouse move (touch exploration) event.
118  void OnTapTimerFired();
119
120  // Dispatch a new event outside of the event rewriting flow.
121  void DispatchEvent(ui::Event* event);
122
123  scoped_ptr<ui::Event> CreateMouseMoveEvent(const gfx::PointF& location,
124                                             int flags);
125
126  void EnterTouchToMouseMode();
127
128  // Set the state to NO_FINGERS_DOWN and reset any other fields to their
129  // default value.
130  void ResetToNoFingersDown();
131
132  enum State {
133    // No fingers are down and no events are pending.
134    NO_FINGERS_DOWN,
135
136    // A single finger is down, but we're not yet sure if this is going
137    // to be touch exploration or something else.
138    SINGLE_TAP_PRESSED,
139
140    // The user pressed and released a single finger - a tap - but we have
141    // to wait until the end of the grace period to allow the user to tap the
142    // second time. If the second tap doesn't occurs within the grace period,
143    // we dispatch a mouse move at the location of the first tap.
144    SINGLE_TAP_RELEASED,
145
146    // The user tapped once, and before the grace period expired, pressed
147    // one finger down to begin a double-tap, but has not released it yet.
148    DOUBLE_TAP_PRESSED,
149
150    // We're in touch exploration mode. Anything other than the first finger
151    // is ignored, and movements of the first finger are rewritten as mouse
152    // move events. This mode is entered if a single finger is pressed and
153    // after the grace period the user hasn't added a second finger or
154    // moved the finger outside of the slop region. We'll stay in this
155    // mode until all fingers are lifted.
156    TOUCH_EXPLORATION,
157
158    // The user placed two or more fingers down within the grace period.
159    // We're now in passthrough mode until all fingers are lifted. Initially
160    // the first finger is ignored and other fingers are passed through
161    // as-is. If a finger other than the initial one is the first to be
162    // released, we rewrite the first finger with the touch id of the finger
163    // that was released, from now on. The motivation for this is that if
164    // the user starts a scroll with 2 fingers, they can release either one
165    // and continue the scrolling.
166    PASSTHROUGH_MINUS_ONE,
167
168    // The user was in touch exploration, but has placed down another finger.
169    // If the user releases the second finger, a touch press and release
170    // will go through at the last touch explore location. If the user
171    // releases the touch explore finger, the other finger will continue with
172    // touch explore. Any fingers pressed past the first two are ignored.
173    TOUCH_EXPLORE_SECOND_PRESS,
174  };
175
176  void VlogState(const char* function_name);
177
178  void VlogEvent(const ui::TouchEvent& event, const char* function_name);
179
180  // Gets enum name from integer value.
181  const char* EnumStateToString(State state);
182
183  std::string EnumEventTypeToString(ui::EventType type);
184
185  aura::Window* root_window_;
186
187  // A set of touch ids for fingers currently touching the screen.
188  std::vector<int> current_touch_ids_;
189
190  // Map of touch ids to their last known location.
191  std::map<int, gfx::PointF> touch_locations_;
192
193  // The touch id that any events on the initial finger should be rewritten
194  // as in passthrough-minus-one mode. If kTouchIdUnassigned, events on the
195  // initial finger are discarded. If kTouchIdNone, the initial finger
196  // has been released and no more rewriting will be done.
197  int initial_touch_id_passthrough_mapping_;
198
199  // The current state.
200  State state_;
201
202  // A copy of the event from the initial touch press.
203  scoped_ptr<ui::TouchEvent> initial_press_;
204
205  // The last synthesized mouse move event. When the user double-taps,
206  // we send the passed-through tap to the location of this event.
207  scoped_ptr<ui::TouchEvent> last_touch_exploration_;
208
209  // A timer to fire the mouse move event after the double-tap delay.
210  base::OneShotTimer<TouchExplorationController> tap_timer_;
211
212  // For testing only, an event handler to use for generated events
213  // outside of the normal event rewriting flow.
214  ui::EventHandler* event_handler_for_testing_;
215
216  // A default gesture detector config, so we can share the same
217  // timeout and pixel slop constants.
218  ui::GestureDetector::Config gesture_detector_config_;
219
220  // The previous state entered.
221  State prev_state_;
222
223  // A copy of the previous event passed.
224  scoped_ptr<ui::TouchEvent> prev_event_;
225
226  DISALLOW_COPY_AND_ASSIGN(TouchExplorationController);
227};
228
229}  // namespace ui
230
231#endif  // UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_
232