Windows should animate when they are about to get docked at screen edges.
[chromium-blink-merge.git] / ash / wm / sticky_keys.cc
blob55c5c9b887cfc50f66a988e39d0594ea05f3d6db
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"
7 #include <X11/Xlib.h>
8 #undef RootWindow
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"
16 namespace ash {
18 namespace {
20 // An implementation of StickyKeysHandler::StickyKeysHandlerDelegate.
21 class StickyKeysHandlerDelegateImpl :
22 public StickyKeysHandler::StickyKeysHandlerDelegate {
23 public:
24 StickyKeysHandlerDelegateImpl();
25 virtual ~StickyKeysHandlerDelegateImpl();
27 // StickyKeysHandlerDelegate overrides.
28 virtual void DispatchKeyEvent(ui::KeyEvent* event,
29 aura::Window* target) OVERRIDE;
30 private:
31 DISALLOW_COPY_AND_ASSIGN(StickyKeysHandlerDelegateImpl);
34 StickyKeysHandlerDelegateImpl::StickyKeysHandlerDelegateImpl() {
37 StickyKeysHandlerDelegateImpl::~StickyKeysHandlerDelegateImpl() {
40 void StickyKeysHandlerDelegateImpl::DispatchKeyEvent(ui::KeyEvent* event,
41 aura::Window* target) {
42 DCHECK(target);
43 target->GetRootWindow()->AsRootWindowHostDelegate()->OnHostKeyEvent(event);
46 } // namespace
48 ///////////////////////////////////////////////////////////////////////////////
49 // StickyKeys
50 StickyKeys::StickyKeys()
51 : shift_sticky_key_(
52 new StickyKeysHandler(ui::EF_SHIFT_DOWN,
53 new StickyKeysHandlerDelegateImpl())),
54 alt_sticky_key_(
55 new StickyKeysHandler(ui::EF_ALT_DOWN,
56 new StickyKeysHandlerDelegateImpl())),
57 ctrl_sticky_key_(
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 ///////////////////////////////////////////////////////////////////////////////
72 // StickyKeysHandler
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),
78 delegate_(delegate) {
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_) {
94 case DISABLED:
95 return HandleDisabledState(event);
96 case ENABLED:
97 return HandleEnabledState(event);
98 case LOCKED:
99 return HandleLockedState(event);
101 NOTREACHED();
102 return false;
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);
120 } else {
121 return event->type() == ui::ET_KEY_PRESSED ?
122 NORMAL_KEY_DOWN : NORMAL_KEY_UP;
125 if (is_target_key) {
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());
138 return true;
139 case TARGET_MODIFIER_DOWN:
140 case NORMAL_KEY_DOWN:
141 case NORMAL_KEY_UP:
142 case OTHER_MODIFIER_DOWN:
143 case OTHER_MODIFIER_UP:
144 return false;
146 NOTREACHED();
147 return false;
150 bool StickyKeysHandler::HandleEnabledState(ui::KeyEvent* event) {
151 switch (TranslateKeyEvent(event)) {
152 case NORMAL_KEY_UP:
153 case TARGET_MODIFIER_DOWN:
154 return true;
155 case TARGET_MODIFIER_UP:
156 current_state_ = LOCKED;
157 modifier_up_event_.reset();
158 return true;
159 case NORMAL_KEY_DOWN: {
160 DCHECK(modifier_up_event_.get());
161 aura::Window* target = static_cast<aura::Window*>(event->target());
162 DCHECK(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;
172 return true;
174 case OTHER_MODIFIER_DOWN:
175 case OTHER_MODIFIER_UP:
176 return false;
178 NOTREACHED();
179 return false;
182 bool StickyKeysHandler::HandleLockedState(ui::KeyEvent* event) {
183 switch (TranslateKeyEvent(event)) {
184 case TARGET_MODIFIER_DOWN:
185 return true;
186 case TARGET_MODIFIER_UP:
187 current_state_ = DISABLED;
188 return false;
189 case NORMAL_KEY_DOWN:
190 case NORMAL_KEY_UP:
191 AppendModifier(event);
192 return false;
193 case OTHER_MODIFIER_DOWN:
194 case OTHER_MODIFIER_UP:
195 return false;
197 NOTREACHED();
198 return false;
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;
207 break;
208 case ui::EF_ALT_DOWN:
209 xkey->state |= Mod1Mask;
210 break;
211 case ui::EF_SHIFT_DOWN:
212 xkey->state |= ShiftMask;
213 break;
214 default:
215 NOTREACHED();
217 event->set_flags(event->flags() | modifier_flag_);
218 event->set_character(ui::GetCharacterFromKeyCode(event->key_code(),
219 event->flags()));
220 event->NormalizeFlags();
223 } // namespace ash