Commit 56281735 authored by flackr@chromium.org's avatar flackr@chromium.org

Only block internal touchpad and allow external mice to continue working in maximize mode.

BUG=362881
TEST=Manual, plug in an external mouse and observe it continues working when device is in maximize mode while internal touchpad does not.

Review URL: https://codereview.chromium.org/269633005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@272254 0039d316-1c4b-4281-b951-d872f2087c98
parent 394bf06f
...@@ -574,6 +574,9 @@ ...@@ -574,6 +574,9 @@
'wm/lock_state_controller.cc', 'wm/lock_state_controller.cc',
'wm/lock_state_controller.h', 'wm/lock_state_controller.h',
'wm/lock_state_observer.h', 'wm/lock_state_observer.h',
'wm/maximize_mode/internal_input_device_list.h',
'wm/maximize_mode/internal_input_device_list_x11.cc',
'wm/maximize_mode/internal_input_device_list_x11.h',
'wm/maximize_mode/maximize_mode_controller.cc', 'wm/maximize_mode/maximize_mode_controller.cc',
'wm/maximize_mode/maximize_mode_controller.h', 'wm/maximize_mode/maximize_mode_controller.h',
'wm/maximize_mode/maximize_mode_event_blocker.cc', 'wm/maximize_mode/maximize_mode_event_blocker.cc',
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_WM_MAXIMIZE_MODE_INTERNAL_INPUT_DEVICE_LIST_H_
#define ASH_WM_MAXIMIZE_MODE_INTERNAL_INPUT_DEVICE_LIST_H_
#include "ash/ash_export.h"
#include "base/macros.h"
namespace ui {
class Event;
}
namespace ash {
// Identifies which input devices are internal and provides a helper function to
// test if an input event came from an internal device.
class ASH_EXPORT InternalInputDeviceList {
public:
InternalInputDeviceList() {}
virtual ~InternalInputDeviceList() {}
virtual bool IsEventFromInternalDevice(const ui::Event* event) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(InternalInputDeviceList);
};
} // namespace ash
#endif // ASH_WM_MAXIMIZE_MODE_INTERNAL_INPUT_DEVICE_LIST_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/wm/maximize_mode/internal_input_device_list_x11.h"
#include <X11/extensions/XInput2.h>
#include <X11/Xlib.h>
#include "base/strings/string_util.h"
#include "ui/events/event.h"
#include "ui/events/x/device_data_manager.h"
#include "ui/events/x/device_list_cache_x.h"
#include "ui/gfx/x/x11_types.h"
namespace ash {
namespace {
// The name of the xinput device corresponding to the internal touchpad.
const char kInternalTouchpadName[] = "Elan Touchpad";
// The name of the xinput device corresponding to the internal keyboard.
const char kInternalKeyboardName[] = "AT Translated Set 2 keyboard";
} // namespace
InternalInputDeviceListX11::InternalInputDeviceListX11() {
if (ui::DeviceDataManager::GetInstance()->IsXInput2Available()) {
XIDeviceList xi_dev_list = ui::DeviceListCacheX::GetInstance()->
GetXI2DeviceList(gfx::GetXDisplay());
for (int i = 0; i < xi_dev_list.count; ++i) {
std::string device_name(xi_dev_list[i].name);
base::TrimWhitespaceASCII(device_name, base::TRIM_TRAILING, &device_name);
if (device_name == kInternalTouchpadName ||
device_name == kInternalKeyboardName)
internal_device_ids_.insert(xi_dev_list[i].deviceid);
}
}
}
InternalInputDeviceListX11::~InternalInputDeviceListX11() {
}
bool InternalInputDeviceListX11::IsEventFromInternalDevice(
const ui::Event* event) {
if (!event->HasNativeEvent())
return false;
XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(
event->native_event()->xcookie.data);
return internal_device_ids_.find(xiev->sourceid) !=
internal_device_ids_.end();
}
} // namespace ash
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_WM_MAXIMIZE_MODE_INTERNAL_INPUT_DEVICE_LIST_X11_H_
#define ASH_WM_MAXIMIZE_MODE_INTERNAL_INPUT_DEVICE_LIST_X11_H_
#include <set>
#include "ash/wm/maximize_mode/internal_input_device_list.h"
#include "base/macros.h"
namespace ui {
class Event;
}
namespace ash {
// Identifies which input devices are internal and provides a helper function to
// test if an input event came from an internal device.
class InternalInputDeviceListX11 : public InternalInputDeviceList {
public:
InternalInputDeviceListX11();
virtual ~InternalInputDeviceListX11();
// InternalInputDeviceList:
virtual bool IsEventFromInternalDevice(const ui::Event* event) OVERRIDE;
private:
// Tracks the device ids of internal input devices.
std::set<int> internal_device_ids_;
DISALLOW_COPY_AND_ASSIGN(InternalInputDeviceListX11);
};
} // namespace ash
#endif // ASH_WM_MAXIMIZE_MODE_INTERNAL_INPUT_DEVICE_LIST_X11_H_
...@@ -17,6 +17,7 @@ class EventHandler; ...@@ -17,6 +17,7 @@ class EventHandler;
namespace ash { namespace ash {
class MaximizeModeControllerTest;
class MaximizeModeEventBlocker; class MaximizeModeEventBlocker;
// MaximizeModeController listens to accelerometer events and automatically // MaximizeModeController listens to accelerometer events and automatically
...@@ -53,6 +54,8 @@ class ASH_EXPORT MaximizeModeController : public AccelerometerObserver { ...@@ -53,6 +54,8 @@ class ASH_EXPORT MaximizeModeController : public AccelerometerObserver {
const gfx::Vector3dF& lid) OVERRIDE; const gfx::Vector3dF& lid) OVERRIDE;
private: private:
friend class MaximizeModeControllerTest;
// Detect hinge rotation from |base| and |lid| accelerometers and // Detect hinge rotation from |base| and |lid| accelerometers and
// automatically start / stop maximize mode. // automatically start / stop maximize mode.
void HandleHingeRotation(const gfx::Vector3dF& base, void HandleHingeRotation(const gfx::Vector3dF& base,
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include "ash/test/test_screenshot_delegate.h" #include "ash/test/test_screenshot_delegate.h"
#include "ash/test/test_system_tray_delegate.h" #include "ash/test/test_system_tray_delegate.h"
#include "ash/test/test_volume_control_delegate.h" #include "ash/test/test_volume_control_delegate.h"
#include "ash/wm/maximize_mode/internal_input_device_list.h"
#include "ash/wm/maximize_mode/maximize_mode_event_blocker.h"
#include "ui/aura/test/event_generator.h" #include "ui/aura/test/event_generator.h"
#include "ui/events/event_handler.h" #include "ui/events/event_handler.h"
#include "ui/gfx/vector3d_f.h" #include "ui/gfx/vector3d_f.h"
...@@ -58,6 +60,21 @@ void EventCounter::OnEvent(ui::Event* event) { ...@@ -58,6 +60,21 @@ void EventCounter::OnEvent(ui::Event* event) {
event_count_++; event_count_++;
} }
// A test internal input device list which pretends that all events are from
// internal devices to allow verifying that the event blocking works.
class TestInternalInputDeviceList : public InternalInputDeviceList {
public:
TestInternalInputDeviceList() {}
virtual ~TestInternalInputDeviceList() {}
virtual bool IsEventFromInternalDevice(const ui::Event* event) OVERRIDE {
return true;
}
private:
DISALLOW_COPY_AND_ASSIGN(TestInternalInputDeviceList);
};
} // namespace } // namespace
// Test accelerometer data taken with the lid at less than 180 degrees while // Test accelerometer data taken with the lid at less than 180 degrees while
...@@ -109,6 +126,13 @@ class MaximizeModeControllerTest : public test::AshTestBase { ...@@ -109,6 +126,13 @@ class MaximizeModeControllerTest : public test::AshTestBase {
return Shell::GetInstance()->IsMaximizeModeWindowManagerEnabled(); return Shell::GetInstance()->IsMaximizeModeWindowManagerEnabled();
} }
// Overrides the internal input device list for the current event targeters
// with one which always returns true.
void InstallTestInternalDeviceList() {
maximize_mode_controller()->event_blocker_->internal_devices_.reset(
new TestInternalInputDeviceList);
}
gfx::Display::Rotation GetInternalDisplayRotation() const { gfx::Display::Rotation GetInternalDisplayRotation() const {
return Shell::GetInstance()->display_manager()->GetDisplayInfo( return Shell::GetInstance()->display_manager()->GetDisplayInfo(
gfx::Display::InternalDisplayId()).rotation(); gfx::Display::InternalDisplayId()).rotation();
...@@ -326,6 +350,7 @@ TEST_F(MaximizeModeControllerTest, BlocksKeyboardAndMouse) { ...@@ -326,6 +350,7 @@ TEST_F(MaximizeModeControllerTest, BlocksKeyboardAndMouse) {
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, 1.0f), TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, 1.0f),
gfx::Vector3dF(1.0f, 0.0f, 0.0f)); gfx::Vector3dF(1.0f, 0.0f, 0.0f));
ASSERT_TRUE(IsMaximizeModeStarted()); ASSERT_TRUE(IsMaximizeModeStarted());
InstallTestInternalDeviceList();
event_generator.PressKey(ui::VKEY_ESCAPE, 0); event_generator.PressKey(ui::VKEY_ESCAPE, 0);
event_generator.ReleaseKey(ui::VKEY_ESCAPE, 0); event_generator.ReleaseKey(ui::VKEY_ESCAPE, 0);
......
...@@ -5,10 +5,18 @@ ...@@ -5,10 +5,18 @@
#include "ash/wm/maximize_mode/maximize_mode_event_blocker.h" #include "ash/wm/maximize_mode/maximize_mode_event_blocker.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/wm/maximize_mode/internal_input_device_list.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "ui/aura/client/cursor_client.h" #include "ui/aura/client/cursor_client.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tree_host.h"
#include "ui/events/event_targeter.h" #include "ui/events/event_targeter.h"
#include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/point.h"
#if defined(USE_X11)
#include "ash/wm/maximize_mode/internal_input_device_list_x11.h"
#endif
namespace ash { namespace ash {
...@@ -17,11 +25,11 @@ namespace { ...@@ -17,11 +25,11 @@ namespace {
// Event targeter to prevent delivery of mouse and touchpad events while // Event targeter to prevent delivery of mouse and touchpad events while
// maximize mode is active. Other events such as touch are passed on to the // maximize mode is active. Other events such as touch are passed on to the
// default targeter. // default targeter.
// TODO(flackr): This should only stop events from the internal keyboard and
// touchpad.
class BlockKeyboardAndTouchpadTargeter : public ui::EventTargeter { class BlockKeyboardAndTouchpadTargeter : public ui::EventTargeter {
public: public:
BlockKeyboardAndTouchpadTargeter(); BlockKeyboardAndTouchpadTargeter(
aura::Window* root_window,
MaximizeModeEventBlocker* event_blocker);
virtual ~BlockKeyboardAndTouchpadTargeter(); virtual ~BlockKeyboardAndTouchpadTargeter();
// Sets the default targeter to use when the event is not being blocked. // Sets the default targeter to use when the event is not being blocked.
...@@ -32,16 +40,34 @@ class BlockKeyboardAndTouchpadTargeter : public ui::EventTargeter { ...@@ -32,16 +40,34 @@ class BlockKeyboardAndTouchpadTargeter : public ui::EventTargeter {
ui::Event* event) OVERRIDE; ui::Event* event) OVERRIDE;
private: private:
// A weak pointer to the root window on which this targeter will be set. The
// root window owns this targeter.
aura::Window* root_window_;
// A weak pointer to the event blocker which owns the scoped targeter owning
// this targeter.
MaximizeModeEventBlocker* event_blocker_;
// A weak pointer to the targeter this targeter is wrapping. The // A weak pointer to the targeter this targeter is wrapping. The
// default_targeter is owned by the ScopedWindowTargeter which will be valid // default_targeter is owned by the ScopedWindowTargeter which will be valid
// as long as this targeter is alive. // as long as this targeter is alive.
ui::EventTargeter* default_targeter_; ui::EventTargeter* default_targeter_;
// The last known mouse location to lock the cursor in place to when events
// come from the internal touchpad.
gfx::Point last_mouse_location_;
DISALLOW_COPY_AND_ASSIGN(BlockKeyboardAndTouchpadTargeter); DISALLOW_COPY_AND_ASSIGN(BlockKeyboardAndTouchpadTargeter);
}; };
BlockKeyboardAndTouchpadTargeter::BlockKeyboardAndTouchpadTargeter() BlockKeyboardAndTouchpadTargeter::BlockKeyboardAndTouchpadTargeter(
: default_targeter_(NULL) { aura::Window* root_window,
MaximizeModeEventBlocker* event_blocker)
: root_window_(root_window),
event_blocker_(event_blocker),
default_targeter_(NULL),
last_mouse_location_(root_window->GetHost()->dispatcher()->
GetLastMouseLocationInRoot()) {
} }
BlockKeyboardAndTouchpadTargeter::~BlockKeyboardAndTouchpadTargeter() { BlockKeyboardAndTouchpadTargeter::~BlockKeyboardAndTouchpadTargeter() {
...@@ -55,19 +81,37 @@ void BlockKeyboardAndTouchpadTargeter::SetDefaultTargeter( ...@@ -55,19 +81,37 @@ void BlockKeyboardAndTouchpadTargeter::SetDefaultTargeter(
ui::EventTarget* BlockKeyboardAndTouchpadTargeter::FindTargetForEvent( ui::EventTarget* BlockKeyboardAndTouchpadTargeter::FindTargetForEvent(
ui::EventTarget* root, ui::EventTarget* root,
ui::Event* event) { ui::Event* event) {
if (event->IsMouseEvent() || bool internal_device = event_blocker_->internal_devices() &&
event->IsMouseWheelEvent() || event_blocker_->internal_devices()->IsEventFromInternalDevice(event);
event->IsScrollEvent()) { if (event->IsMouseEvent()) {
if (internal_device) {
// The cursor movement is handled at a lower level which is not blocked.
// Move the mouse cursor back to its last known location resulting from
// an external mouse to prevent the internal touchpad from moving it.
root_window_->GetHost()->MoveCursorToHostLocation(
last_mouse_location_);
return NULL;
} else {
// Track the last location seen from an external mouse event.
last_mouse_location_ =
static_cast<ui::MouseEvent*>(event)->root_location();
root_window_->GetHost()->ConvertPointToHost(&last_mouse_location_);
}
} else if (internal_device && (event->IsMouseWheelEvent() ||
event->IsScrollEvent())) {
return NULL; return NULL;
} } else if (event->IsKeyEvent() && event->HasNativeEvent()) {
if (event->IsKeyEvent() && event->HasNativeEvent()) { // TODO(flackr): Disable events only from the internal keyboard device
// when we begin using XI2 events for keyboard events
// (http://crbug.com/368750) and can tell which device the event is
// coming from, http://crbug.com/362881.
// TODO(bruthig): Fix this to block rewritten volume keys // TODO(bruthig): Fix this to block rewritten volume keys
// (i.e. F9 and F10) from the device's keyboard. https://crbug.com/368669 // (i.e. F9 and F10) from the device's keyboard. https://crbug.com/368669
ui::KeyEvent* key_event = static_cast<ui::KeyEvent*>(event); ui::KeyEvent* key_event = static_cast<ui::KeyEvent*>(event);
if (key_event->key_code() != ui::VKEY_VOLUME_DOWN && if (key_event->key_code() != ui::VKEY_VOLUME_DOWN &&
key_event->key_code() != ui::VKEY_VOLUME_UP key_event->key_code() != ui::VKEY_VOLUME_UP
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
&& key_event->key_code() != ui::VKEY_POWER && key_event->key_code() != ui::VKEY_POWER
#endif #endif
) { ) {
return NULL; return NULL;
...@@ -78,7 +122,11 @@ ui::EventTarget* BlockKeyboardAndTouchpadTargeter::FindTargetForEvent( ...@@ -78,7 +122,11 @@ ui::EventTarget* BlockKeyboardAndTouchpadTargeter::FindTargetForEvent(
} // namespace } // namespace
MaximizeModeEventBlocker::MaximizeModeEventBlocker() { MaximizeModeEventBlocker::MaximizeModeEventBlocker()
#if defined(USE_X11)
: internal_devices_(new InternalInputDeviceListX11)
#endif
{
Shell::GetInstance()->AddShellObserver(this); Shell::GetInstance()->AddShellObserver(this);
// Hide the cursor as mouse events will be blocked. // Hide the cursor as mouse events will be blocked.
...@@ -107,7 +155,7 @@ void MaximizeModeEventBlocker::OnRootWindowAdded(aura::Window* root_window) { ...@@ -107,7 +155,7 @@ void MaximizeModeEventBlocker::OnRootWindowAdded(aura::Window* root_window) {
void MaximizeModeEventBlocker::AddEventTargeterOn( void MaximizeModeEventBlocker::AddEventTargeterOn(
aura::Window* root_window) { aura::Window* root_window) {
BlockKeyboardAndTouchpadTargeter* targeter = BlockKeyboardAndTouchpadTargeter* targeter =
new BlockKeyboardAndTouchpadTargeter(); new BlockKeyboardAndTouchpadTargeter(root_window, this);
aura::ScopedWindowTargeter* scoped_targeter = new aura::ScopedWindowTargeter( aura::ScopedWindowTargeter* scoped_targeter = new aura::ScopedWindowTargeter(
root_window, scoped_ptr<ui::EventTargeter>(targeter)); root_window, scoped_ptr<ui::EventTargeter>(targeter));
targeter->SetDefaultTargeter(scoped_targeter->old_targeter()); targeter->SetDefaultTargeter(scoped_targeter->old_targeter());
......
...@@ -5,8 +5,11 @@ ...@@ -5,8 +5,11 @@
#ifndef ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_EVENT_BLOCKER_H_ #ifndef ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_EVENT_BLOCKER_H_
#define ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_EVENT_BLOCKER_H_ #define ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_EVENT_BLOCKER_H_
#include <set>
#include "ash/shell_observer.h" #include "ash/shell_observer.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h" #include "base/memory/scoped_vector.h"
#include "ui/aura/scoped_window_targeter.h" #include "ui/aura/scoped_window_targeter.h"
...@@ -16,6 +19,9 @@ class Window; ...@@ -16,6 +19,9 @@ class Window;
namespace ash { namespace ash {
class InternalInputDeviceList;
class MaximizeModeControllerTest;
// A class which blocks mouse and keyboard events while instantiated by // A class which blocks mouse and keyboard events while instantiated by
// replacing the root window event targeter. // replacing the root window event targeter.
class MaximizeModeEventBlocker : public ShellObserver { class MaximizeModeEventBlocker : public ShellObserver {
...@@ -23,14 +29,21 @@ class MaximizeModeEventBlocker : public ShellObserver { ...@@ -23,14 +29,21 @@ class MaximizeModeEventBlocker : public ShellObserver {
MaximizeModeEventBlocker(); MaximizeModeEventBlocker();
virtual ~MaximizeModeEventBlocker(); virtual ~MaximizeModeEventBlocker();
InternalInputDeviceList* internal_devices() {
return internal_devices_.get();
}
// ShellObserver: // ShellObserver:
virtual void OnRootWindowAdded(aura::Window* root_window) OVERRIDE; virtual void OnRootWindowAdded(aura::Window* root_window) OVERRIDE;
private: private:
friend class MaximizeModeControllerTest;
// Adds an event targeter on |root_window| to block mouse and keyboard events. // Adds an event targeter on |root_window| to block mouse and keyboard events.
void AddEventTargeterOn(aura::Window* root_window); void AddEventTargeterOn(aura::Window* root_window);
ScopedVector<aura::ScopedWindowTargeter> targeters_; ScopedVector<aura::ScopedWindowTargeter> targeters_;
scoped_ptr<InternalInputDeviceList> internal_devices_;
DISALLOW_COPY_AND_ASSIGN(MaximizeModeEventBlocker); DISALLOW_COPY_AND_ASSIGN(MaximizeModeEventBlocker);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment