1c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// found in the LICENSE file.
4c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
5c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_x11.h"
65c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
7c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include <set>
8c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include <X11/extensions/XInput2.h>
9c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include <X11/Xlib.h>
10c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
11c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ash/display/display_controller.h"
12c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ash/screen_util.h"
13c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ash/shell.h"
14c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/memory/scoped_ptr.h"
15c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/strings/string_util.h"
16c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/aura/client/screen_position_client.h"
17c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/aura/env.h"
18c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/aura/window.h"
19c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/aura/window_event_dispatcher.h"
20c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/aura/window_tree_host.h"
21c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/events/event.h"
22c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/events/event_utils.h"
23c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/events/keycodes/keyboard_codes_posix.h"
24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/events/platform/platform_event_source.h"
25c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/events/x/device_data_manager_x11.h"
265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/events/x/device_list_cache_x.h"
27c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/gfx/x/x11_types.h"
28c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
29c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochnamespace ash {
30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
31c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochnamespace {
32c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
33c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// The name of the xinput device corresponding to the internal touchpad.
34c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst char kInternalTouchpadName[] = "Elan Touchpad";
35c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
36c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// The name of the xinput device corresponding to the internal keyboard.
37c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst char kInternalKeyboardName[] = "AT Translated Set 2 keyboard";
38c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
39c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Repeated key events have their source set to the core keyboard device.
40c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// These must be disabled also until http://crbug.com/402898 is resolved.
41c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst char kCoreKeyboardName[] = "Virtual core keyboard";
42c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
43c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Device id used to indicate that a device has not been detected.
44c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst int kDeviceIdNone = -1;
45c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
46c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochgfx::Point GetMouseLocationInScreen() {
47c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return aura::Env::GetInstance()->last_mouse_location();
48c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
49c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
50c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid SetMouseLocationInScreen(const gfx::Point& screen_location) {
51c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  gfx::Display display = ash::ScreenUtil::FindDisplayContainingPoint(
52c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      screen_location);
53c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!display.is_valid())
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
55c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  aura::Window* root_window = Shell::GetInstance()->display_controller()->
56c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      GetRootWindowForDisplayId(display.id());
57c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  gfx::Point host_location(screen_location);
58c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  aura::client::ScreenPositionClient* client =
59c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      aura::client::GetScreenPositionClient(root_window);
60c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (client)
61c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    client->ConvertPointFromScreen(root_window, &host_location);
62c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  root_window->GetHost()->MoveCursorTo(host_location);
63c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
64c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
65c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}  // namespace
66c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
67c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochScopedDisableInternalMouseAndKeyboardX11::
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ScopedDisableInternalMouseAndKeyboardX11()
69c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    : touchpad_device_id_(kDeviceIdNone),
70c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      keyboard_device_id_(kDeviceIdNone),
71c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      core_keyboard_device_id_(kDeviceIdNone),
72c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      last_mouse_location_(GetMouseLocationInScreen()) {
73c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
74c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ui::DeviceDataManagerX11* device_data_manager =
75c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      static_cast<ui::DeviceDataManagerX11*>(
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          ui::DeviceDataManager::GetInstance());
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (device_data_manager->IsXInput2Available()) {
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    XIDeviceList xi_dev_list = ui::DeviceListCacheX::GetInstance()->
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        GetXI2DeviceList(gfx::GetXDisplay());
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for (int i = 0; i < xi_dev_list.count; ++i) {
816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      std::string device_name(xi_dev_list[i].name);
820de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      base::TrimWhitespaceASCII(device_name, base::TRIM_TRAILING, &device_name);
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (device_name == kInternalTouchpadName) {
84c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        touchpad_device_id_ = xi_dev_list[i].deviceid;
85c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        device_data_manager->DisableDevice(touchpad_device_id_);
86c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      } else if (device_name == kInternalKeyboardName) {
87c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        keyboard_device_id_ = xi_dev_list[i].deviceid;
88c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        device_data_manager->DisableDevice(keyboard_device_id_);
89c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      } else if (device_name == kCoreKeyboardName) {
90c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        core_keyboard_device_id_ = xi_dev_list[i].deviceid;
91c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        device_data_manager->DisableDevice(core_keyboard_device_id_);
92c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      }
93c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    }
94c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
95c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Allow the accessible keys present on the side of some devices to continue
96c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // working.
97c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<std::set<ui::KeyboardCode> > excepted_keys(
98c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      new std::set<ui::KeyboardCode>);
99c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  excepted_keys->insert(ui::VKEY_VOLUME_DOWN);
100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  excepted_keys->insert(ui::VKEY_VOLUME_UP);
101c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  excepted_keys->insert(ui::VKEY_POWER);
102c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  device_data_manager->SetDisabledKeyboardAllowedKeys(excepted_keys.Pass());
103c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
104c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
105c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
106c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochScopedDisableInternalMouseAndKeyboardX11::
107c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    ~ScopedDisableInternalMouseAndKeyboardX11() {
108c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ui::DeviceDataManagerX11* device_data_manager =
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      static_cast<ui::DeviceDataManagerX11*>(
110c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          ui::DeviceDataManager::GetInstance());
111c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (touchpad_device_id_ != kDeviceIdNone)
112c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    device_data_manager->EnableDevice(touchpad_device_id_);
113c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (keyboard_device_id_ != kDeviceIdNone)
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    device_data_manager->EnableDevice(keyboard_device_id_);
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (core_keyboard_device_id_ != kDeviceIdNone)
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    device_data_manager->EnableDevice(core_keyboard_device_id_);
117c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  device_data_manager->SetDisabledKeyboardAllowedKeys(
118c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      scoped_ptr<std::set<ui::KeyboardCode> >());
119c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this);
120c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
121c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
122c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ScopedDisableInternalMouseAndKeyboardX11::WillProcessEvent(
123c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const ui::PlatformEvent& event) {
124c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
125c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
126c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ScopedDisableInternalMouseAndKeyboardX11::DidProcessEvent(
127c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const ui::PlatformEvent& event) {
128c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (event->type != GenericEvent)
129c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
130c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  XIDeviceEvent* xievent =
131c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      static_cast<XIDeviceEvent*>(event->xcookie.data);
132c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ui::DeviceDataManagerX11* device_data_manager =
133c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      static_cast<ui::DeviceDataManagerX11*>(
134c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          ui::DeviceDataManager::GetInstance());
135c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (xievent->evtype != XI_Motion ||
136c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      device_data_manager->IsFlingEvent(event) ||
137c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      device_data_manager->IsScrollEvent(event) ||
138c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      device_data_manager->IsCMTMetricsEvent(event)) {
139c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
140c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
141c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (xievent->sourceid == touchpad_device_id_) {
142c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // The cursor will have already moved even though the move event will be
143c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // blocked. Move the mouse cursor back to its last known location resulting
144c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // from an external mouse to prevent the internal touchpad from moving it.
145c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    SetMouseLocationInScreen(last_mouse_location_);
146c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  } else {
147c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // Track the last location seen from an external mouse event.
148c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    last_mouse_location_ = GetMouseLocationInScreen();
149c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
150c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
151c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
152c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}  // namespace ash
153c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch