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.
5 #include "chrome/browser/chromeos/system_key_event_listener.h"
7 #define XK_MISCELLANY 1
8 #include <X11/keysymdef.h>
9 #include <X11/XF86keysym.h>
10 #include <X11/XKBlib.h>
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"
21 static SystemKeyEventListener* g_system_key_event_listener = NULL;
25 void SystemKeyEventListener::Initialize() {
26 CHECK(!g_system_key_event_listener);
27 g_system_key_event_listener = new SystemKeyEventListener();
31 void 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;
40 SystemKeyEventListener* SystemKeyEventListener::GetInstance() {
41 return g_system_key_event_listener;
44 SystemKeyEventListener::SystemKeyEventListener()
47 pressed_modifiers_(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);
54 XDisplay* display = gfx::GetXDisplay();
55 int xkb_major_version = XkbMajorVersion;
56 int xkb_minor_version = XkbMinorVersion;
57 if (!XkbQueryExtension(display,
58 NULL, // opcode_return
62 &xkb_minor_version)) {
63 LOG(WARNING) << "Could not query Xkb extension";
66 if (!XkbSelectEvents(display, XkbUseCoreKbd,
68 XkbStateNotifyMask)) {
69 LOG(WARNING) << "Could not install Xkb Indicator observer";
72 base::MessageLoopForUI::current()->AddObserver(this);
75 SystemKeyEventListener::~SystemKeyEventListener() {
79 void SystemKeyEventListener::Stop() {
82 base::MessageLoopForUI::current()->RemoveObserver(this);
86 void SystemKeyEventListener::AddCapsLockObserver(CapsLockObserver* observer) {
87 caps_lock_observers_.AddObserver(observer);
90 void SystemKeyEventListener::AddModifiersObserver(ModifiersObserver* observer) {
91 modifiers_observers_.AddObserver(observer);
94 void SystemKeyEventListener::RemoveCapsLockObserver(
95 CapsLockObserver* observer) {
96 caps_lock_observers_.RemoveObserver(observer);
99 void SystemKeyEventListener::RemoveModifiersObserver(
100 ModifiersObserver* observer) {
101 modifiers_observers_.RemoveObserver(observer);
104 base::EventStatus SystemKeyEventListener::WillProcessEvent(
105 const base::NativeEvent& event) {
106 return ProcessedXEvent(event) ? base::EVENT_HANDLED : base::EVENT_CONTINUE;
109 void SystemKeyEventListener::DidProcessEvent(const base::NativeEvent& event) {
112 void SystemKeyEventListener::OnCapsLock(bool enabled) {
113 FOR_EACH_OBSERVER(CapsLockObserver,
114 caps_lock_observers_,
115 OnCapsLockChange(enabled));
118 void SystemKeyEventListener::OnModifiers(int state) {
119 FOR_EACH_OBSERVER(ModifiersObserver,
120 modifiers_observers_,
121 OnModifiersChange(state));
124 bool SystemKeyEventListener::ProcessedXEvent(XEvent* xevent) {
125 input_method::InputMethodManager* input_method_manager =
126 input_method::InputMethodManager::Get();
128 if (xevent->type == xkb_event_base_) {
129 // TODO(yusukes): Move this part to aura::WindowTreeHost.
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_);
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 */);
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_);
161 } // namespace chromeos