Home | History | Annotate | Download | only in wm
      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_WM_STICKY_KEYS_H_
      6 #define ASH_WM_STICKY_KEYS_H_
      7 
      8 #include "ash/ash_export.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "ui/base/events/event_constants.h"
     11 
     12 namespace ui {
     13 class KeyEvent;
     14 }  // namespace ui
     15 
     16 namespace aura {
     17 class Window;
     18 }  // namespace aura
     19 
     20 namespace ash {
     21 
     22 class StickyKeysHandler;
     23 
     24 // StickyKeys is an accessibility feature for users to be able to compose
     25 // key event with modifier keys without simultaneous key press event. Instead,
     26 // they can compose modified key events separately pressing each of the keys
     27 // involved.
     28 // e.g. Composing Ctrl + T
     29 //       User Action   : The KeyEvent widget will receives
     30 // ----------------------------------------------------------
     31 // 1. Press Ctrl key   : Ctrl Keydown.
     32 // 2. Release Ctrl key : No event
     33 // 3. Press T key      : T keydown event with ctrl modifier.
     34 // 4.                  : Ctrl Keyup
     35 // 5. Release T key    : T keyup without ctrl modifier (Windows behavior)
     36 //
     37 // By typing same modifier keys twice, users can generate bunch of modified key
     38 // events.
     39 // e.g. To focus tabs consistently by Ctrl + 1, Ctrl + 2 ...
     40 //       User Action   : The KeyEvent widget will receives
     41 // ----------------------------------------------------------
     42 // 1. Press Ctrl key   : Ctrl Keydown
     43 // 2. Release Ctrl key : No event
     44 // 3. Press Ctrl key   : No event
     45 // 4. Release Ctrl key : No event
     46 // 5. Press 1 key      : 1 Keydown event with Ctrl modifier.
     47 // 6. Release 1 key    : 1 Keyup event with Ctrl modifier.
     48 // 7. Press 2 key      : 2 Keydown event with Ctrl modifier.
     49 // 8. Release 2 key    : 2 Keyup event with Ctrl modifier.
     50 // 9. Press Ctrl key   : No event
     51 // 10. Release Ctrl key: Ctrl Keyup
     52 //
     53 // In the case of Chrome OS, StickyKeys supports Shift,Alt,Ctrl modifiers. Each
     54 // handling or state is performed independently.
     55 //
     56 // StickyKeys is disabled by default.
     57 class ASH_EXPORT StickyKeys {
     58  public:
     59   StickyKeys();
     60   ~StickyKeys();
     61 
     62   // Handles keyboard event. Returns true if Sticky key consumes keyboard event.
     63   bool HandleKeyEvent(ui::KeyEvent* event);
     64 
     65  private:
     66   // Sticky key handlers.
     67   scoped_ptr<StickyKeysHandler> shift_sticky_key_;
     68   scoped_ptr<StickyKeysHandler> alt_sticky_key_;
     69   scoped_ptr<StickyKeysHandler> ctrl_sticky_key_;
     70 
     71   DISALLOW_COPY_AND_ASSIGN(StickyKeys);
     72 };
     73 
     74 // StickyKeysHandler handles key event and performs StickyKeys for specific
     75 // modifier keys. If monitored keyboard events are recieved, StickyKeysHandler
     76 // changes internal state. If non modifier keyboard events are received,
     77 // StickyKeysHandler will append modifier based on internal state. For other
     78 // events, StickyKeysHandler does nothing.
     79 //
     80 // The DISABLED state is default state and any incomming non modifier keyboard
     81 // events will not be modified. The ENABLED state is one shot modification
     82 // state. Only next keyboard event will be modified. After that, internal state
     83 // will be back to DISABLED state with sending modifier keyup event. In the case
     84 // of LOCKED state, all incomming keyboard events will be modified. The LOCKED
     85 // state will be back to DISABLED state by next monitoring modifier key.
     86 //
     87 // The detailed state flow as follows:
     88 //                                     Current state
     89 //                  |   DISABLED    |    ENABLED     |    LOCKED   |
     90 // ----------------------------------------------------------------|
     91 // Modifier KeyDown |   noop        |    noop(*)     |    noop(*)  |
     92 // Modifier KeyUp   | To ENABLED(*) | To LOCKED(*)   | To DISABLED |
     93 // Normal KeyDown   |   noop        | To DISABLED(#) |    noop(#)  |
     94 // Normal KeyUp     |   noop        |    noop        |    noop(#)  |
     95 // Other KeyUp/Down |   noop        |    noop        |    noop     |
     96 //
     97 // Here, (*) means key event will be consumed by StickyKeys, and (#) means event
     98 // is modified.
     99 class ASH_EXPORT StickyKeysHandler {
    100  public:
    101   class StickyKeysHandlerDelegate {
    102    public:
    103     StickyKeysHandlerDelegate();
    104     virtual ~StickyKeysHandlerDelegate();
    105 
    106     // Dispatches keyboard event synchronously.
    107     virtual void DispatchKeyEvent(ui::KeyEvent* event,
    108                                   aura::Window* target) = 0;
    109   };
    110   // Represents Sticky Key state.
    111   enum StickyKeyState {
    112     // The sticky key is disabled. Incomming non modifier key events are not
    113     // affected.
    114     DISABLED,
    115     // The sticky key is enabled. Incomming non modifier key down events are
    116     // modified with |modifier_flag_|. After that, sticky key state become
    117     // DISABLED.
    118     ENABLED,
    119     // The sticky key is locked. Incomming non modifier key down events are
    120     // modified with |modifier_flag_|.
    121     LOCKED,
    122   };
    123 
    124   // This class takes an ownership of |delegate|.
    125   StickyKeysHandler(ui::EventFlags modifier_flag,
    126                     StickyKeysHandlerDelegate* delegate);
    127   ~StickyKeysHandler();
    128 
    129   // Handles key event. Returns true if key is consumed.
    130   bool HandleKeyEvent(ui::KeyEvent* event);
    131 
    132   // Returns current internal state.
    133   StickyKeyState current_state() const { return current_state_; }
    134 
    135  private:
    136   // Represents event type in Sticky Key context.
    137   enum KeyEventType {
    138     TARGET_MODIFIER_DOWN,  // The monitoring modifier key is down.
    139     TARGET_MODIFIER_UP,  // The monitoring modifier key is up.
    140     NORMAL_KEY_DOWN,  // The non modifier key is down.
    141     NORMAL_KEY_UP,  // The non modifier key is up.
    142     OTHER_MODIFIER_DOWN,  // The modifier key but not monitored key is down.
    143     OTHER_MODIFIER_UP,  // The modifier key but not monitored key is up.
    144   };
    145 
    146   // Translates |event| to sticky keys event type.
    147   KeyEventType TranslateKeyEvent(ui::KeyEvent* event);
    148 
    149   // Handles key event in DISABLED state.
    150   bool HandleDisabledState(ui::KeyEvent* event);
    151 
    152   // Handles key event in ENABLED state.
    153   bool HandleEnabledState(ui::KeyEvent* event);
    154 
    155   // Handles key event in LOCKED state.
    156   bool HandleLockedState(ui::KeyEvent* event);
    157 
    158   // Adds |modifier_flags_| into |event|.
    159   void AppendModifier(ui::KeyEvent* event);
    160 
    161   // The modifier flag to be monitored and appended.
    162   const ui::EventFlags modifier_flag_;
    163 
    164   // The current sticky key status.
    165   StickyKeyState current_state_;
    166 
    167   // True if the received key event is sent by StickyKeyHandler.
    168   bool keyevent_from_myself_;
    169 
    170   // The modifier up key event to be sent on non modifier key on ENABLED state.
    171   scoped_ptr<ui::KeyEvent> modifier_up_event_;
    172 
    173   scoped_ptr<StickyKeysHandlerDelegate> delegate_;
    174 
    175   DISALLOW_COPY_AND_ASSIGN(StickyKeysHandler);
    176 };
    177 
    178 }  // namespace ash
    179 
    180 #endif  // ASH_WM_STICKY_KEYS_H_
    181