15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/chromeos/events/system_key_event_listener.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define XK_MISCELLANY 1
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/keysymdef.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/XF86keysym.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/XKBlib.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef Status
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chromeos/ime/ime_keyboard.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/ime/input_method_manager.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/x/x11_util.h"
16c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/events/platform/platform_event_source.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static SystemKeyEventListener* g_system_key_event_listener = NULL;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemKeyEventListener::Initialize() {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!g_system_key_event_listener);
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_system_key_event_listener = new SystemKeyEventListener();
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemKeyEventListener::Shutdown() {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We may call Shutdown without calling Initialize, e.g. if we exit early.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_system_key_event_listener) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete g_system_key_event_listener;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_system_key_event_listener = NULL;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SystemKeyEventListener* SystemKeyEventListener::GetInstance() {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_system_key_event_listener;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SystemKeyEventListener::SystemKeyEventListener()
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : stopped_(false),
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      xkb_event_base_(0) {
4768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XDisplay* display = gfx::GetXDisplay();
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int xkb_major_version = XkbMajorVersion;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int xkb_minor_version = XkbMinorVersion;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!XkbQueryExtension(display,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         NULL,  // opcode_return
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         &xkb_event_base_,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         NULL,  // error_return
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         &xkb_major_version,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         &xkb_minor_version)) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Could not query Xkb extension";
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!XkbSelectEvents(display, XkbUseCoreKbd,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       XkbStateNotifyMask,
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       XkbStateNotifyMask)) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Could not install Xkb Indicator observer";
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SystemKeyEventListener::~SystemKeyEventListener() {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Stop();
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemKeyEventListener::Stop() {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stopped_)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
75c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stopped_ = true;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
79c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid SystemKeyEventListener::WillProcessEvent(const base::NativeEvent& event) {
80c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ProcessedXEvent(event);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SystemKeyEventListener::DidProcessEvent(const base::NativeEvent& event) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
86c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid SystemKeyEventListener::ProcessedXEvent(XEvent* xevent) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  input_method::InputMethodManager* input_method_manager =
88a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      input_method::InputMethodManager::Get();
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (xevent->type == xkb_event_base_) {
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // TODO(yusukes): Move this part to aura::WindowTreeHost.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XkbEvent* xkey_event = reinterpret_cast<XkbEvent*>(xevent);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (xkey_event->any.xkb_type == XkbStateNotify) {
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (xkey_event->state.mods) {
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // TODO(yusukes,adlr): Let the user know that num lock is unsupported.
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Force turning off Num Lock (crosbug.com/29169)
97a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        input_method_manager->GetImeKeyboard()->DisableNumLock();
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chromeos
104