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

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

Issue 385073009: Side Slide Gestures for Accessibility (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed Comments Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #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/timer/timer.h"
9 #include "base/values.h" 9 #include "base/values.h"
10 #include "ui/chromeos/ui_chromeos_export.h" 10 #include "ui/chromeos/ui_chromeos_export.h"
11 #include "ui/events/event.h" 11 #include "ui/events/event.h"
12 #include "ui/events/event_rewriter.h" 12 #include "ui/events/event_rewriter.h"
13 #include "ui/events/gesture_detection/gesture_detector.h" 13 #include "ui/events/gesture_detection/gesture_detector.h"
14 #include "ui/events/gestures/gesture_provider_aura.h" 14 #include "ui/events/gestures/gesture_provider_aura.h"
15 #include "ui/gfx/geometry/point.h" 15 #include "ui/gfx/geometry/point.h"
16 16
17 namespace aura { 17 namespace aura {
18 class Window; 18 class Window;
19 } 19 }
20 20
21 namespace ui { 21 namespace ui {
22 22
23 class Event; 23 class Event;
24 class EventHandler; 24 class EventHandler;
25 class GestureEvent; 25 class GestureEvent;
26 class GestureProviderAura; 26 class GestureProviderAura;
27 class TouchEvent; 27 class TouchEvent;
28 28
29 // A delegate to handle commands in response to detected accessibility gesture
30 // events.
31 class TouchExplorationControllerDelegate {
32 public:
33 virtual ~TouchExplorationControllerDelegate() {}
34
35 // This function should be called whenever the delegate wants to play a sound
36 // when the volume adjusts.
37 virtual void PlayVolumeAdjustSound() = 0;
38
39 // Takes an int from 0.0 to 100.0 that indicates the percent the volume
40 // should be set to.
41 virtual void SetOutputLevel(int volume) = 0;
42 };
43
29 // TouchExplorationController is used in tandem with "Spoken Feedback" to 44 // TouchExplorationController is used in tandem with "Spoken Feedback" to
30 // make the touch UI accessible. Gestures are mapped to accessiblity key 45 // make the touch UI accessible. Gestures performed in the middle of the screen
31 // shortcuts. 46 // are mapped to accessiblity key shortcuts while gestures performed on the edge
47 // of the screen can change settings.
32 // 48 //
33 // ** Short version ** 49 // ** Short version **
34 // 50 //
35 // At a high-level, single-finger events are used for accessibility - 51 // At a high-level, single-finger events are used for accessibility -
36 // exploring the screen gets turned into mouse moves (which can then be 52 // exploring the screen gets turned into mouse moves (which can then be
37 // spoken by an accessibility service running), a single tap while the user 53 // spoken by an accessibility service running), a single tap while the user
38 // is in touch exploration or a double-tap simulates a click, and gestures 54 // is in touch exploration or a double-tap simulates a click, and gestures
39 // can be used to send high-level accessibility commands. For example, a swipe 55 // can be used to send high-level accessibility commands. For example, a swipe
40 // right would correspond to the keyboard short cut shift+search+right. 56 // right would correspond to the keyboard short cut shift+search+right.
41 // When two or more fingers are pressed initially, from then on the events 57 // When two or more fingers are pressed initially, from then on the events
42 // are passed through, but with the initial finger removed - so if you swipe 58 // are passed through, but with the initial finger removed - so if you swipe
43 // down with two fingers, the running app will see a one-finger swipe. 59 // down with two fingers, the running app will see a one-finger swipe. Slide
60 // gestures performed on the edge of the screen can change settings
61 // continuously. For example, sliding a finger along the right side of the
62 // screen will change the volume.
44 // 63 //
45 // ** Long version ** 64 // ** Long version **
46 // 65 //
47 // Here are the details of the implementation: 66 // Here are the details of the implementation:
48 // 67 //
49 // When the first touch is pressed, a 300 ms grace period timer starts. 68 // When the first touch is pressed, a 300 ms grace period timer starts.
50 // 69 //
51 // If the user keeps their finger down for more than 300 ms and doesn't 70 // If the user keeps their finger down for more than 300 ms and doesn't
52 // perform a supported accessibility gesture in that time (e.g. swipe right), 71 // perform a supported accessibility gesture in that time (e.g. swipe right),
53 // they enter touch exploration mode, and all movements are translated into 72 // they enter touch exploration mode, and all movements are translated into
(...skipping 30 matching lines...) Expand all
84 // their touch exploration finger by tapping anywhere else on the screen with 103 // their touch exploration finger by tapping anywhere else on the screen with
85 // a second finger, while the touch exploration finger is still pressed. 104 // a second finger, while the touch exploration finger is still pressed.
86 // 105 //
87 // If the user adds a second finger during the grace period, they enter 106 // If the user adds a second finger during the grace period, they enter
88 // two to one finger passthrough mode. In this mode, the first finger is 107 // two to one finger passthrough mode. In this mode, the first finger is
89 // ignored and the user can scroll or drag with the second finger. If either 108 // ignored and the user can scroll or drag with the second finger. If either
90 // finger is released, nothing happens until all fingers are up. If the user 109 // finger is released, nothing happens until all fingers are up. If the user
91 // adds a third finger while in two to one finger mode, all fingers and touch 110 // adds a third finger while in two to one finger mode, all fingers and touch
92 // events are passed through from then on. 111 // events are passed through from then on.
93 // 112 //
113 // If the user places a finger on the edge of the screen and moves their finger
114 // past slop, a slide gesture is performed. The user can then slide one finger
115 // along an edge of the screen and continuously control a setting. Once the user
116 // enters this state, the boundaries that define an edge expand so that the user
117 // can now adjust the setting within a slightly bigger width along the screen.
118 // If the user exits this area without lifting their finger, they will not be
119 // able to perform any actions, however if they keep their finger down and
120 // return to the "hot edge," then they can still adjust the setting. In order to
121 // perform other touch accessibility movements, the user must lift their finger.
122 // If additional fingers are added while in this state, the user will transition
123 // to passthrough.
124 //
125 // Currently, only the right edge is mapped to control the volume. Volume
126 // control along the edge of the screen is directly proportional to where the
127 // user's finger is located on the screen. The top right corner of the screen
128 // automatically sets the volume to 100% and the bottome right corner of the
129 // screen automatically sets the volume to 0% once the user has moved past slop.
130 //
94 // Once touch exploration mode has been activated, 131 // Once touch exploration mode has been activated,
95 // it remains in that mode until all fingers have been released. 132 // it remains in that mode until all fingers have been released.
96 // 133 //
97 // The caller is expected to retain ownership of instances of this class and 134 // The caller is expected to retain ownership of instances of this class and
98 // destroy them before |root_window| is destroyed. 135 // destroy them before |root_window| is destroyed.
99 class UI_CHROMEOS_EXPORT TouchExplorationController 136 class UI_CHROMEOS_EXPORT TouchExplorationController
100 : public ui::EventRewriter, 137 : public ui::EventRewriter,
101 public ui::GestureProviderAuraClient { 138 public ui::GestureProviderAuraClient {
102 public: 139 public:
103 explicit TouchExplorationController(aura::Window* root_window); 140 explicit TouchExplorationController(
141 aura::Window* root_window,
142 ui::TouchExplorationControllerDelegate* delegate);
104 virtual ~TouchExplorationController(); 143 virtual ~TouchExplorationController();
105 144
106 private: 145 private:
107 friend class TouchExplorationControllerTestApi; 146 friend class TouchExplorationControllerTestApi;
108 147
109 // Overridden from ui::EventRewriter 148 // Overridden from ui::EventRewriter
110 virtual ui::EventRewriteStatus RewriteEvent( 149 virtual ui::EventRewriteStatus RewriteEvent(
111 const ui::Event& event, 150 const ui::Event& event,
112 scoped_ptr<ui::Event>* rewritten_event) OVERRIDE; 151 scoped_ptr<ui::Event>* rewritten_event) OVERRIDE;
113 virtual ui::EventRewriteStatus NextDispatchEvent( 152 virtual ui::EventRewriteStatus NextDispatchEvent(
(...skipping 13 matching lines...) Expand all
127 ui::EventRewriteStatus InTwoToOneFinger( 166 ui::EventRewriteStatus InTwoToOneFinger(
128 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event); 167 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
129 ui::EventRewriteStatus InPassthrough( 168 ui::EventRewriteStatus InPassthrough(
130 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event); 169 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
131 ui::EventRewriteStatus InGestureInProgress( 170 ui::EventRewriteStatus InGestureInProgress(
132 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event); 171 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
133 ui::EventRewriteStatus InTouchExploreSecondPress( 172 ui::EventRewriteStatus InTouchExploreSecondPress(
134 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event); 173 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
135 ui::EventRewriteStatus InWaitForRelease( 174 ui::EventRewriteStatus InWaitForRelease(
136 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event); 175 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
176 ui::EventRewriteStatus InSlideGesture(
177 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
137 178
138 // This timer is started every time we get the first press event, and 179 // This timer is started every time we get the first press event, and
139 // it fires after the double-click timeout elapses (300 ms by default). 180 // it fires after the double-click timeout elapses (300 ms by default).
140 // If the user taps and releases within 300 ms and doesn't press again, 181 // If the user taps and releases within 300 ms and doesn't press again,
141 // we treat that as a single mouse move (touch exploration) event. 182 // we treat that as a single mouse move (touch exploration) event.
142 void OnTapTimerFired(); 183 void OnTapTimerFired();
143 184
144 // Dispatch a new event outside of the event rewriting flow. 185 // Dispatch a new event outside of the event rewriting flow.
145 void DispatchEvent(ui::Event* event); 186 void DispatchEvent(ui::Event* event);
146 187
147 // Overridden from GestureProviderAuraClient. 188 // Overridden from GestureProviderAuraClient.
148 // 189 //
149 // The gesture provider keeps track of all the touch events after 190 // The gesture provider keeps track of all the touch events after
150 // the user moves fast enough to trigger a gesture. After the user 191 // the user moves fast enough to trigger a gesture. After the user
151 // completes their gesture, this method will decide what keyboard 192 // completes their gesture, this method will decide what keyboard
152 // input their gesture corresponded to. 193 // input their gesture corresponded to.
153 virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE; 194 virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE;
154 195
155 // Process the gesture events that have been created. 196 // Process the gesture events that have been created.
156 void ProcessGestureEvents(); 197 void ProcessGestureEvents();
157 198
158 void OnSwipeEvent(ui::GestureEvent* swipe_gesture); 199 void OnSwipeEvent(ui::GestureEvent* swipe_gesture);
159 200
201 void SideSlideControl(ui::GestureEvent* gesture);
202
160 // Dispatches the keyboard short cut Shift+Search+<arrow key> 203 // Dispatches the keyboard short cut Shift+Search+<arrow key>
161 // outside the event rewritting flow. 204 // outside the event rewritting flow.
162 void DispatchShiftSearchKeyEvent(const ui::KeyboardCode direction); 205 void DispatchShiftSearchKeyEvent(const ui::KeyboardCode direction);
163 206
164 scoped_ptr<ui::Event> CreateMouseMoveEvent(const gfx::PointF& location, 207 scoped_ptr<ui::Event> CreateMouseMoveEvent(const gfx::PointF& location,
165 int flags); 208 int flags);
166 209
167 void EnterTouchToMouseMode(); 210 void EnterTouchToMouseMode();
168 211
169 // Set the state to NO_FINGERS_DOWN and reset any other fields to their 212 // Set the state to NO_FINGERS_DOWN and reset any other fields to their
170 // default value. 213 // default value.
171 void ResetToNoFingersDown(); 214 void ResetToNoFingersDown();
172 215
216 void PlaySoundForTimer();
217
218 // Some constants used in touch_exploration_controller:
219
220 // Within this many dips of the screen edge, the release event generated will
221 // reset the state to NoFingersDown.
222 const float kLeavingScreenEdge = 6;
223 // Swipe/scroll gestures within these bounds (in dips) will change preset
dmazzoni 2014/07/22 18:15:33 Nit: newline before this.
aboxhall 2014/07/22 18:16:47 nit: s/dips/DIPs/
lisayin 2014/07/22 18:26:51 Done.
224 // settings.
225 const float kMaxDistanceFromEdge = 75;
226
227 // After a slide gesture has been triggered, if the finger is still within
228 // these bounds (in DIPs), the preset settings will still change.
229 const float kSlopDistanceFromEdge = kMaxDistanceFromEdge + 40;
230
173 enum State { 231 enum State {
174 // No fingers are down and no events are pending. 232 // No fingers are down and no events are pending.
175 NO_FINGERS_DOWN, 233 NO_FINGERS_DOWN,
176 234
177 // A single finger is down, but we're not yet sure if this is going 235 // A single finger is down, but we're not yet sure if this is going
178 // to be touch exploration or something else. 236 // to be touch exploration or something else.
179 SINGLE_TAP_PRESSED, 237 SINGLE_TAP_PRESSED,
180 238
181 // The user pressed and released a single finger - a tap - but we have 239 // The user pressed and released a single finger - a tap - but we have
182 // to wait until the end of the grace period to allow the user to tap the 240 // to wait until the end of the grace period to allow the user to tap the
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 // If the user is in TWO_TO_ONE_FINGER with two fingers down and presses 287 // If the user is in TWO_TO_ONE_FINGER with two fingers down and presses
230 // a third finger, every finger and touch event is passed through until 288 // a third finger, every finger and touch event is passed through until
231 // all fingers are released. 289 // all fingers are released.
232 PASSTHROUGH, 290 PASSTHROUGH,
233 291
234 // If the user lifted a finger in TWO_TO_ONE_FINGER, they must release 292 // If the user lifted a finger in TWO_TO_ONE_FINGER, they must release
235 // all fingers before completing any more actions. This state is 293 // all fingers before completing any more actions. This state is
236 // generally useful for developing new features, because it creates a 294 // generally useful for developing new features, because it creates a
237 // simple way to handle a dead end in user flow. 295 // simple way to handle a dead end in user flow.
238 WAIT_FOR_RELEASE, 296 WAIT_FOR_RELEASE,
297
298 // If the user is within the given bounds from an edge of the screen, not
299 // including corners, then the resulting movements will be interpreted as
300 // slide gestures.
301 SLIDE_GESTURE,
239 }; 302 };
240 303
304 enum ScreenLocation {
305 // Hot "edges" of the screen are each represented by a respective bit.
306 NO_EDGE = 0,
307 RIGHT_EDGE = 1 << 0,
308 TOP_EDGE = 1 << 1,
309 LEFT_EDGE = 1 << 2,
310 BOTTOM_EDGE = 1 << 3,
311 };
312
313 // Given a point, if it is within the given bounds of an edge, returns the
314 // edge. If it is within the given bounds of two edges, returns an int with
315 // both bits that represent the respective edges turned on. Otherwise returns
316 // SCREEN_CENTER.
317 int FindEdgesWithinBounds(gfx::Point point, float bounds);
318
241 void VlogState(const char* function_name); 319 void VlogState(const char* function_name);
242 320
243 void VlogEvent(const ui::TouchEvent& event, const char* function_name); 321 void VlogEvent(const ui::TouchEvent& event, const char* function_name);
244 322
245 // Gets enum name from integer value. 323 // Gets enum name from integer value.
246 const char* EnumStateToString(State state); 324 const char* EnumStateToString(State state);
247 325
248 aura::Window* root_window_; 326 aura::Window* root_window_;
249 327
328 // Handles volume control. Not owned.
329 ui::TouchExplorationControllerDelegate* delegate_;
330
250 // A set of touch ids for fingers currently touching the screen. 331 // A set of touch ids for fingers currently touching the screen.
251 std::vector<int> current_touch_ids_; 332 std::vector<int> current_touch_ids_;
252 333
253 // Map of touch ids to their last known location. 334 // Map of touch ids to their last known location.
254 std::map<int, gfx::PointF> touch_locations_; 335 std::map<int, gfx::PointF> touch_locations_;
255 336
256 // The current state. 337 // The current state.
257 State state_; 338 State state_;
258 339
259 // A copy of the event from the initial touch press. 340 // A copy of the event from the initial touch press.
260 scoped_ptr<ui::TouchEvent> initial_press_; 341 scoped_ptr<ui::TouchEvent> initial_press_;
261 342
262 // Stores the most recent event from a finger that is currently not 343 // Stores the most recent event from a finger that is currently not
263 // sending events through, but might in the future (e.g. TwoToOneFinger 344 // sending events through, but might in the future (e.g. TwoToOneFinger
264 // to Passthrough state). 345 // to Passthrough state).
265 scoped_ptr<ui::TouchEvent> last_unused_finger_event_; 346 scoped_ptr<ui::TouchEvent> last_unused_finger_event_;
266 347
267 // The last synthesized mouse move event. When the user double-taps, 348 // The last synthesized mouse move event. When the user double-taps,
268 // we send the passed-through tap to the location of this event. 349 // we send the passed-through tap to the location of this event.
269 scoped_ptr<ui::TouchEvent> last_touch_exploration_; 350 scoped_ptr<ui::TouchEvent> last_touch_exploration_;
270 351
271 // The last event from the finger that is being passed through in 352 // The last event from the finger that is being passed through in
272 // TWO_TO_ONE_FINGER. When the user lifts a finger during two to one, 353 // TWO_TO_ONE_FINGER. When the user lifts a finger during two to one,
273 // the location and id of the touch release is from here. 354 // the location and id of the touch release is from here.
274 scoped_ptr<ui::TouchEvent> last_two_to_one_; 355 scoped_ptr<ui::TouchEvent> last_two_to_one_;
275 356
276 // A timer to fire the mouse move event after the double-tap delay. 357 // A timer to fire the mouse move event after the double-tap delay.
277 base::OneShotTimer<TouchExplorationController> tap_timer_; 358 base::OneShotTimer<TouchExplorationController> tap_timer_;
278 359
360 // A timer to fire an indicating sound when sliding to change volume.
361 base::RepeatingTimer<TouchExplorationController> sound_timer_;
362
279 // For testing only, an event handler to use for generated events 363 // For testing only, an event handler to use for generated events
280 // outside of the normal event rewriting flow. 364 // outside of the normal event rewriting flow.
281 ui::EventHandler* event_handler_for_testing_; 365 ui::EventHandler* event_handler_for_testing_;
282 366
283 // A default gesture detector config, so we can share the same 367 // A default gesture detector config, so we can share the same
284 // timeout and pixel slop constants. 368 // timeout and pixel slop constants.
285 ui::GestureDetector::Config gesture_detector_config_; 369 ui::GestureDetector::Config gesture_detector_config_;
286 370
287 // Gesture Handler to interpret the touch events. 371 // Gesture Handler to interpret the touch events.
288 ui::GestureProviderAura gesture_provider_; 372 ui::GestureProviderAura gesture_provider_;
289 373
290 // The previous state entered. 374 // The previous state entered.
291 State prev_state_; 375 State prev_state_;
292 376
293 // A copy of the previous event passed. 377 // A copy of the previous event passed.
294 scoped_ptr<ui::TouchEvent> prev_event_; 378 scoped_ptr<ui::TouchEvent> prev_event_;
295 379
296 // This toggles whether VLOGS are turned on or not. 380 // This toggles whether VLOGS are turned on or not.
297 bool VLOG_on_; 381 bool VLOG_on_;
298 382
299 DISALLOW_COPY_AND_ASSIGN(TouchExplorationController); 383 DISALLOW_COPY_AND_ASSIGN(TouchExplorationController);
300 }; 384 };
301 385
302 } // namespace ui 386 } // namespace ui
303 387
304 #endif // UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_ 388 #endif // UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698