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