Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / system_key_event_listener.cc
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
18 namespace chromeos {
19
20 namespace {
21 static SystemKeyEventListener* g_system_key_event_listener = NULL;
22 }  // namespace
23
24 // static
25 void SystemKeyEventListener::Initialize() {
26   CHECK(!g_system_key_event_listener);
27   g_system_key_event_listener = new SystemKeyEventListener();
28 }
29
30 // static
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;
36   }
37 }
38
39 // static
40 SystemKeyEventListener* SystemKeyEventListener::GetInstance() {
41   return g_system_key_event_listener;
42 }
43
44 SystemKeyEventListener::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   XDisplay* display = gfx::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
75 SystemKeyEventListener::~SystemKeyEventListener() {
76   Stop();
77 }
78
79 void SystemKeyEventListener::Stop() {
80   if (stopped_)
81     return;
82   base::MessageLoopForUI::current()->RemoveObserver(this);
83   stopped_ = true;
84 }
85
86 void SystemKeyEventListener::AddCapsLockObserver(CapsLockObserver* observer) {
87   caps_lock_observers_.AddObserver(observer);
88 }
89
90 void SystemKeyEventListener::AddModifiersObserver(ModifiersObserver* observer) {
91   modifiers_observers_.AddObserver(observer);
92 }
93
94 void SystemKeyEventListener::RemoveCapsLockObserver(
95     CapsLockObserver* observer) {
96   caps_lock_observers_.RemoveObserver(observer);
97 }
98
99 void SystemKeyEventListener::RemoveModifiersObserver(
100     ModifiersObserver* observer) {
101   modifiers_observers_.RemoveObserver(observer);
102 }
103
104 base::EventStatus SystemKeyEventListener::WillProcessEvent(
105     const base::NativeEvent& event) {
106   return ProcessedXEvent(event) ? base::EVENT_HANDLED : base::EVENT_CONTINUE;
107 }
108
109 void SystemKeyEventListener::DidProcessEvent(const base::NativeEvent& event) {
110 }
111
112 void SystemKeyEventListener::OnCapsLock(bool enabled) {
113   FOR_EACH_OBSERVER(CapsLockObserver,
114                     caps_lock_observers_,
115                     OnCapsLockChange(enabled));
116 }
117
118 void SystemKeyEventListener::OnModifiers(int state) {
119   FOR_EACH_OBSERVER(ModifiersObserver,
120                     modifiers_observers_,
121                     OnModifiersChange(state));
122 }
123
124 bool 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::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_);
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