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 #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