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/xinput_hierarchy_changed_event_listener.h"
8 #include <X11/extensions/XInput2.h>
10 #include "chromeos/ime/input_method_manager.h"
11 #include "chromeos/ime/xkeyboard.h"
12 #include "ui/base/x/x11_util.h"
17 // Gets the major opcode for XInput2. Returns -1 on error.
18 int GetXInputOpCode() {
19 static const char kExtensionName[] = "XInputExtension";
25 gfx::GetXDisplay(), kExtensionName, &xi_opcode, &event, &error)) {
26 VLOG(1) << "X Input extension not available: error=" << error;
32 // Checks the |event| and asynchronously sets the XKB layout when necessary.
33 void HandleHierarchyChangedEvent(
34 XIHierarchyEvent* event,
35 ObserverList<DeviceHierarchyObserver>* observer_list) {
36 if (!(event->flags & (XISlaveAdded | XISlaveRemoved)))
39 bool update_keyboard_status = false;
40 for (int i = 0; i < event->num_info; ++i) {
41 XIHierarchyInfo* info = &event->info[i];
42 if ((info->flags & XISlaveAdded) && (info->use == XIFloatingSlave)) {
43 FOR_EACH_OBSERVER(DeviceHierarchyObserver,
45 DeviceAdded(info->deviceid));
46 update_keyboard_status = true;
47 } else if (info->flags & XISlaveRemoved) {
48 // Can't check info->use here; it appears to always be 0.
49 FOR_EACH_OBSERVER(DeviceHierarchyObserver,
51 DeviceRemoved(info->deviceid));
55 if (update_keyboard_status) {
56 chromeos::input_method::InputMethodManager* input_method_manager =
57 chromeos::input_method::InputMethodManager::Get();
58 chromeos::input_method::XKeyboard* xkeyboard =
59 input_method_manager->GetXKeyboard();
60 xkeyboard->ReapplyCurrentModifierLockStatus();
61 xkeyboard->ReapplyCurrentKeyboardLayout();
68 XInputHierarchyChangedEventListener*
69 XInputHierarchyChangedEventListener::GetInstance() {
70 return Singleton<XInputHierarchyChangedEventListener>::get();
73 XInputHierarchyChangedEventListener::XInputHierarchyChangedEventListener()
75 xiopcode_(GetXInputOpCode()) {
79 XInputHierarchyChangedEventListener::~XInputHierarchyChangedEventListener() {
83 void XInputHierarchyChangedEventListener::Stop() {
92 void XInputHierarchyChangedEventListener::AddObserver(
93 DeviceHierarchyObserver* observer) {
94 observer_list_.AddObserver(observer);
97 void XInputHierarchyChangedEventListener::RemoveObserver(
98 DeviceHierarchyObserver* observer) {
99 observer_list_.RemoveObserver(observer);
102 bool XInputHierarchyChangedEventListener::ProcessedXEvent(XEvent* xevent) {
103 if ((xevent->xcookie.type != GenericEvent) ||
104 (xevent->xcookie.extension != xiopcode_)) {
108 XGenericEventCookie* cookie = &(xevent->xcookie);
109 bool handled = false;
111 if (cookie->evtype == XI_HierarchyChanged) {
112 XIHierarchyEvent* event = static_cast<XIHierarchyEvent*>(cookie->data);
113 HandleHierarchyChangedEvent(event, &observer_list_);
114 if (event->flags & XIDeviceEnabled || event->flags & XIDeviceDisabled)
115 NotifyDeviceHierarchyChanged();
117 } else if (cookie->evtype == XI_KeyPress || cookie->evtype == XI_KeyRelease) {
118 XIDeviceEvent* xiev = reinterpret_cast<XIDeviceEvent*>(cookie->data);
119 if (xiev->deviceid == xiev->sourceid) {
120 FOR_EACH_OBSERVER(DeviceHierarchyObserver,
122 DeviceKeyPressedOrReleased(xiev->deviceid));
130 void XInputHierarchyChangedEventListener::NotifyDeviceHierarchyChanged() {
131 FOR_EACH_OBSERVER(DeviceHierarchyObserver,
133 DeviceHierarchyChanged());
136 } // namespace chromeos