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 #include "ash/wm/sticky_keys.h" 6 7 #include <X11/Xlib.h> 8 #undef RootWindow 9 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" 15 16 namespace ash { 17 18 namespace { 19 20 // An implementation of StickyKeysHandler::StickyKeysHandlerDelegate. 21 class StickyKeysHandlerDelegateImpl : 22 public StickyKeysHandler::StickyKeysHandlerDelegate { 23 public: 24 StickyKeysHandlerDelegateImpl(); 25 virtual ~StickyKeysHandlerDelegateImpl(); 26 27 // StickyKeysHandlerDelegate overrides. 28 virtual void DispatchKeyEvent(ui::KeyEvent* event, 29 aura::Window* target) OVERRIDE; 30 private: 31 DISALLOW_COPY_AND_ASSIGN(StickyKeysHandlerDelegateImpl); 32 }; 33 34 StickyKeysHandlerDelegateImpl::StickyKeysHandlerDelegateImpl() { 35 } 36 37 StickyKeysHandlerDelegateImpl::~StickyKeysHandlerDelegateImpl() { 38 } 39 40 void StickyKeysHandlerDelegateImpl::DispatchKeyEvent(ui::KeyEvent* event, 41 aura::Window* target) { 42 DCHECK(target); 43 target->GetRootWindow()->AsRootWindowHostDelegate()->OnHostKeyEvent(event); 44 } 45 46 } // namespace 47 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())) { 60 } 61 62 StickyKeys::~StickyKeys() { 63 } 64 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); 69 } 70 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) { 79 } 80 81 StickyKeysHandler::~StickyKeysHandler() { 82 } 83 84 StickyKeysHandler::StickyKeysHandlerDelegate::StickyKeysHandlerDelegate() { 85 } 86 87 StickyKeysHandler::StickyKeysHandlerDelegate::~StickyKeysHandlerDelegate() { 88 } 89 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); 100 } 101 NOTREACHED(); 102 return false; 103 } 104 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; 123 } 124 125 if (is_target_key) { 126 return event->type() == ui::ET_KEY_PRESSED ? 127 TARGET_MODIFIER_DOWN : TARGET_MODIFIER_UP; 128 } 129 return event->type() == ui::ET_KEY_PRESSED ? 130 OTHER_MODIFIER_DOWN : OTHER_MODIFIER_UP; 131 } 132 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; 145 } 146 NOTREACHED(); 147 return false; 148 } 149 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); 163 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; 173 } 174 case OTHER_MODIFIER_DOWN: 175 case OTHER_MODIFIER_UP: 176 return false; 177 } 178 NOTREACHED(); 179 return false; 180 } 181 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; 196 } 197 NOTREACHED(); 198 return false; 199 } 200 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(); 216 } 217 event->set_flags(event->flags() | modifier_flag_); 218 event->set_character(ui::GetCharacterFromKeyCode(event->key_code(), 219 event->flags())); 220 event->NormalizeFlags(); 221 } 222 223 } // namespace ash 224