1 // Copyright 2014 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 "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_x11.h"
8 #include <X11/extensions/XInput2.h>
11 #include "ash/display/display_controller.h"
12 #include "ash/screen_util.h"
13 #include "ash/shell.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/strings/string_util.h"
16 #include "ui/aura/client/cursor_client.h"
17 #include "ui/aura/client/screen_position_client.h"
18 #include "ui/aura/env.h"
19 #include "ui/aura/window.h"
20 #include "ui/aura/window_event_dispatcher.h"
21 #include "ui/aura/window_tree_host.h"
22 #include "ui/events/devices/input_device.h"
23 #include "ui/events/devices/keyboard_device.h"
24 #include "ui/events/devices/x11/device_data_manager_x11.h"
25 #include "ui/events/devices/x11/device_list_cache_x11.h"
26 #include "ui/events/event.h"
27 #include "ui/events/event_utils.h"
28 #include "ui/events/keycodes/keyboard_codes_posix.h"
29 #include "ui/events/platform/platform_event_source.h"
30 #include "ui/gfx/x/x11_types.h"
36 // The name of the xinput device corresponding to the internal touchpad.
37 const char kInternalTouchpadName
[] = "Elan Touchpad";
39 // Repeated key events have their source set to the core keyboard device.
40 // These must be disabled also until http://crbug.com/402898 is resolved.
41 const char kCoreKeyboardName
[] = "Virtual core keyboard";
43 // Device id used to indicate that a device has not been detected.
44 const int kDeviceIdNone
= -1;
46 gfx::Point
GetMouseLocationInScreen() {
47 return aura::Env::GetInstance()->last_mouse_location();
50 void SetMouseLocationInScreen(const gfx::Point
& screen_location
) {
51 gfx::Display display
= ash::ScreenUtil::FindDisplayContainingPoint(
53 if (!display
.is_valid())
55 aura::Window
* root_window
= Shell::GetInstance()->display_controller()->
56 GetRootWindowForDisplayId(display
.id());
57 gfx::Point
host_location(screen_location
);
58 aura::client::ScreenPositionClient
* client
=
59 aura::client::GetScreenPositionClient(root_window
);
61 client
->ConvertPointFromScreen(root_window
, &host_location
);
62 root_window
->GetHost()->MoveCursorTo(host_location
);
67 ScopedDisableInternalMouseAndKeyboardX11::
68 ScopedDisableInternalMouseAndKeyboardX11()
69 : touchpad_device_id_(kDeviceIdNone
),
70 keyboard_device_id_(kDeviceIdNone
),
71 core_keyboard_device_id_(kDeviceIdNone
),
72 last_mouse_location_(GetMouseLocationInScreen()) {
74 ui::DeviceDataManagerX11
* device_data_manager
=
75 static_cast<ui::DeviceDataManagerX11
*>(
76 ui::DeviceDataManager::GetInstance());
77 if (device_data_manager
->IsXInput2Available()) {
78 const XIDeviceList
& xi_dev_list
=
79 ui::DeviceListCacheX11::GetInstance()->GetXI2DeviceList(
81 for (int i
= 0; i
< xi_dev_list
.count
; ++i
) {
82 std::string
device_name(xi_dev_list
[i
].name
);
83 base::TrimWhitespaceASCII(device_name
, base::TRIM_TRAILING
, &device_name
);
84 if (device_name
== kInternalTouchpadName
) {
85 touchpad_device_id_
= xi_dev_list
[i
].deviceid
;
86 device_data_manager
->DisableDevice(touchpad_device_id_
);
87 aura::client::GetCursorClient(
88 Shell::GetInstance()->GetPrimaryRootWindow())->HideCursor();
89 } else if (device_name
== kCoreKeyboardName
) {
90 core_keyboard_device_id_
= xi_dev_list
[i
].deviceid
;
91 device_data_manager
->DisableDevice(core_keyboard_device_id_
);
95 for (const ui::KeyboardDevice
& device
:
96 device_data_manager
->keyboard_devices()) {
97 if (device
.type
== ui::InputDeviceType::INPUT_DEVICE_INTERNAL
) {
98 keyboard_device_id_
= device
.id
;
99 device_data_manager
->DisableDevice(keyboard_device_id_
);
104 // Allow the accessible keys present on the side of some devices to continue
106 scoped_ptr
<std::set
<ui::KeyboardCode
> > excepted_keys(
107 new std::set
<ui::KeyboardCode
>);
108 excepted_keys
->insert(ui::VKEY_VOLUME_DOWN
);
109 excepted_keys
->insert(ui::VKEY_VOLUME_UP
);
110 excepted_keys
->insert(ui::VKEY_POWER
);
111 device_data_manager
->SetDisabledKeyboardAllowedKeys(excepted_keys
.Pass());
112 ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
115 ScopedDisableInternalMouseAndKeyboardX11::
116 ~ScopedDisableInternalMouseAndKeyboardX11() {
117 ui::DeviceDataManagerX11
* device_data_manager
=
118 static_cast<ui::DeviceDataManagerX11
*>(
119 ui::DeviceDataManager::GetInstance());
120 if (touchpad_device_id_
!= kDeviceIdNone
)
121 device_data_manager
->EnableDevice(touchpad_device_id_
);
122 if (keyboard_device_id_
!= kDeviceIdNone
)
123 device_data_manager
->EnableDevice(keyboard_device_id_
);
124 if (core_keyboard_device_id_
!= kDeviceIdNone
)
125 device_data_manager
->EnableDevice(core_keyboard_device_id_
);
126 device_data_manager
->SetDisabledKeyboardAllowedKeys(
127 scoped_ptr
<std::set
<ui::KeyboardCode
> >());
128 ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this);
131 void ScopedDisableInternalMouseAndKeyboardX11::WillProcessEvent(
132 const ui::PlatformEvent
& event
) {
135 void ScopedDisableInternalMouseAndKeyboardX11::DidProcessEvent(
136 const ui::PlatformEvent
& event
) {
137 if (event
->type
!= GenericEvent
)
139 XIDeviceEvent
* xievent
=
140 static_cast<XIDeviceEvent
*>(event
->xcookie
.data
);
141 ui::DeviceDataManagerX11
* device_data_manager
=
142 static_cast<ui::DeviceDataManagerX11
*>(
143 ui::DeviceDataManager::GetInstance());
144 if (xievent
->evtype
!= XI_Motion
||
145 device_data_manager
->IsFlingEvent(event
) ||
146 device_data_manager
->IsScrollEvent(event
) ||
147 device_data_manager
->IsCMTMetricsEvent(event
)) {
150 if (xievent
->sourceid
== touchpad_device_id_
) {
151 // The cursor will have already moved even though the move event will be
152 // blocked. Move the mouse cursor back to its last known location resulting
153 // from an external mouse to prevent the internal touchpad from moving it.
154 SetMouseLocationInScreen(last_mouse_location_
);
156 // Track the last location seen from an external mouse event.
157 last_mouse_location_
= GetMouseLocationInScreen();