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

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

Issue 296403011: Support double-tap to click in touch accessibility controller. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address more feedback Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
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/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"
James Cook 2014/06/05 18:04:42 Could this be forward declared?
dmazzoni 2014/06/05 23:32:25 Done.
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 // ** Short version **
25 // moves. This is the "Touch Exploration Mode". (The idea is that mouse moves 29 //
26 // will be subsequently used by another component to move focus between UI 30 // At a high-level, single-finger events are used for accessibility -
27 // elements, and the elements will be read out to the user.) 31 // exploring the screen gets turned into mouse moves (which can then be
28 // - When more than one finger is touching the screen, touches from the 32 // spoken by an accessibility service running), a double-tap simulates a
29 // first (i.e. "oldest") finger are ignored, and the other touches go through 33 // click, and gestures can be used to send high-level accessibility commands.
30 // as is. 34 // When two or more fingers are pressed initially, from then on the events
35 // are passed through, but with the initial finger removed - so if you swipe
36 // down with two fingers, the running app will see a one-finger swipe.
37 //
38 // ** Long version **
39 //
40 // Here are the details of the implementation:
41 //
42 // When the first touch is pressed, a 300 ms grace period timer starts.
43 //
44 // If the user keeps their finger down for more than 300 ms and doesn't
45 // perform a supported accessibility gesture in that time, they enter
James Cook 2014/06/05 18:04:41 nit: Does "supported accessibility gesture" mean d
dmazzoni 2014/06/05 23:32:25 This is supposed to mean a "gesture", like swipe.
46 // touch exploration mode, and all movements are translated into synthesized
47 // mouse move events.
48 //
49 // Also, if the user moves their single finger outside a certain slop region
50 // (without performing a gesture), they enter touch exploration mode earlier
51 // than 300 ms.
52 //
53 // If the user taps and releases their finger, after 300 ms from the initial
54 // touch, a single mouse move is fired.
55 //
56 // If the user double-taps, the second tap is passed through, allowing the
57 // user to click - however, the double-tap location is changed to the location
58 // of the last successful touch exploration - that allows the user to explore
59 // anywhere on the screen, hear its description, then double-tap anywhere
60 // to activate it.
61 //
62 // If the user adds a second finger during the grace period, they enter
63 // passthrough mode. In this mode, the first finger is ignored but all
64 // additional touch events are mostly passed through unmodified. So a
65 // two-finger scroll gets passed through as a one-finger scroll. However,
66 // once in passthrough mode, if one finger is released, the remaining fingers
67 // continue to pass through events, allowing the user to start a scroll
68 // with two fingers but finish it with one. Sometimes this requires rewriting
69 // the touch ids.
70 //
71 // Once either touch exploration or passthrough mode has been activated,
72 // it remains in that mode until all fingers have been released.
James Cook 2014/06/05 18:04:42 Nice explanation of how the feature works.
73 //
31 // The caller is expected to retain ownership of instances of this class and 74 // The caller is expected to retain ownership of instances of this class and
32 // destroy them before |root_window| is destroyed. 75 // destroy them before |root_window| is destroyed.
33 class UI_CHROMEOS_EXPORT TouchExplorationController : 76 class UI_CHROMEOS_EXPORT TouchExplorationController :
34 public ui::EventRewriter { 77 public ui::EventRewriter {
35 public: 78 public:
36 explicit TouchExplorationController(aura::Window* root_window); 79 explicit TouchExplorationController(aura::Window* root_window);
37 virtual ~TouchExplorationController(); 80 virtual ~TouchExplorationController();
38 81
82 void CallTapTimerNowForTesting();
83 void SetEventHandlerForTesting(ui::EventHandler* event_handler_for_testing);
84
39 private: 85 private:
40 scoped_ptr<ui::Event> CreateMouseMoveEvent(const gfx::PointF& location,
41 int flags);
42
43 void EnterTouchToMouseMode();
44
45 // Overridden from ui::EventRewriter 86 // Overridden from ui::EventRewriter
46 virtual ui::EventRewriteStatus RewriteEvent( 87 virtual ui::EventRewriteStatus RewriteEvent(
47 const ui::Event& event, scoped_ptr<ui::Event>* rewritten_event) OVERRIDE; 88 const ui::Event& event, scoped_ptr<ui::Event>* rewritten_event) OVERRIDE;
48 virtual ui::EventRewriteStatus NextDispatchEvent( 89 virtual ui::EventRewriteStatus NextDispatchEvent(
49 const ui::Event& last_event, scoped_ptr<ui::Event>* new_event) OVERRIDE; 90 const ui::Event& last_event, scoped_ptr<ui::Event>* new_event) OVERRIDE;
50 91
92 // Event handlers based on the current state - see State, below.
93 ui::EventRewriteStatus OnNoFingersDown(
94 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
95 ui::EventRewriteStatus OnSingleTapPressed(
96 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
97 ui::EventRewriteStatus OnSingleTapReleased(
98 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
99 ui::EventRewriteStatus OnDoubleTapPressed(
100 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
101 ui::EventRewriteStatus OnTouchExploration(
102 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
103 ui::EventRewriteStatus OnPassthroughMinusOne(
104 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
105
106 // This timer is started every time we get the first press event, and
107 // it fires after the double-click timeout elapses (300 ms by default).
108 // If the user taps and releases within 300 ms and doesn't press again,
109 // we treat that as a single mouse move (touch exploration) event.
110 void OnTapTimerFired();
111
112 // Dispatch a new event outside of the event rewriting flow.
113 void DispatchEvent(ui::Event* event);
114
115 scoped_ptr<ui::Event> CreateMouseMoveEvent(const gfx::PointF& location,
116 int flags);
117
118 void EnterTouchToMouseMode();
119
120 // Set the state to NO_FINGERS_DOWN and reset any other fields to their
121 // default value.
122 void ResetToNoFingersDown();
123
124 enum State {
125 // No fingers are down and no events are pending.
126 NO_FINGERS_DOWN,
127
128 // A single finger is down, but we're not yet sure if this is going
129 // to be touch exploration or something else.
130 SINGLE_TAP_PRESSED,
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 to allow the user to tap the
134 // second time. If the second tap doesn't occus within the grace period,
James Cook 2014/06/05 18:04:42 nit: occus -> occur
dmazzoni 2014/06/05 23:32:25 Done.
135 // we dispatch a mouse move at the location of the first tap.
136 SINGLE_TAP_RELEASED,
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 // We're in touch exploration mode. Anything other than the first finger
143 // is ignored, and movements of the first finger are rewritten as mouse
144 // move events. This mode is entered if a single finger is pressed and
145 // after the grace period the user hasn't added a second finger or
146 // moved the finger outside of the slop region. We'll stay in this
147 // mode until all fingers are lifted.
148 TOUCH_EXPLORATION,
James Cook 2014/06/05 18:04:41 Question: Can you get into a state where the devic
dmazzoni 2014/06/05 23:32:25 That's a good question. Turning spoken feedback of
149
150 // The user placed two or more fingers down within the grace period.
151 // We're now in passthrough mode until all fingers are lifted. Initially
152 // the first finger is ignored and other fingers are passed through
153 // as-is. If a finger other than the initial one is the first to be
154 // released, we rewrite the first finger with the touch id of the finger
155 // that was released, from now on. The motivation for this is that if
156 // the user starts a scroll with 2 fingers, they can release either one
157 // and continue the scrolling.
158 PASSTHROUGH_MINUS_ONE,
159 };
James Cook 2014/06/05 18:04:41 Again, nice description - very thorough.
160
161 aura::Window* root_window_;
162
51 // A set of touch ids for fingers currently touching the screen. 163 // A set of touch ids for fingers currently touching the screen.
52 std::vector<int> touch_ids_; 164 std::vector<int> current_touch_ids_;
53 165
54 // Map of touch ids to their last known location. 166 // Map of touch ids to their last known location.
55 std::map<int, gfx::PointF> touch_locations_; 167 std::map<int, gfx::PointF> touch_locations_;
56 168
57 // Initialized from RewriteEvent() and dispatched in NextDispatchEvent(). 169 // The touch id that any events on the initial finger should be rewritten
58 scoped_ptr<ui::Event> next_dispatch_event_; 170 // as in passthrough-minus-one mode. If 0, events on the initial finger are
171 // discarded. If -1, the initial finger has been released and no more
172 // rewriting will be done.
173 int initial_touch_id_passthrough_mapping_;
59 174
60 aura::Window* root_window_; 175 // The current state.
176 State state_;
177
178 // A copy of the event from the initial touch press.
179 scoped_ptr<ui::TouchEvent> initial_press_;
180
181 // The last location where we synthesized a mouse move event.
182 // When the user double-taps, we send the passed-through tap here.
183 gfx::PointF last_touch_exploration_location_;
184
185 // A timer to fire the mouse move event after the double-tap delay.
186 base::OneShotTimer<TouchExplorationController> tap_timer_;
187
188 // For testing only, an event handler to use for generated events
189 // outside of the normal event rewriting flow.
190 ui::EventHandler* event_handler_for_testing_;
191
192 // A default gesture detector config, so we can share the same
193 // timeout and pixel slop constants.
194 ui::GestureDetector::Config gesture_detector_config_;
61 195
62 DISALLOW_COPY_AND_ASSIGN(TouchExplorationController); 196 DISALLOW_COPY_AND_ASSIGN(TouchExplorationController);
63 }; 197 };
64 198
65 } // namespace ui 199 } // namespace ui
66 200
67 #endif // UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_ 201 #endif // UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698