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/events/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 "chromeos/ime/ime_keyboard.h"
14#include "chromeos/ime/input_method_manager.h"
15#include "ui/base/x/x11_util.h"
16#include "ui/events/platform/platform_event_source.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      xkb_event_base_(0) {
47  XDisplay* display = gfx::GetXDisplay();
48  int xkb_major_version = XkbMajorVersion;
49  int xkb_minor_version = XkbMinorVersion;
50  if (!XkbQueryExtension(display,
51                         NULL,  // opcode_return
52                         &xkb_event_base_,
53                         NULL,  // error_return
54                         &xkb_major_version,
55                         &xkb_minor_version)) {
56    LOG(WARNING) << "Could not query Xkb extension";
57  }
58
59  if (!XkbSelectEvents(display, XkbUseCoreKbd,
60                       XkbStateNotifyMask,
61                       XkbStateNotifyMask)) {
62    LOG(WARNING) << "Could not install Xkb Indicator observer";
63  }
64
65  ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
66}
67
68SystemKeyEventListener::~SystemKeyEventListener() {
69  Stop();
70}
71
72void SystemKeyEventListener::Stop() {
73  if (stopped_)
74    return;
75  ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this);
76  stopped_ = true;
77}
78
79void SystemKeyEventListener::WillProcessEvent(const base::NativeEvent& event) {
80  ProcessedXEvent(event);
81}
82
83void SystemKeyEventListener::DidProcessEvent(const base::NativeEvent& event) {
84}
85
86void SystemKeyEventListener::ProcessedXEvent(XEvent* xevent) {
87  input_method::InputMethodManager* input_method_manager =
88      input_method::InputMethodManager::Get();
89
90  if (xevent->type == xkb_event_base_) {
91    // TODO(yusukes): Move this part to aura::WindowTreeHost.
92    XkbEvent* xkey_event = reinterpret_cast<XkbEvent*>(xevent);
93    if (xkey_event->any.xkb_type == XkbStateNotify) {
94      if (xkey_event->state.mods) {
95        // TODO(yusukes,adlr): Let the user know that num lock is unsupported.
96        // Force turning off Num Lock (crosbug.com/29169)
97        input_method_manager->GetImeKeyboard()->DisableNumLock();
98      }
99    }
100  }
101}
102
103}  // namespace chromeos
104