Home | History | Annotate | Download | only in maximize_mode
      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 
     29 namespace ash {
     30 
     31 namespace {
     32 
     33 // The name of the xinput device corresponding to the internal touchpad.
     34 const char kInternalTouchpadName[] = "Elan Touchpad";
     35 
     36 // The name of the xinput device corresponding to the internal keyboard.
     37 const 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.
     41 const char kCoreKeyboardName[] = "Virtual core keyboard";
     42 
     43 // Device id used to indicate that a device has not been detected.
     44 const int kDeviceIdNone = -1;
     45 
     46 gfx::Point GetMouseLocationInScreen() {
     47   return aura::Env::GetInstance()->last_mouse_location();
     48 }
     49 
     50 void 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 
     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()) {
     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 
    106 ScopedDisableInternalMouseAndKeyboardX11::
    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 
    122 void ScopedDisableInternalMouseAndKeyboardX11::WillProcessEvent(
    123     const ui::PlatformEvent& event) {
    124 }
    125 
    126 void 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