1// Copyright (c) 2012 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 "chrome/browser/chromeos/system_key_event_listener.h" 6 7#define XK_MISCELLANY 1 8#include <X11/keysymdef.h> 9#include <X11/XF86keysym.h> 10#include <X11/XKBlib.h> 11#undef Status 12 13#include "base/message_loop/message_loop.h" 14#include "chromeos/ime/input_method_manager.h" 15#include "chromeos/ime/xkeyboard.h" 16#include "ui/base/x/x11_util.h" 17 18namespace chromeos { 19 20namespace { 21static SystemKeyEventListener* g_system_key_event_listener = NULL; 22} // namespace 23 24// static 25void SystemKeyEventListener::Initialize() { 26 CHECK(!g_system_key_event_listener); 27 g_system_key_event_listener = new SystemKeyEventListener(); 28} 29 30// static 31void SystemKeyEventListener::Shutdown() { 32 // We may call Shutdown without calling Initialize, e.g. if we exit early. 33 if (g_system_key_event_listener) { 34 delete g_system_key_event_listener; 35 g_system_key_event_listener = NULL; 36 } 37} 38 39// static 40SystemKeyEventListener* SystemKeyEventListener::GetInstance() { 41 return g_system_key_event_listener; 42} 43 44SystemKeyEventListener::SystemKeyEventListener() 45 : stopped_(false), 46 num_lock_mask_(0), 47 pressed_modifiers_(0), 48 xkb_event_base_(0) { 49 input_method::XKeyboard* xkeyboard = 50 input_method::InputMethodManager::Get()->GetXKeyboard(); 51 num_lock_mask_ = xkeyboard->GetNumLockMask(); 52 xkeyboard->GetLockedModifiers(&caps_lock_is_on_, NULL); 53 54 Display* display = ui::GetXDisplay(); 55 int xkb_major_version = XkbMajorVersion; 56 int xkb_minor_version = XkbMinorVersion; 57 if (!XkbQueryExtension(display, 58 NULL, // opcode_return 59 &xkb_event_base_, 60 NULL, // error_return 61 &xkb_major_version, 62 &xkb_minor_version)) { 63 LOG(WARNING) << "Could not query Xkb extension"; 64 } 65 66 if (!XkbSelectEvents(display, XkbUseCoreKbd, 67 XkbStateNotifyMask, 68 XkbStateNotifyMask)) { 69 LOG(WARNING) << "Could not install Xkb Indicator observer"; 70 } 71 72 base::MessageLoopForUI::current()->AddObserver(this); 73} 74 75SystemKeyEventListener::~SystemKeyEventListener() { 76 Stop(); 77} 78 79void SystemKeyEventListener::Stop() { 80 if (stopped_) 81 return; 82 base::MessageLoopForUI::current()->RemoveObserver(this); 83 stopped_ = true; 84} 85 86void SystemKeyEventListener::AddCapsLockObserver(CapsLockObserver* observer) { 87 caps_lock_observers_.AddObserver(observer); 88} 89 90void SystemKeyEventListener::AddModifiersObserver(ModifiersObserver* observer) { 91 modifiers_observers_.AddObserver(observer); 92} 93 94void SystemKeyEventListener::RemoveCapsLockObserver( 95 CapsLockObserver* observer) { 96 caps_lock_observers_.RemoveObserver(observer); 97} 98 99void SystemKeyEventListener::RemoveModifiersObserver( 100 ModifiersObserver* observer) { 101 modifiers_observers_.RemoveObserver(observer); 102} 103 104base::EventStatus SystemKeyEventListener::WillProcessEvent( 105 const base::NativeEvent& event) { 106 return ProcessedXEvent(event) ? base::EVENT_HANDLED : base::EVENT_CONTINUE; 107} 108 109void SystemKeyEventListener::DidProcessEvent(const base::NativeEvent& event) { 110} 111 112void SystemKeyEventListener::OnCapsLock(bool enabled) { 113 FOR_EACH_OBSERVER(CapsLockObserver, 114 caps_lock_observers_, 115 OnCapsLockChange(enabled)); 116} 117 118void SystemKeyEventListener::OnModifiers(int state) { 119 FOR_EACH_OBSERVER(ModifiersObserver, 120 modifiers_observers_, 121 OnModifiersChange(state)); 122} 123 124bool SystemKeyEventListener::ProcessedXEvent(XEvent* xevent) { 125 input_method::InputMethodManager* input_method_manager = 126 input_method::InputMethodManager::Get(); 127 128 if (xevent->type == xkb_event_base_) { 129 // TODO(yusukes): Move this part to aura::RootWindowHost. 130 XkbEvent* xkey_event = reinterpret_cast<XkbEvent*>(xevent); 131 if (xkey_event->any.xkb_type == XkbStateNotify) { 132 const bool caps_lock_enabled = (xkey_event->state.locked_mods) & LockMask; 133 if (caps_lock_is_on_ != caps_lock_enabled) { 134 caps_lock_is_on_ = caps_lock_enabled; 135 OnCapsLock(caps_lock_is_on_); 136 } 137 if (xkey_event->state.mods) { 138 // TODO(yusukes,adlr): Let the user know that num lock is unsupported. 139 // Force turning off Num Lock (crosbug.com/29169) 140 input_method_manager->GetXKeyboard()->SetLockedModifiers( 141 input_method::kDontChange /* caps lock */, 142 input_method::kDisableLock /* num lock */); 143 } 144 int current_modifiers = 0; 145 if (xkey_event->state.mods & ShiftMask) 146 current_modifiers |= ModifiersObserver::SHIFT_PRESSED; 147 if (xkey_event->state.mods & ControlMask) 148 current_modifiers |= ModifiersObserver::CTRL_PRESSED; 149 if (xkey_event->state.mods & Mod1Mask) 150 current_modifiers |= ModifiersObserver::ALT_PRESSED; 151 if (current_modifiers != pressed_modifiers_) { 152 pressed_modifiers_ = current_modifiers; 153 OnModifiers(pressed_modifiers_); 154 } 155 return true; 156 } 157 } 158 return false; 159} 160 161} // namespace chromeos 162