sticky_keys_controller.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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. #ifndef ASH_ACCESSIBILITY_STICKY_KEYS_STICKY_KEYS_CONTROLLER_H_
  5. #define ASH_ACCESSIBILITY_STICKY_KEYS_STICKY_KEYS_CONTROLLER_H_
  6. #include <memory>
  7. #include "ash/accessibility/sticky_keys/sticky_keys_state.h"
  8. #include "ash/ash_export.h"
  9. #include "ui/events/event_constants.h"
  10. #include "ui/events/event_handler.h"
  11. #include "ui/events/event_rewriter.h"
  12. #include "ui/events/keycodes/keyboard_codes.h"
  13. #include "ui/events/types/event_type.h"
  14. namespace ui {
  15. class Event;
  16. class KeyEvent;
  17. class MouseEvent;
  18. } // namespace ui
  19. namespace ash {
  20. class StickyKeysOverlay;
  21. class StickyKeysHandler;
  22. // StickyKeysController is an accessibility feature for users to be able to
  23. // compose key and mouse event with modifier keys without simultaneous key
  24. // press event. Instead they can compose events separately pressing each of the
  25. // modifier keys involved.
  26. // e.g. Composing Ctrl + T
  27. // User Action : The KeyEvent widget will receives
  28. // ----------------------------------------------------------
  29. // 1. Press Ctrl key : Ctrl Keydown.
  30. // 2. Release Ctrl key : No event
  31. // 3. Press T key : T keydown event with ctrl modifier.
  32. // 4. : Ctrl Keyup
  33. // 5. Release T key : T keyup without ctrl modifier (Windows behavior)
  34. //
  35. // By typing same modifier keys twice, users can generate bunch of modified key
  36. // events.
  37. // e.g. To focus tabs consistently by Ctrl + 1, Ctrl + 2 ...
  38. // User Action : The KeyEvent widget will receives
  39. // ----------------------------------------------------------
  40. // 1. Press Ctrl key : Ctrl Keydown
  41. // 2. Release Ctrl key : No event
  42. // 3. Press Ctrl key : No event
  43. // 4. Release Ctrl key : No event
  44. // 5. Press 1 key : 1 Keydown event with Ctrl modifier.
  45. // 6. Release 1 key : 1 Keyup event with Ctrl modifier.
  46. // 7. Press 2 key : 2 Keydown event with Ctrl modifier.
  47. // 8. Release 2 key : 2 Keyup event with Ctrl modifier.
  48. // 9. Press Ctrl key : No event
  49. // 10. Release Ctrl key: Ctrl Keyup
  50. //
  51. // In the case of Chrome OS, StickyKeysController supports Shift,Alt,Ctrl
  52. // modifiers. Each handling or state is performed independently.
  53. //
  54. // StickyKeysController is disabled by default.
  55. class ASH_EXPORT StickyKeysController : public ui::EventRewriter {
  56. public:
  57. StickyKeysController();
  58. StickyKeysController(const StickyKeysController&) = delete;
  59. StickyKeysController& operator=(const StickyKeysController&) = delete;
  60. ~StickyKeysController() override;
  61. // Activate sticky keys to intercept and modify incoming events.
  62. void Enable(bool enabled);
  63. void SetModifiersEnabled(bool mod3_enabled, bool altgr_enabled);
  64. // Update StickyKeysOverlay bounds (e.g. if the workspace area changed).
  65. void UpdateStickyKeysOverlayBoundsIfNeeded();
  66. // Returns the StickyKeyOverlay used by the controller. Ownership is not
  67. // passed.
  68. StickyKeysOverlay* GetOverlayForTest();
  69. // ui::EventRewriter:
  70. ui::EventRewriteStatus RewriteEvent(
  71. const ui::Event& event,
  72. std::unique_ptr<ui::Event>* rewritten_event) override;
  73. ui::EventRewriteStatus NextDispatchEvent(
  74. const ui::Event& last_event,
  75. std::unique_ptr<ui::Event>* new_event) override;
  76. bool enabled_for_test() const { return enabled_; }
  77. private:
  78. // Rewrite keyboard event.
  79. ui::EventRewriteStatus RewriteKeyEvent(
  80. const ui::KeyEvent& event,
  81. std::unique_ptr<ui::Event>* rewritten_event);
  82. // Rewrite mouse event.
  83. ui::EventRewriteStatus RewriteMouseEvent(
  84. const ui::MouseEvent& event,
  85. std::unique_ptr<ui::Event>* rewritten_event);
  86. // Rewrite scroll event.
  87. ui::EventRewriteStatus RewriteScrollEvent(
  88. const ui::ScrollEvent& event,
  89. std::unique_ptr<ui::Event>* rewritten_event);
  90. // Updates the overlay UI with the current state of the sticky keys.
  91. void UpdateOverlay();
  92. // Whether sticky keys is activated and modifying events.
  93. bool enabled_;
  94. // Whether the current layout has a mod3 key.
  95. bool mod3_enabled_;
  96. // Whether the current layout has an altgr key.
  97. bool altgr_enabled_;
  98. // Sticky key handlers.
  99. std::unique_ptr<StickyKeysHandler> shift_sticky_key_;
  100. std::unique_ptr<StickyKeysHandler> alt_sticky_key_;
  101. std::unique_ptr<StickyKeysHandler> altgr_sticky_key_;
  102. std::unique_ptr<StickyKeysHandler> ctrl_sticky_key_;
  103. std::unique_ptr<StickyKeysHandler> mod3_sticky_key_;
  104. std::unique_ptr<StickyKeysHandler> search_sticky_key_;
  105. std::unique_ptr<StickyKeysOverlay> overlay_;
  106. };
  107. // StickyKeysHandler handles key event and controls sticky keysfor specific
  108. // modifier keys. If monitored keyboard events are received, StickyKeysHandler
  109. // changes internal state. If non modifier keyboard events or mouse events are
  110. // received, StickyKeysHandler will append modifier based on internal state.
  111. // For other events, StickyKeysHandler does nothing.
  112. //
  113. // The DISABLED state is default state and any incoming non modifier keyboard
  114. // events will not be modified. The ENABLED state is one shot modification
  115. // state. Only next keyboard event will be modified. After that, internal state
  116. // will be back to DISABLED state with sending modifier keyup event. In the case
  117. // of LOCKED state, all incomming keyboard events will be modified. The LOCKED
  118. // state will be back to DISABLED state by next monitoring modifier key.
  119. //
  120. // The detailed state flow as follows:
  121. // Current state
  122. // | DISABLED | ENABLED | LOCKED |
  123. // ----------------------------------------------------------------|
  124. // Modifier KeyDown | noop | noop(*) | noop(*) |
  125. // Modifier KeyUp | To ENABLED(*) | To LOCKED(*) | To DISABLED |
  126. // Normal KeyDown | noop | To DISABLED(#) | noop(#) |
  127. // Normal KeyUp | noop | noop | noop(#) |
  128. // Other KeyUp/Down | noop | noop | noop |
  129. // Mouse Press | noop | noop(#) | noop(#) |
  130. // Mouse Release | noop | To DISABLED(#) | noop(#) |
  131. // Mouse Wheel | noop | To DISABLED(#) | noop(#) |
  132. // Other Mouse Event| noop | noop | noop |
  133. //
  134. // Here, (*) means key event will be consumed by StickyKeys, and (#) means event
  135. // is modified.
  136. class ASH_EXPORT StickyKeysHandler {
  137. public:
  138. explicit StickyKeysHandler(ui::EventFlags modifier_flag);
  139. StickyKeysHandler(const StickyKeysHandler&) = delete;
  140. StickyKeysHandler& operator=(const StickyKeysHandler&) = delete;
  141. ~StickyKeysHandler();
  142. // Handles keyboard event. Returns true if Sticky key consumes keyboard event.
  143. // Sets its own modifier flag in |mod_down_flags| if it is active and needs
  144. // to be added to the event, and sets |released| if releasing it.
  145. bool HandleKeyEvent(const ui::KeyEvent& event,
  146. int* mod_down_flags,
  147. bool* released);
  148. // Handles mouse event. Returns true if sticky key consumes mouse event.
  149. // Sets its own modifier flag in |mod_down_flags| if it is active and needs
  150. // to be added to the event, and sets |released| if releasing it.
  151. bool HandleMouseEvent(const ui::MouseEvent& event,
  152. int* mod_down_flags,
  153. bool* released);
  154. // Handles scroll event. Returns true if sticky key consumes scroll event.
  155. // Sets its own modifier flag in |mod_down_flags| if it is active and needs
  156. // to be added to the event, and sets |released| if releasing it.
  157. bool HandleScrollEvent(const ui::ScrollEvent& event,
  158. int* mod_down_flags,
  159. bool* released);
  160. // Fetches a pending modifier-up event if one exists and the return
  161. // parameter |new_event| is available (i.e. not set). Returns the number
  162. // of pending events still remaining to be returned.
  163. int GetModifierUpEvent(std::unique_ptr<ui::Event>* new_event);
  164. // Returns current internal state.
  165. StickyKeyState current_state() const { return current_state_; }
  166. private:
  167. // Represents event type in Sticky Key context.
  168. enum KeyEventType {
  169. TARGET_MODIFIER_DOWN, // The monitoring modifier key is down.
  170. TARGET_MODIFIER_UP, // The monitoring modifier key is up.
  171. NORMAL_KEY_DOWN, // The non modifier key is down.
  172. NORMAL_KEY_UP, // The non modifier key is up.
  173. OTHER_MODIFIER_DOWN, // The modifier key but not monitored key is down.
  174. OTHER_MODIFIER_UP, // The modifier key but not monitored key is up.
  175. };
  176. // Translates event type and key code to sticky keys event type.
  177. KeyEventType TranslateKeyEvent(ui::EventType type, ui::KeyboardCode key_code);
  178. // Handles key event in DISABLED state. Returns true if sticky keys
  179. // consumes the keyboard event.
  180. bool HandleDisabledState(const ui::KeyEvent& event);
  181. // Handles key event in ENABLED state. Returns true if sticky keys
  182. // consumes the keyboard event.
  183. bool HandleEnabledState(const ui::KeyEvent& event,
  184. int* mod_down_flags,
  185. bool* released);
  186. // Handles key event in LOCKED state. Returns true if sticky keys
  187. // consumes the keyboard event.
  188. bool HandleLockedState(const ui::KeyEvent& event,
  189. int* mod_down_flags,
  190. bool* released);
  191. // The modifier flag to be monitored and appended to events.
  192. const ui::EventFlags modifier_flag_;
  193. // The current sticky key status.
  194. StickyKeyState current_state_;
  195. // True if we received the TARGET_MODIFIER_DOWN event while in the DISABLED
  196. // state but before we receive the TARGET_MODIFIER_UP event. Normal
  197. // shortcuts (eg. ctrl + t) during this time will prevent a transition to
  198. // the ENABLED state.
  199. bool preparing_to_enable_;
  200. // Tracks the scroll direction of the current scroll sequence. Sticky keys
  201. // stops modifying the scroll events of the sequence when the direction
  202. // changes. If no sequence is tracked, the value is 0.
  203. int scroll_delta_;
  204. // The modifier up key event to be sent on non modifier key on ENABLED state.
  205. std::unique_ptr<ui::KeyEvent> modifier_up_event_;
  206. };
  207. } // namespace ash
  208. #endif // ASH_ACCESSIBILITY_STICKY_KEYS_STICKY_KEYS_CONTROLLER_H_