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.
5 #include "ash/wm/sticky_keys.h"
10 #include "base/basictypes.h"
11 #include "base/debug/stack_trace.h"
12 #include "ui/aura/root_window.h"
13 #include "ui/base/events/event.h"
14 #include "ui/base/keycodes/keyboard_code_conversion.h"
20 // An implementation of StickyKeysHandler::StickyKeysHandlerDelegate.
21 class StickyKeysHandlerDelegateImpl
:
22 public StickyKeysHandler::StickyKeysHandlerDelegate
{
24 StickyKeysHandlerDelegateImpl();
25 virtual ~StickyKeysHandlerDelegateImpl();
27 // StickyKeysHandlerDelegate overrides.
28 virtual void DispatchKeyEvent(ui::KeyEvent
* event
,
29 aura::Window
* target
) OVERRIDE
;
31 DISALLOW_COPY_AND_ASSIGN(StickyKeysHandlerDelegateImpl
);
34 StickyKeysHandlerDelegateImpl::StickyKeysHandlerDelegateImpl() {
37 StickyKeysHandlerDelegateImpl::~StickyKeysHandlerDelegateImpl() {
40 void StickyKeysHandlerDelegateImpl::DispatchKeyEvent(ui::KeyEvent
* event
,
41 aura::Window
* target
) {
43 target
->GetRootWindow()->AsRootWindowHostDelegate()->OnHostKeyEvent(event
);
48 ///////////////////////////////////////////////////////////////////////////////
50 StickyKeys::StickyKeys()
52 new StickyKeysHandler(ui::EF_SHIFT_DOWN
,
53 new StickyKeysHandlerDelegateImpl())),
55 new StickyKeysHandler(ui::EF_ALT_DOWN
,
56 new StickyKeysHandlerDelegateImpl())),
58 new StickyKeysHandler(ui::EF_CONTROL_DOWN
,
59 new StickyKeysHandlerDelegateImpl())) {
62 StickyKeys::~StickyKeys() {
65 bool StickyKeys::HandleKeyEvent(ui::KeyEvent
* event
) {
66 return shift_sticky_key_
->HandleKeyEvent(event
) ||
67 alt_sticky_key_
->HandleKeyEvent(event
) ||
68 ctrl_sticky_key_
->HandleKeyEvent(event
);
71 ///////////////////////////////////////////////////////////////////////////////
73 StickyKeysHandler::StickyKeysHandler(ui::EventFlags target_modifier_flag
,
74 StickyKeysHandlerDelegate
* delegate
)
75 : modifier_flag_(target_modifier_flag
),
76 current_state_(DISABLED
),
77 keyevent_from_myself_(false),
81 StickyKeysHandler::~StickyKeysHandler() {
84 StickyKeysHandler::StickyKeysHandlerDelegate::StickyKeysHandlerDelegate() {
87 StickyKeysHandler::StickyKeysHandlerDelegate::~StickyKeysHandlerDelegate() {
90 bool StickyKeysHandler::HandleKeyEvent(ui::KeyEvent
* event
) {
91 if (keyevent_from_myself_
)
92 return false; // Do not handle self-generated key event.
93 switch (current_state_
) {
95 return HandleDisabledState(event
);
97 return HandleEnabledState(event
);
99 return HandleLockedState(event
);
105 StickyKeysHandler::KeyEventType
106 StickyKeysHandler::TranslateKeyEvent(ui::KeyEvent
* event
) {
107 bool is_target_key
= false;
108 if (event
->key_code() == ui::VKEY_SHIFT
||
109 event
->key_code() == ui::VKEY_LSHIFT
||
110 event
->key_code() == ui::VKEY_RSHIFT
) {
111 is_target_key
= (modifier_flag_
== ui::EF_SHIFT_DOWN
);
112 } else if (event
->key_code() == ui::VKEY_CONTROL
||
113 event
->key_code() == ui::VKEY_LCONTROL
||
114 event
->key_code() == ui::VKEY_RCONTROL
) {
115 is_target_key
= (modifier_flag_
== ui::EF_CONTROL_DOWN
);
116 } else if (event
->key_code() == ui::VKEY_MENU
||
117 event
->key_code() == ui::VKEY_LMENU
||
118 event
->key_code() == ui::VKEY_RMENU
) {
119 is_target_key
= (modifier_flag_
== ui::EF_ALT_DOWN
);
121 return event
->type() == ui::ET_KEY_PRESSED
?
122 NORMAL_KEY_DOWN
: NORMAL_KEY_UP
;
126 return event
->type() == ui::ET_KEY_PRESSED
?
127 TARGET_MODIFIER_DOWN
: TARGET_MODIFIER_UP
;
129 return event
->type() == ui::ET_KEY_PRESSED
?
130 OTHER_MODIFIER_DOWN
: OTHER_MODIFIER_UP
;
133 bool StickyKeysHandler::HandleDisabledState(ui::KeyEvent
* event
) {
134 switch (TranslateKeyEvent(event
)) {
135 case TARGET_MODIFIER_UP
:
136 current_state_
= ENABLED
;
137 modifier_up_event_
.reset(event
->Copy());
139 case TARGET_MODIFIER_DOWN
:
140 case NORMAL_KEY_DOWN
:
142 case OTHER_MODIFIER_DOWN
:
143 case OTHER_MODIFIER_UP
:
150 bool StickyKeysHandler::HandleEnabledState(ui::KeyEvent
* event
) {
151 switch (TranslateKeyEvent(event
)) {
153 case TARGET_MODIFIER_DOWN
:
155 case TARGET_MODIFIER_UP
:
156 current_state_
= LOCKED
;
157 modifier_up_event_
.reset();
159 case NORMAL_KEY_DOWN
: {
160 DCHECK(modifier_up_event_
.get());
161 aura::Window
* target
= static_cast<aura::Window
*>(event
->target());
164 current_state_
= DISABLED
;
165 AppendModifier(event
);
166 // We can't post event, so dispatch current keyboard event first then
167 // dispatch next keyboard event.
168 keyevent_from_myself_
= true;
169 delegate_
->DispatchKeyEvent(event
, target
);
170 delegate_
->DispatchKeyEvent(modifier_up_event_
.get(), target
);
171 keyevent_from_myself_
= false;
174 case OTHER_MODIFIER_DOWN
:
175 case OTHER_MODIFIER_UP
:
182 bool StickyKeysHandler::HandleLockedState(ui::KeyEvent
* event
) {
183 switch (TranslateKeyEvent(event
)) {
184 case TARGET_MODIFIER_DOWN
:
186 case TARGET_MODIFIER_UP
:
187 current_state_
= DISABLED
;
189 case NORMAL_KEY_DOWN
:
191 AppendModifier(event
);
193 case OTHER_MODIFIER_DOWN
:
194 case OTHER_MODIFIER_UP
:
201 void StickyKeysHandler::AppendModifier(ui::KeyEvent
* event
) {
202 XEvent
* xev
= event
->native_event();
203 XKeyEvent
* xkey
= &(xev
->xkey
);
204 switch (modifier_flag_
) {
205 case ui::EF_CONTROL_DOWN
:
206 xkey
->state
|= ControlMask
;
208 case ui::EF_ALT_DOWN
:
209 xkey
->state
|= Mod1Mask
;
211 case ui::EF_SHIFT_DOWN
:
212 xkey
->state
|= ShiftMask
;
217 event
->set_flags(event
->flags() | modifier_flag_
);
218 event
->set_character(ui::GetCharacterFromKeyCode(event
->key_code(),
220 event
->NormalizeFlags();