• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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 ASH_STICKY_KEYS_STICKY_KEYS_CONTROLLER_H_
6 #define ASH_STICKY_KEYS_STICKY_KEYS_CONTROLLER_H_
7 
8 #include "ash/ash_export.h"
9 #include "ash/sticky_keys/sticky_keys_state.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "ui/events/event_constants.h"
12 #include "ui/events/event_handler.h"
13 #include "ui/events/event_rewriter.h"
14 #include "ui/events/keycodes/keyboard_codes.h"
15 
16 namespace ui {
17 class Event;
18 class KeyEvent;
19 class MouseEvent;
20 }  // namespace ui
21 
22 namespace aura {
23 class Window;
24 }  // namespace aura
25 
26 namespace ash {
27 
28 class StickyKeysOverlay;
29 class StickyKeysHandler;
30 
31 // StickyKeysController is an accessibility feature for users to be able to
32 // compose key and mouse event with modifier keys without simultaneous key
33 // press event. Instead they can compose events separately pressing each of the
34 // modifier keys involved.
35 // e.g. Composing Ctrl + T
36 //       User Action   : The KeyEvent widget will receives
37 // ----------------------------------------------------------
38 // 1. Press Ctrl key   : Ctrl Keydown.
39 // 2. Release Ctrl key : No event
40 // 3. Press T key      : T keydown event with ctrl modifier.
41 // 4.                  : Ctrl Keyup
42 // 5. Release T key    : T keyup without ctrl modifier (Windows behavior)
43 //
44 // By typing same modifier keys twice, users can generate bunch of modified key
45 // events.
46 // e.g. To focus tabs consistently by Ctrl + 1, Ctrl + 2 ...
47 //       User Action   : The KeyEvent widget will receives
48 // ----------------------------------------------------------
49 // 1. Press Ctrl key   : Ctrl Keydown
50 // 2. Release Ctrl key : No event
51 // 3. Press Ctrl key   : No event
52 // 4. Release Ctrl key : No event
53 // 5. Press 1 key      : 1 Keydown event with Ctrl modifier.
54 // 6. Release 1 key    : 1 Keyup event with Ctrl modifier.
55 // 7. Press 2 key      : 2 Keydown event with Ctrl modifier.
56 // 8. Release 2 key    : 2 Keyup event with Ctrl modifier.
57 // 9. Press Ctrl key   : No event
58 // 10. Release Ctrl key: Ctrl Keyup
59 //
60 // In the case of Chrome OS, StickyKeysController supports Shift,Alt,Ctrl
61 // modifiers. Each handling or state is performed independently.
62 //
63 // StickyKeysController is disabled by default.
64 class ASH_EXPORT StickyKeysController {
65  public:
66   StickyKeysController();
67   virtual ~StickyKeysController();
68 
69   // Activate sticky keys to intercept and modify incoming events.
70   void Enable(bool enabled);
71 
72   void SetModifiersEnabled(bool mod3_enabled, bool altgr_enabled);
73 
74   // Returns the StickyKeyOverlay used by the controller. Ownership is not
75   // passed.
76   StickyKeysOverlay* GetOverlayForTest();
77 
78   // Handles keyboard event. Returns an |EventRewriteStatus|, and may
79   // modify |flags|:
80   // - Returns ui::EVENT_REWRITE_DISCARD, and leaves |flags| untouched,
81   //   if the event is consumed (i.e. a sticky modifier press or release);
82   // - Returns ui::EVENT_REWRITE_REWRITTEN if the event needs to be modified
83   //   according to the returned |flags| (i.e. a sticky-modified key);
84   // - Returns ui::EVENT_REWRITE_DISPATCH_ANOTHER if the event needs to be
85   //   modified according to the returned |flags|, and there are delayed
86   //   modifier-up   events now to be retrieved using |NextDispatchEvent()|
87   //   (i.e. a sticky-modified key that ends a sticky state);
88   // - Otherwise returns ui::EVENT_REWRITE_CONTINUE and leaves |flags|
89   //   unchanged.
90   ui::EventRewriteStatus RewriteKeyEvent(const ui::KeyEvent& event,
91                                          ui::KeyboardCode key_code,
92                                          int* flags);
93 
94   // Handles mouse event.
95   ui::EventRewriteStatus RewriteMouseEvent(const ui::MouseEvent& event,
96                                            int* flags);
97 
98   // Handles scroll event.
99   ui::EventRewriteStatus RewriteScrollEvent(const ui::ScrollEvent& event,
100                                             int* flags);
101 
102   // Obtains a pending modifier-up event. If the immediately previous
103   // call to |Rewrite...Event()| or |NextDispatchEvent()| returned
104   // ui::EVENT_REWRITE_DISPATCH_ANOTHER, this sets |new_event| and returns:
105   // - ui::EVENT_REWRITE_DISPATCH_ANOTHER if there is at least one more
106   //   pending modifier-up event;
107   // - ui::EVENT_REWRITE_REWRITE if this is the last or only modifier-up event;
108   // Otherwise, there is no pending modifier-up event, and this function
109   // returns ui::EVENT_REWRITE_CONTINUE and sets |new_event| to NULL.
110   ui::EventRewriteStatus NextDispatchEvent(scoped_ptr<ui::Event>* new_event);
111 
112  private:
113   // Handles keyboard event. Returns true if Sticky key consumes keyboard event.
114   // Adds to |mod_down_flags| any flag to be added to the key event.
115   // Sets |released| if any modifier is to be released after the key event.
116   bool HandleKeyEvent(const ui::KeyEvent& event,
117                       ui::KeyboardCode key_code,
118                       int* mod_down_flags,
119                       bool* released);
120 
121   // Handles mouse event. Returns true if Sticky key consumes keyboard event.
122   // Sets |released| if any modifier is to be released after the key event.
123   bool HandleMouseEvent(const ui::MouseEvent& event,
124                         int* mod_down_flags,
125                         bool* released);
126 
127   // Handles scroll event. Returns true if Sticky key consumes keyboard event.
128   // Sets |released| if any modifier is to be released after the key event.
129   bool HandleScrollEvent(const ui::ScrollEvent& event,
130                          int* mod_down_flags,
131                          bool* released);
132 
133   // Updates the overlay UI with the current state of the sticky keys.
134   void UpdateOverlay();
135 
136   // Whether sticky keys is activated and modifying events.
137   bool enabled_;
138 
139   // Whether the current layout has a mod3 key.
140   bool mod3_enabled_;
141 
142   // Whether the current layout has an altgr key.
143   bool altgr_enabled_;
144 
145   // Sticky key handlers.
146   scoped_ptr<StickyKeysHandler> shift_sticky_key_;
147   scoped_ptr<StickyKeysHandler> alt_sticky_key_;
148   scoped_ptr<StickyKeysHandler> altgr_sticky_key_;
149   scoped_ptr<StickyKeysHandler> ctrl_sticky_key_;
150   scoped_ptr<StickyKeysHandler> mod3_sticky_key_;
151 
152   scoped_ptr<StickyKeysOverlay> overlay_;
153 
154   DISALLOW_COPY_AND_ASSIGN(StickyKeysController);
155 };
156 
157 // StickyKeysHandler handles key event and controls sticky keysfor specific
158 // modifier keys. If monitored keyboard events are recieved, StickyKeysHandler
159 // changes internal state. If non modifier keyboard events or mouse events are
160 // received, StickyKeysHandler will append modifier based on internal state.
161 // For other events, StickyKeysHandler does nothing.
162 //
163 // The DISABLED state is default state and any incoming non modifier keyboard
164 // events will not be modified. The ENABLED state is one shot modification
165 // state. Only next keyboard event will be modified. After that, internal state
166 // will be back to DISABLED state with sending modifier keyup event. In the case
167 // of LOCKED state, all incomming keyboard events will be modified. The LOCKED
168 // state will be back to DISABLED state by next monitoring modifier key.
169 //
170 // The detailed state flow as follows:
171 //                                     Current state
172 //                  |   DISABLED    |    ENABLED     |    LOCKED   |
173 // ----------------------------------------------------------------|
174 // Modifier KeyDown |   noop        |    noop(*)     |    noop(*)  |
175 // Modifier KeyUp   | To ENABLED(*) | To LOCKED(*)   | To DISABLED |
176 // Normal KeyDown   |   noop        | To DISABLED(#) |    noop(#)  |
177 // Normal KeyUp     |   noop        |    noop        |    noop(#)  |
178 // Other KeyUp/Down |   noop        |    noop        |    noop     |
179 // Mouse Press      |   noop        |    noop(#)     |    noop(#)  |
180 // Mouse Release    |   noop        | To DISABLED(#) |    noop(#)  |
181 // Mouse Wheel      |   noop        | To DISABLED(#) |    noop(#)  |
182 // Other Mouse Event|   noop        |    noop        |    noop     |
183 //
184 // Here, (*) means key event will be consumed by StickyKeys, and (#) means event
185 // is modified.
186 class ASH_EXPORT StickyKeysHandler {
187  public:
188   explicit StickyKeysHandler(ui::EventFlags modifier_flag);
189   ~StickyKeysHandler();
190 
191   // Handles keyboard event. Returns true if Sticky key consumes keyboard event.
192   // Sets its own modifier flag in |mod_down_flags| if it is active and needs
193   // to be added to the event, and sets |released| if releasing it.
194   bool HandleKeyEvent(const ui::KeyEvent& event,
195                       ui::KeyboardCode key_code,
196                       int* mod_down_flags,
197                       bool* released);
198 
199   // Handles mouse event. Returns true if sticky key consumes mouse event.
200   // Sets its own modifier flag in |mod_down_flags| if it is active and needs
201   // to be added to the event, and sets |released| if releasing it.
202   bool HandleMouseEvent(const ui::MouseEvent& event,
203                         int* mod_down_flags,
204                         bool* released);
205 
206   // Handles scroll event. Returns true if sticky key consumes scroll event.
207   // Sets its own modifier flag in |mod_down_flags| if it is active and needs
208   // to be added to the event, and sets |released| if releasing it.
209   bool HandleScrollEvent(const ui::ScrollEvent& event,
210                          int* mod_down_flags,
211                          bool* released);
212 
213   // Fetches a pending modifier-up event if one exists and the return
214   // parameter |new_event| is available (i.e. not set). Returns the number
215   // of pending events still remaining to be returned.
216   int GetModifierUpEvent(scoped_ptr<ui::Event>* new_event);
217 
218   // Returns current internal state.
current_state()219   StickyKeyState current_state() const { return current_state_; }
220 
221  private:
222   // Represents event type in Sticky Key context.
223   enum KeyEventType {
224     TARGET_MODIFIER_DOWN,  // The monitoring modifier key is down.
225     TARGET_MODIFIER_UP,  // The monitoring modifier key is up.
226     NORMAL_KEY_DOWN,  // The non modifier key is down.
227     NORMAL_KEY_UP,  // The non modifier key is up.
228     OTHER_MODIFIER_DOWN,  // The modifier key but not monitored key is down.
229     OTHER_MODIFIER_UP,  // The modifier key but not monitored key is up.
230   };
231 
232   // Translates event type and key code to sticky keys event type.
233   KeyEventType TranslateKeyEvent(ui::EventType type, ui::KeyboardCode key_code);
234 
235   // Handles key event in DISABLED state. Returns true if sticky keys
236   // consumes the keyboard event.
237   bool HandleDisabledState(const ui::KeyEvent& event,
238                            ui::KeyboardCode key_code);
239 
240   // Handles key event in ENABLED state. Returns true if sticky keys
241   // consumes the keyboard event.
242   bool HandleEnabledState(const ui::KeyEvent& event,
243                           ui::KeyboardCode key_code,
244                           int* mod_down_flags,
245                           bool* released);
246 
247   // Handles key event in LOCKED state. Returns true if sticky keys
248   // consumes the keyboard event.
249   bool HandleLockedState(const ui::KeyEvent& event,
250                          ui::KeyboardCode key_code,
251                          int* mod_down_flags,
252                          bool* released);
253 
254   // The modifier flag to be monitored and appended to events.
255   const ui::EventFlags modifier_flag_;
256 
257   // The current sticky key status.
258   StickyKeyState current_state_;
259 
260   // True if we received the TARGET_MODIFIER_DOWN event while in the DISABLED
261   // state but before we receive the TARGET_MODIFIER_UP event. Normal
262   // shortcuts (eg. ctrl + t) during this time will prevent a transition to
263   // the ENABLED state.
264   bool preparing_to_enable_;
265 
266   // Tracks the scroll direction of the current scroll sequence. Sticky keys
267   // stops modifying the scroll events of the sequence when the direction
268   // changes. If no sequence is tracked, the value is 0.
269   int scroll_delta_;
270 
271   // The modifier up key event to be sent on non modifier key on ENABLED state.
272   scoped_ptr<ui::KeyEvent> modifier_up_event_;
273 
274   DISALLOW_COPY_AND_ASSIGN(StickyKeysHandler);
275 };
276 
277 }  // namespace ash
278 
279 #endif  // ASH_STICKY_KEYS_STICKY_KEYS_CONTROLLER_H_
280