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. 4 5#include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_x11.h" 6 7#include <set> 8#include <X11/extensions/XInput2.h> 9#include <X11/Xlib.h> 10 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/screen_position_client.h" 17#include "ui/aura/env.h" 18#include "ui/aura/window.h" 19#include "ui/aura/window_event_dispatcher.h" 20#include "ui/aura/window_tree_host.h" 21#include "ui/events/event.h" 22#include "ui/events/event_utils.h" 23#include "ui/events/keycodes/keyboard_codes_posix.h" 24#include "ui/events/platform/platform_event_source.h" 25#include "ui/events/x/device_data_manager_x11.h" 26#include "ui/events/x/device_list_cache_x.h" 27#include "ui/gfx/x/x11_types.h" 28 29namespace ash { 30 31namespace { 32 33// The name of the xinput device corresponding to the internal touchpad. 34const char kInternalTouchpadName[] = "Elan Touchpad"; 35 36// The name of the xinput device corresponding to the internal keyboard. 37const char kInternalKeyboardName[] = "AT Translated Set 2 keyboard"; 38 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. 41const char kCoreKeyboardName[] = "Virtual core keyboard"; 42 43// Device id used to indicate that a device has not been detected. 44const int kDeviceIdNone = -1; 45 46gfx::Point GetMouseLocationInScreen() { 47 return aura::Env::GetInstance()->last_mouse_location(); 48} 49 50void SetMouseLocationInScreen(const gfx::Point& screen_location) { 51 gfx::Display display = ash::ScreenUtil::FindDisplayContainingPoint( 52 screen_location); 53 if (!display.is_valid()) 54 return; 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); 60 if (client) 61 client->ConvertPointFromScreen(root_window, &host_location); 62 root_window->GetHost()->MoveCursorTo(host_location); 63} 64 65} // namespace 66 67ScopedDisableInternalMouseAndKeyboardX11:: 68 ScopedDisableInternalMouseAndKeyboardX11() 69 : touchpad_device_id_(kDeviceIdNone), 70 keyboard_device_id_(kDeviceIdNone), 71 core_keyboard_device_id_(kDeviceIdNone), 72 last_mouse_location_(GetMouseLocationInScreen()) { 73 74 ui::DeviceDataManagerX11* device_data_manager = 75 static_cast<ui::DeviceDataManagerX11*>( 76 ui::DeviceDataManager::GetInstance()); 77 if (device_data_manager->IsXInput2Available()) { 78 XIDeviceList xi_dev_list = ui::DeviceListCacheX::GetInstance()-> 79 GetXI2DeviceList(gfx::GetXDisplay()); 80 for (int i = 0; i < xi_dev_list.count; ++i) { 81 std::string device_name(xi_dev_list[i].name); 82 base::TrimWhitespaceASCII(device_name, base::TRIM_TRAILING, &device_name); 83 if (device_name == kInternalTouchpadName) { 84 touchpad_device_id_ = xi_dev_list[i].deviceid; 85 device_data_manager->DisableDevice(touchpad_device_id_); 86 } else if (device_name == kInternalKeyboardName) { 87 keyboard_device_id_ = xi_dev_list[i].deviceid; 88 device_data_manager->DisableDevice(keyboard_device_id_); 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_); 92 } 93 } 94 } 95 // Allow the accessible keys present on the side of some devices to continue 96 // working. 97 scoped_ptr<std::set<ui::KeyboardCode> > excepted_keys( 98 new std::set<ui::KeyboardCode>); 99 excepted_keys->insert(ui::VKEY_VOLUME_DOWN); 100 excepted_keys->insert(ui::VKEY_VOLUME_UP); 101 excepted_keys->insert(ui::VKEY_POWER); 102 device_data_manager->SetDisabledKeyboardAllowedKeys(excepted_keys.Pass()); 103 ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this); 104} 105 106ScopedDisableInternalMouseAndKeyboardX11:: 107 ~ScopedDisableInternalMouseAndKeyboardX11() { 108 ui::DeviceDataManagerX11* device_data_manager = 109 static_cast<ui::DeviceDataManagerX11*>( 110 ui::DeviceDataManager::GetInstance()); 111 if (touchpad_device_id_ != kDeviceIdNone) 112 device_data_manager->EnableDevice(touchpad_device_id_); 113 if (keyboard_device_id_ != kDeviceIdNone) 114 device_data_manager->EnableDevice(keyboard_device_id_); 115 if (core_keyboard_device_id_ != kDeviceIdNone) 116 device_data_manager->EnableDevice(core_keyboard_device_id_); 117 device_data_manager->SetDisabledKeyboardAllowedKeys( 118 scoped_ptr<std::set<ui::KeyboardCode> >()); 119 ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this); 120} 121 122void ScopedDisableInternalMouseAndKeyboardX11::WillProcessEvent( 123 const ui::PlatformEvent& event) { 124} 125 126void ScopedDisableInternalMouseAndKeyboardX11::DidProcessEvent( 127 const ui::PlatformEvent& event) { 128 if (event->type != GenericEvent) 129 return; 130 XIDeviceEvent* xievent = 131 static_cast<XIDeviceEvent*>(event->xcookie.data); 132 ui::DeviceDataManagerX11* device_data_manager = 133 static_cast<ui::DeviceDataManagerX11*>( 134 ui::DeviceDataManager::GetInstance()); 135 if (xievent->evtype != XI_Motion || 136 device_data_manager->IsFlingEvent(event) || 137 device_data_manager->IsScrollEvent(event) || 138 device_data_manager->IsCMTMetricsEvent(event)) { 139 return; 140 } 141 if (xievent->sourceid == touchpad_device_id_) { 142 // The cursor will have already moved even though the move event will be 143 // blocked. Move the mouse cursor back to its last known location resulting 144 // from an external mouse to prevent the internal touchpad from moving it. 145 SetMouseLocationInScreen(last_mouse_location_); 146 } else { 147 // Track the last location seen from an external mouse event. 148 last_mouse_location_ = GetMouseLocationInScreen(); 149 } 150} 151 152} // namespace ash 153