OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_ | 5 #ifndef UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_ |
6 #define UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_ | 6 #define UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_ |
7 | 7 |
8 #include "base/timer/timer.h" | |
8 #include "base/values.h" | 9 #include "base/values.h" |
9 #include "ui/chromeos/ui_chromeos_export.h" | 10 #include "ui/chromeos/ui_chromeos_export.h" |
11 #include "ui/events/event_handler.h" | |
10 #include "ui/events/event_rewriter.h" | 12 #include "ui/events/event_rewriter.h" |
13 #include "ui/events/gesture_detection/gesture_detector.h" | |
11 #include "ui/gfx/geometry/point.h" | 14 #include "ui/gfx/geometry/point.h" |
12 | 15 |
13 namespace aura { | 16 namespace aura { |
14 class Window; | 17 class Window; |
15 } | 18 } |
16 | 19 |
17 namespace ui { | 20 namespace ui { |
18 | 21 |
19 class Event; | 22 class Event; |
23 class TouchEvent; | |
20 | 24 |
21 // TouchExplorationController is used in tandem with "Spoken Feedback" to | 25 // TouchExplorationController is used in tandem with "Spoken Feedback" to |
22 // make the touch UI accessible. TouchExplorationController rewrites the | 26 // make the touch UI accessible. |
23 // incoming touch events as follows: | 27 // |
24 // - When one finger is touching the screen, touch events are converted to mouse | 28 // At a high-level, single-finger events are used for accessibility - |
25 // moves. This is the "Touch Exploration Mode". (The idea is that mouse moves | 29 // exploring the screen gets turned into mouse moves (which can then be |
26 // will be subsequently used by another component to move focus between UI | 30 // spoken by an accessibility service running), a double-tap simulates a |
27 // elements, and the elements will be read out to the user.) | 31 // click, and gestures can be used to send high-level accessibility commands. |
28 // - When more than one finger is touching the screen, touches from the | 32 // Whenever two or more fingers are pressed, the events are passed through |
29 // first (i.e. "oldest") finger are ignored, and the other touches go through | 33 // withone finger removed - so if you swipe down with two fingers, the |
30 // as is. | 34 // running app will see a one-finger swipe. |
35 // | |
36 // Here are the details of the implementation: | |
37 // | |
38 // When the first touch is pressed, a 300 ms grace period timer starts. | |
39 // | |
40 // If the user keeps their finger down for more than 300 ms and doesn't | |
41 // perform a gesture in that time, they enter touch exploration mode, and | |
42 // all movements are translated into synthesized mouse move events. | |
43 // | |
44 // Also, if the user moves their single finger outside a certain slop region | |
45 // (without performing a gesture), they enter touch exploration mode earlier | |
46 // than 300 ms. | |
47 // | |
48 // If the user taps and releases their finger, after 300 ms from the initial | |
49 // touch, a single mouse move is fired. | |
50 // | |
51 // If the user double-taps, the second tap is passed through, allowing the | |
52 // user to click - however, the double-tap location is changed to the location | |
53 // of the last successful touch exploration - that allows the user to explore | |
54 // anywhere on the screen, hear its description, then double-tap anywhere | |
55 // to activate it. | |
56 // | |
57 // If the user adds a second finger during the grace period, they enter | |
58 // passthrough mode. In this mode, the first finger is ignored but all | |
59 // additional touch events are mostly passed through unmodified. So a | |
60 // two-finger scroll gets passed through as a one-finger scroll. However, | |
61 // once in passthrough mode, if one finger is released, the remaining finger | |
62 // continues to pass through events, allowing the user to start a scroll | |
63 // with two fingers but finish it with one. Sometimes this requires rewriting | |
64 // the touch ids. | |
65 // | |
66 // Once either touch exploration or passthrough mode has been activated, | |
67 // it remains in that mode until all fingers have been released. | |
68 // | |
31 // The caller is expected to retain ownership of instances of this class and | 69 // The caller is expected to retain ownership of instances of this class and |
32 // destroy them before |root_window| is destroyed. | 70 // destroy them before |root_window| is destroyed. |
33 class UI_CHROMEOS_EXPORT TouchExplorationController : | 71 class UI_CHROMEOS_EXPORT TouchExplorationController : |
34 public ui::EventRewriter { | 72 public ui::EventRewriter { |
35 public: | 73 public: |
36 explicit TouchExplorationController(aura::Window* root_window); | 74 explicit TouchExplorationController(aura::Window* root_window); |
37 virtual ~TouchExplorationController(); | 75 virtual ~TouchExplorationController(); |
38 | 76 |
77 void CallTapTimerNowForTesting(); | |
78 void SetEventHandlerForTesting(ui::EventHandler* event_handler_for_testing); | |
79 | |
39 private: | 80 private: |
40 scoped_ptr<ui::Event> CreateMouseMoveEvent(const gfx::PointF& location, | |
41 int flags); | |
42 | |
43 void EnterTouchToMouseMode(); | |
44 | |
45 // Overridden from ui::EventRewriter | 81 // Overridden from ui::EventRewriter |
46 virtual ui::EventRewriteStatus RewriteEvent( | 82 virtual ui::EventRewriteStatus RewriteEvent( |
47 const ui::Event& event, scoped_ptr<ui::Event>* rewritten_event) OVERRIDE; | 83 const ui::Event& event, scoped_ptr<ui::Event>* rewritten_event) OVERRIDE; |
48 virtual ui::EventRewriteStatus NextDispatchEvent( | 84 virtual ui::EventRewriteStatus NextDispatchEvent( |
49 const ui::Event& last_event, scoped_ptr<ui::Event>* new_event) OVERRIDE; | 85 const ui::Event& last_event, scoped_ptr<ui::Event>* new_event) OVERRIDE; |
50 | 86 |
87 // Event handlers based on the current state - see State, below. | |
88 ui::EventRewriteStatus OnNoFingersDown( | |
89 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event); | |
90 ui::EventRewriteStatus OnGracePeriod( | |
91 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event); | |
92 ui::EventRewriteStatus OnTouchExploration( | |
93 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event); | |
94 ui::EventRewriteStatus OnPassthroughMinusOne( | |
95 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event); | |
96 ui::EventRewriteStatus OnSingleTapPending( | |
97 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event); | |
98 ui::EventRewriteStatus OnDoubleTapPressed( | |
99 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event); | |
100 | |
101 // This timer is started every time we get the first press event, and | |
102 // it fires after the double-click timeout elapses (300 ms by default). | |
103 // If the user taps and releases within 300 ms and doesn't press again, | |
104 // we treat that as a single mouse move (touch exploration) event. | |
105 void OnTapTimerFired(); | |
106 | |
107 // Dispatch a new event outside of the event rewriting flow. | |
108 void DispatchEvent(ui::Event* event); | |
109 | |
110 scoped_ptr<ui::Event> CreateMouseMoveEvent(const gfx::PointF& location, | |
111 int flags); | |
112 | |
113 void EnterTouchToMouseMode(); | |
114 | |
115 // Set the state to NO_FINGERS_DOWN and reset any other fields to their | |
116 // default value. | |
117 void ResetToNoFingersDown(); | |
118 | |
119 enum State { | |
120 // No fingers are down and no events are pending. | |
121 NO_FINGERS_DOWN, | |
122 | |
123 // A single finger is down, but we're not yet sure if this is going | |
124 // to be touch exploration or something else. | |
125 GRACE_PERIOD, | |
126 | |
127 // A single finger is down and after the grace period the user | |
128 // hasn't added a second finger or moved the finger too rapidly. | |
129 // We're now in touch exploration mode until this finger is lifted. | |
130 TOUCH_EXPLORATION, | |
131 | |
132 // The user pressed and released a single finger - a tap - but we have | |
133 // to wait until the end of the grace period before we will rewrite this | |
134 // as touch exploration, in case it's actually the first tap of a mouse | |
135 // move. | |
136 SINGLE_TAP_PENDING, | |
137 | |
138 // The user tapped once, and before the grace period expired, pressed | |
139 // one finger down to begin a double-tap, but has not released it yet. | |
140 DOUBLE_TAP_PRESSED, | |
141 | |
142 // The user placed two or more fingers down within the grace period. | |
143 // We're now in passthrough mode until all fingers are lifted. When | |
144 // two ore more fingers are down, we subtract one finger but otherwise | |
145 // pass through all events unchanged. | |
146 PASSTHROUGH_MINUS_ONE, | |
147 }; | |
148 | |
149 aura::Window* root_window_; | |
150 | |
51 // A set of touch ids for fingers currently touching the screen. | 151 // A set of touch ids for fingers currently touching the screen. |
52 std::vector<int> touch_ids_; | 152 std::vector<int> current_touch_ids_; |
53 | 153 |
54 // Map of touch ids to their last known location. | 154 // Map of touch ids to their last known location. |
55 std::map<int, gfx::PointF> touch_locations_; | 155 std::map<int, gfx::PointF> touch_locations_; |
56 | 156 |
57 // Initialized from RewriteEvent() and dispatched in NextDispatchEvent(). | 157 // The touch id that any events on the initial finger should be rewritten |
58 scoped_ptr<ui::Event> next_dispatch_event_; | 158 // as in passthrough-minus-one mode. If 0, events on the initial finger are |
159 // discarded. | |
mfomitchev
2014/06/04 20:39:30
Nit: Might want to comment here what -1 means.
dmazzoni
2014/06/04 22:46:28
Done.
| |
160 int initial_touch_id_passthrough_mapping_; | |
59 | 161 |
60 aura::Window* root_window_; | 162 // The current state. |
163 State state_; | |
164 | |
165 // A copy of the event from the initial touch press. | |
166 scoped_ptr<ui::TouchEvent> initial_press_; | |
167 | |
168 // The last location where we synthesized a mouse move event. | |
169 // When the user double-taps, we send the passed-through tap here. | |
170 gfx::PointF last_touch_exploration_location_; | |
171 | |
172 // A timer to fire the mouse move event after the double-tap delay. | |
173 base::OneShotTimer<TouchExplorationController> tap_timer_; | |
174 | |
175 // For testing only, an event handler to use for generated events | |
176 // outside of the normal event rewriting flow. | |
177 ui::EventHandler* event_handler_for_testing_; | |
178 | |
179 // A default gesture detector config, so we can share the same | |
180 // timeout and pixel slop constants. | |
181 ui::GestureDetector::Config gesture_detector_config_; | |
61 | 182 |
62 DISALLOW_COPY_AND_ASSIGN(TouchExplorationController); | 183 DISALLOW_COPY_AND_ASSIGN(TouchExplorationController); |
63 }; | 184 }; |
64 | 185 |
65 } // namespace ui | 186 } // namespace ui |
66 | 187 |
67 #endif // UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_ | 188 #endif // UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_ |
OLD | NEW |