blob: 711042272b0a6b81b81dd2190fbefe9eabd595ca [file] [log] [blame]
// 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 "chrome/browser/chromeos/events/event_rewriter.h"
#include <vector>
#include "ash/shell.h"
#include "ash/sticky_keys/sticky_keys_controller.h"
#include "ash/sticky_keys/sticky_keys_overlay.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/window_state.h"
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/prefs/pref_member.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/chromeos/input_method/input_method_configuration.h"
#include "chrome/browser/chromeos/input_method/mock_input_method_manager.h"
#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
#include "chrome/browser/chromeos/preferences.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_pref_service_syncable.h"
#include "chromeos/chromeos_switches.h"
#include "components/user_manager/fake_user_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/ime/chromeos/fake_ime_keyboard.h"
#include "ui/events/event.h"
#include "ui/events/event_rewriter.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/events/test/events_test_utils.h"
#include "ui/events/test/test_event_processor.h"
#if defined(USE_X11)
#include <X11/keysym.h>
#include "ui/events/devices/x11/touch_factory_x11.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/events_test_utils_x11.h"
#include "ui/gfx/x/x11_types.h"
#endif
namespace {
// The device id of the test touchpad device.
#if defined(USE_X11)
const int kTouchPadDeviceId = 1;
const int kMasterKeyboardDeviceId = 3;
#endif
const int kKeyboardDeviceId = 2;
std::string GetExpectedResultAsString(ui::EventType ui_type,
ui::KeyboardCode ui_keycode,
ui::DomCode code,
int ui_flags, // ui::EventFlags
ui::DomKey key,
base::char16 character) {
return base::StringPrintf("ui_keycode=0x%X ui_flags=0x%X ui_type=%d",
ui_keycode,
ui_flags & ~ui::EF_IS_REPEAT,
ui_type);
}
std::string GetKeyEventAsString(const ui::KeyEvent& keyevent) {
return GetExpectedResultAsString(
keyevent.type(), keyevent.key_code(), keyevent.code(), keyevent.flags(),
keyevent.GetDomKey(), keyevent.GetCharacter());
}
std::string GetRewrittenEventAsString(chromeos::EventRewriter* rewriter,
ui::EventType ui_type,
ui::KeyboardCode ui_keycode,
ui::DomCode code,
int ui_flags, // ui::EventFlags
ui::DomKey key,
base::char16 character) {
const ui::KeyEvent event(ui_type, ui_keycode, code, ui_flags, key, character,
ui::EventTimeForNow());
scoped_ptr<ui::Event> new_event;
rewriter->RewriteEvent(event, &new_event);
if (new_event)
return GetKeyEventAsString(
static_cast<const ui::KeyEvent&>(*new_event.get()));
return GetKeyEventAsString(event);
}
// Table entry for simple single key event rewriting tests.
struct KeyTestCase {
enum {
// Test types:
TEST_VKEY = 1 << 0, // Test ui::KeyEvent with no native event
TEST_X11 = 1 << 1, // Test ui::KeyEvent with native XKeyEvent
TEST_ALL = TEST_VKEY | TEST_X11,
// Special test flags:
NUMPAD = 1 << 8, // Reset the XKB scan code on an X11 event based
// on the test DomCode, because
// |XKeysymForWindowsKeyCode()| can not distinguish
// between pairs like XK_Insert and XK_KP_Insert.
};
int test;
ui::EventType type;
struct Event {
ui::KeyboardCode key_code;
ui::DomCode code;
int flags; // ui::EventFlags
ui::DomKey key;
base::char16 character;
} input, expected;
};
std::string GetTestCaseAsString(ui::EventType ui_type,
const KeyTestCase::Event& test) {
return GetExpectedResultAsString(ui_type, test.key_code, test.code,
test.flags, test.key, test.character);
}
#if defined(USE_X11)
// Check rewriting of an X11-based key event.
void CheckX11KeyTestCase(const std::string& expected,
chromeos::EventRewriter* rewriter,
const KeyTestCase& test,
XEvent* xevent) {
ui::KeyEvent xkey_event(xevent);
// Rewrite the event and check the result.
scoped_ptr<ui::Event> new_event;
rewriter->RewriteEvent(xkey_event, &new_event);
ui::KeyEvent& rewritten_key_event =
new_event ? *static_cast<ui::KeyEvent*>(new_event.get()) : xkey_event;
EXPECT_EQ(expected, GetKeyEventAsString(rewritten_key_event));
if ((rewritten_key_event.key_code() != ui::VKEY_UNKNOWN) &&
(rewritten_key_event.native_event()->xkey.keycode != 0)) {
// Build a new ui::KeyEvent from the rewritten native component,
// and check that it also matches the rewritten event.
EXPECT_TRUE(rewritten_key_event.native_event());
ui::KeyEvent from_native_event(rewritten_key_event.native_event());
EXPECT_EQ(expected, GetKeyEventAsString(from_native_event));
}
}
#endif
// Tests a single stateless key rewrite operation.
void CheckKeyTestCase(chromeos::EventRewriter* rewriter,
const KeyTestCase& test) {
std::string expected = GetTestCaseAsString(test.type, test.expected);
if (test.test & KeyTestCase::TEST_VKEY) {
// Check rewriting of a non-native-based key event.
EXPECT_EQ(expected,
GetRewrittenEventAsString(
rewriter, test.type, test.input.key_code, test.input.code,
test.input.flags, test.input.key, test.input.character));
}
#if defined(USE_X11)
if (test.test & KeyTestCase::TEST_X11) {
ui::ScopedXI2Event xev;
// Test an XKeyEvent.
xev.InitKeyEvent(test.type, test.input.key_code, test.input.flags);
XEvent* xevent = xev;
DCHECK((xevent->type == KeyPress) || (xevent->type == KeyRelease));
if (test.test & KeyTestCase::NUMPAD) {
xevent->xkey.keycode =
ui::KeycodeConverter::DomCodeToNativeKeycode(test.input.code);
}
int keycode = xevent->xkey.keycode;
if (keycode) {
CheckX11KeyTestCase(expected, rewriter, test, xevent);
// Test an XI2 GenericEvent.
xev.InitGenericKeyEvent(kMasterKeyboardDeviceId, kKeyboardDeviceId,
test.type, test.input.key_code, test.input.flags);
xevent = xev;
DCHECK(xevent->type == GenericEvent);
XIDeviceEvent* xievent =
static_cast<XIDeviceEvent*>(xevent->xcookie.data);
DCHECK((xievent->evtype == XI_KeyPress) ||
(xievent->evtype == XI_KeyRelease));
xievent->detail = keycode;
CheckX11KeyTestCase(expected, rewriter, test, xevent);
}
}
#endif
}
} // namespace
namespace chromeos {
class EventRewriterTest : public ash::test::AshTestBase {
public:
EventRewriterTest()
: fake_user_manager_(new user_manager::FakeUserManager),
user_manager_enabler_(fake_user_manager_),
input_method_manager_mock_(NULL) {}
~EventRewriterTest() override {}
void SetUp() override {
input_method_manager_mock_ =
new chromeos::input_method::MockInputMethodManager;
chromeos::input_method::InitializeForTesting(
input_method_manager_mock_); // pass ownership
AshTestBase::SetUp();
}
void TearDown() override {
AshTestBase::TearDown();
// Shutdown() deletes the IME mock object.
chromeos::input_method::Shutdown();
}
protected:
void TestRewriteNumPadKeys();
void TestRewriteNumPadKeysOnAppleKeyboard();
const ui::MouseEvent* RewriteMouseButtonEvent(
chromeos::EventRewriter* rewriter,
const ui::MouseEvent& event,
scoped_ptr<ui::Event>* new_event) {
rewriter->RewriteMouseButtonEventForTesting(event, new_event);
return *new_event ? static_cast<const ui::MouseEvent*>(new_event->get())
: &event;
}
user_manager::FakeUserManager* fake_user_manager_; // Not owned.
chromeos::ScopedUserManagerEnabler user_manager_enabler_;
chromeos::input_method::MockInputMethodManager* input_method_manager_mock_;
};
TEST_F(EventRewriterTest, TestRewriteCommandToControl) {
// First, test with a PC keyboard.
TestingPrefServiceSyncable prefs;
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_last_keyboard_device_id_for_testing(kKeyboardDeviceId);
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase pc_keyboard_tests[] = {
// VKEY_A, Alt modifier.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'a'},
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'a'}},
// VKEY_A, Win modifier.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'a'},
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'a'}},
// VKEY_A, Alt+Win modifier.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'a'},
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'a'}},
// VKEY_LWIN (left Windows key), Alt modifier.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0}},
// VKEY_RWIN (right Windows key), Alt modifier.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_RWIN,
ui::DomCode::OS_RIGHT,
ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_RWIN,
ui::DomCode::OS_RIGHT,
ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0}},
};
for (size_t i = 0; i < arraysize(pc_keyboard_tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, pc_keyboard_tests[i]);
}
// An Apple keyboard reusing the ID, zero.
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "Apple Keyboard");
rewriter.set_last_keyboard_device_id_for_testing(kKeyboardDeviceId);
KeyTestCase apple_keyboard_tests[] = {
// VKEY_A, Alt modifier.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'a'},
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'a'}},
// VKEY_A, Win modifier.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'a'},
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_CONTROL_DOWN,
ui::DomKey::CHARACTER,
'a'}},
// VKEY_A, Alt+Win modifier.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'a'},
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::CHARACTER,
'a'}},
// VKEY_LWIN (left Windows key), Alt modifier.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::CONTROL,
0}},
// VKEY_RWIN (right Windows key), Alt modifier.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_RWIN,
ui::DomCode::OS_RIGHT,
ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::CONTROL,
0}},
};
for (size_t i = 0; i < arraysize(apple_keyboard_tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, apple_keyboard_tests[i]);
}
}
// For crbug.com/133896.
TEST_F(EventRewriterTest, TestRewriteCommandToControlWithControlRemapped) {
// Remap Control to Alt.
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
IntegerPrefMember control;
control.Init(prefs::kLanguageRemapControlKeyTo, &prefs);
control.SetValue(chromeos::input_method::kAltKey);
EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_last_keyboard_device_id_for_testing(kKeyboardDeviceId);
KeyTestCase pc_keyboard_tests[] = {
// Control should be remapped to Alt.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0},
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_ALT_DOWN,
ui::DomKey::ALT,
0}},
};
for (size_t i = 0; i < arraysize(pc_keyboard_tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, pc_keyboard_tests[i]);
}
// An Apple keyboard reusing the ID, zero.
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "Apple Keyboard");
rewriter.set_last_keyboard_device_id_for_testing(kKeyboardDeviceId);
KeyTestCase apple_keyboard_tests[] = {
// VKEY_LWIN (left Command key) with Alt modifier. The remapped Command
// key should never be re-remapped to Alt.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::CONTROL,
0}},
// VKEY_RWIN (right Command key) with Alt modifier. The remapped Command
// key should never be re-remapped to Alt.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_RWIN,
ui::DomCode::OS_RIGHT,
ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::CONTROL,
0}},
};
for (size_t i = 0; i < arraysize(apple_keyboard_tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, apple_keyboard_tests[i]);
}
}
void EventRewriterTest::TestRewriteNumPadKeys() {
TestingPrefServiceSyncable prefs;
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_last_keyboard_device_id_for_testing(kKeyboardDeviceId);
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase tests[] = {
// XK_KP_Insert (= NumPad 0 without Num Lock), no modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_INSERT,
ui::DomCode::NUMPAD0,
ui::EF_NONE,
ui::DomKey::INSERT,
0},
{ui::VKEY_NUMPAD0,
ui::DomCode::NUMPAD0,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'0'}},
// XK_KP_Insert (= NumPad 0 without Num Lock), Alt modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_INSERT,
ui::DomCode::NUMPAD0,
ui::EF_ALT_DOWN,
ui::DomKey::INSERT,
0},
{ui::VKEY_NUMPAD0,
ui::DomCode::NUMPAD0,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'0'}},
// XK_KP_Delete (= NumPad . without Num Lock), Alt modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_DELETE,
ui::DomCode::NUMPAD_DECIMAL,
ui::EF_ALT_DOWN,
ui::DomKey::DEL,
0},
{ui::VKEY_DECIMAL,
ui::DomCode::NUMPAD_DECIMAL,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'.'}},
// XK_KP_End (= NumPad 1 without Num Lock), Alt modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_END,
ui::DomCode::NUMPAD1,
ui::EF_ALT_DOWN,
ui::DomKey::END,
0},
{ui::VKEY_NUMPAD1,
ui::DomCode::NUMPAD1,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'1'}},
// XK_KP_Down (= NumPad 2 without Num Lock), Alt modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_DOWN,
ui::DomCode::NUMPAD2,
ui::EF_ALT_DOWN,
ui::DomKey::ARROW_DOWN,
0},
{ui::VKEY_NUMPAD2,
ui::DomCode::NUMPAD2,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'2'}},
// XK_KP_Next (= NumPad 3 without Num Lock), Alt modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_NEXT,
ui::DomCode::NUMPAD3,
ui::EF_ALT_DOWN,
ui::DomKey::PAGE_DOWN,
0},
{ui::VKEY_NUMPAD3,
ui::DomCode::NUMPAD3,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'3'}},
// XK_KP_Left (= NumPad 4 without Num Lock), Alt modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_LEFT,
ui::DomCode::NUMPAD4,
ui::EF_ALT_DOWN,
ui::DomKey::ARROW_LEFT,
0},
{ui::VKEY_NUMPAD4,
ui::DomCode::NUMPAD4,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'4'}},
// XK_KP_Begin (= NumPad 5 without Num Lock), Alt modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_CLEAR,
ui::DomCode::NUMPAD5,
ui::EF_ALT_DOWN,
ui::DomKey::CLEAR,
0},
{ui::VKEY_NUMPAD5,
ui::DomCode::NUMPAD5,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'5'}},
// XK_KP_Right (= NumPad 6 without Num Lock), Alt modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_RIGHT,
ui::DomCode::NUMPAD6,
ui::EF_ALT_DOWN,
ui::DomKey::ARROW_RIGHT,
0},
{ui::VKEY_NUMPAD6,
ui::DomCode::NUMPAD6,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'6'}},
// XK_KP_Home (= NumPad 7 without Num Lock), Alt modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_HOME,
ui::DomCode::NUMPAD7,
ui::EF_ALT_DOWN,
ui::DomKey::HOME,
0},
{ui::VKEY_NUMPAD7,
ui::DomCode::NUMPAD7,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'7'}},
// XK_KP_Up (= NumPad 8 without Num Lock), Alt modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_UP,
ui::DomCode::NUMPAD8,
ui::EF_ALT_DOWN,
ui::DomKey::ARROW_UP,
0},
{ui::VKEY_NUMPAD8,
ui::DomCode::NUMPAD8,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'8'}},
// XK_KP_Prior (= NumPad 9 without Num Lock), Alt modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_PRIOR,
ui::DomCode::NUMPAD9,
ui::EF_ALT_DOWN,
ui::DomKey::PAGE_UP,
0},
{ui::VKEY_NUMPAD9,
ui::DomCode::NUMPAD9,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'9'}},
// XK_KP_0 (= NumPad 0 with Num Lock), Num Lock modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_NUMPAD0,
ui::DomCode::NUMPAD0,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'0'},
{ui::VKEY_NUMPAD0,
ui::DomCode::NUMPAD0,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'0'}},
// XK_KP_DECIMAL (= NumPad . with Num Lock), Num Lock modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_DECIMAL,
ui::DomCode::NUMPAD_DECIMAL,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'.'},
{ui::VKEY_DECIMAL,
ui::DomCode::NUMPAD_DECIMAL,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'.'}},
// XK_KP_1 (= NumPad 1 with Num Lock), Num Lock modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_NUMPAD1,
ui::DomCode::NUMPAD1,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'1'},
{ui::VKEY_NUMPAD1,
ui::DomCode::NUMPAD1,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'1'}},
// XK_KP_2 (= NumPad 2 with Num Lock), Num Lock modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_NUMPAD2,
ui::DomCode::NUMPAD2,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'2'},
{ui::VKEY_NUMPAD2,
ui::DomCode::NUMPAD2,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'2'}},
// XK_KP_3 (= NumPad 3 with Num Lock), Num Lock modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_NUMPAD3,
ui::DomCode::NUMPAD3,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'3'},
{ui::VKEY_NUMPAD3,
ui::DomCode::NUMPAD3,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'3'}},
// XK_KP_4 (= NumPad 4 with Num Lock), Num Lock modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_NUMPAD4,
ui::DomCode::NUMPAD4,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'4'},
{ui::VKEY_NUMPAD4,
ui::DomCode::NUMPAD4,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'4'}},
// XK_KP_5 (= NumPad 5 with Num Lock), Num Lock
// modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_NUMPAD5,
ui::DomCode::NUMPAD5,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'5'},
{ui::VKEY_NUMPAD5,
ui::DomCode::NUMPAD5,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'5'}},
// XK_KP_6 (= NumPad 6 with Num Lock), Num Lock
// modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_NUMPAD6,
ui::DomCode::NUMPAD6,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'6'},
{ui::VKEY_NUMPAD6,
ui::DomCode::NUMPAD6,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'6'}},
// XK_KP_7 (= NumPad 7 with Num Lock), Num Lock
// modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_NUMPAD7,
ui::DomCode::NUMPAD7,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'7'},
{ui::VKEY_NUMPAD7,
ui::DomCode::NUMPAD7,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'7'}},
// XK_KP_8 (= NumPad 8 with Num Lock), Num Lock
// modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_NUMPAD8,
ui::DomCode::NUMPAD8,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'8'},
{ui::VKEY_NUMPAD8,
ui::DomCode::NUMPAD8,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'8'}},
// XK_KP_9 (= NumPad 9 with Num Lock), Num Lock
// modifier.
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_NUMPAD9,
ui::DomCode::NUMPAD9,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'9'},
{ui::VKEY_NUMPAD9,
ui::DomCode::NUMPAD9,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'9'}},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, tests[i]);
}
}
TEST_F(EventRewriterTest, TestRewriteNumPadKeys) {
TestRewriteNumPadKeys();
}
TEST_F(EventRewriterTest, TestRewriteNumPadKeysWithDiamondKeyFlag) {
// Make sure the num lock works correctly even when Diamond key exists.
const base::CommandLine original_cl(*base::CommandLine::ForCurrentProcess());
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
chromeos::switches::kHasChromeOSDiamondKey, "");
TestRewriteNumPadKeys();
*base::CommandLine::ForCurrentProcess() = original_cl;
}
// Tests if the rewriter can handle a Command + Num Pad event.
void EventRewriterTest::TestRewriteNumPadKeysOnAppleKeyboard() {
TestingPrefServiceSyncable prefs;
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "Apple Keyboard");
rewriter.set_last_keyboard_device_id_for_testing(kKeyboardDeviceId);
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase tests[] = {
// XK_KP_End (= NumPad 1 without Num Lock), Win modifier.
// The result should be "Num Pad 1 with Control + Num Lock modifiers".
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_END,
ui::DomCode::NUMPAD1,
ui::EF_COMMAND_DOWN,
ui::DomKey::END,
0},
{ui::VKEY_NUMPAD1,
ui::DomCode::NUMPAD1,
ui::EF_CONTROL_DOWN,
ui::DomKey::CHARACTER,
'1'}},
// XK_KP_1 (= NumPad 1 with Num Lock), Win modifier.
// The result should also be "Num Pad 1 with Control + Num Lock
// modifiers".
{KeyTestCase::TEST_ALL | KeyTestCase::NUMPAD,
ui::ET_KEY_PRESSED,
{ui::VKEY_NUMPAD1,
ui::DomCode::NUMPAD1,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'1'},
{ui::VKEY_NUMPAD1,
ui::DomCode::NUMPAD1,
ui::EF_CONTROL_DOWN,
ui::DomKey::CHARACTER,
'1'}}};
for (size_t i = 0; i < arraysize(tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, tests[i]);
}
}
TEST_F(EventRewriterTest, TestRewriteNumPadKeysOnAppleKeyboard) {
TestRewriteNumPadKeysOnAppleKeyboard();
}
TEST_F(EventRewriterTest,
TestRewriteNumPadKeysOnAppleKeyboardWithDiamondKeyFlag) {
// Makes sure the num lock works correctly even when Diamond key exists.
const base::CommandLine original_cl(*base::CommandLine::ForCurrentProcess());
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
chromeos::switches::kHasChromeOSDiamondKey, "");
TestRewriteNumPadKeysOnAppleKeyboard();
*base::CommandLine::ForCurrentProcess() = original_cl;
}
TEST_F(EventRewriterTest, TestRewriteModifiersNoRemap) {
TestingPrefServiceSyncable prefs;
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase tests[] = {
// Press Search. Confirm the event is not rewritten.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN, ui::DomCode::OS_LEFT, ui::EF_NONE, ui::DomKey::OS, 0},
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0}},
// Press left Control. Confirm the event is not rewritten.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0}},
// Press right Control. Confirm the event is not rewritten.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0}},
// Press left Alt. Confirm the event is not rewritten.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_ALT_DOWN,
ui::DomKey::ALT,
0},
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_ALT_DOWN,
ui::DomKey::ALT,
0}},
// Press right Alt. Confirm the event is not rewritten.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_ALT_DOWN,
ui::DomKey::ALT,
0},
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_ALT_DOWN,
ui::DomKey::ALT,
0}},
// Test KeyRelease event, just in case.
// Release Search. Confirm the release event is not rewritten.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_RELEASED,
{ui::VKEY_LWIN, ui::DomCode::OS_LEFT, ui::EF_NONE, ui::DomKey::OS, 0},
{ui::VKEY_LWIN, ui::DomCode::OS_LEFT, ui::EF_NONE, ui::DomKey::OS, 0}},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, tests[i]);
}
}
TEST_F(EventRewriterTest, TestRewriteModifiersNoRemapMultipleKeys) {
TestingPrefServiceSyncable prefs;
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase tests[] = {
// Press Alt with Shift. Confirm the event is not rewritten.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::ALT,
0},
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::ALT,
0}},
// Press Search with Caps Lock mask. Confirm the event is not rewritten.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_CAPS_LOCK_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_CAPS_LOCK_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0}},
// Release Search with Caps Lock mask. Confirm the event is not rewritten.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_RELEASED,
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_CAPS_LOCK_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_CAPS_LOCK_DOWN,
ui::DomKey::OS,
0}},
// Press Shift+Ctrl+Alt+Search+A. Confirm the event is not rewritten.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_B,
ui::DomCode::KEY_B,
ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN |
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'B'},
{ui::VKEY_B,
ui::DomCode::KEY_B,
ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN |
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'B'}},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, tests[i]);
}
}
TEST_F(EventRewriterTest, TestRewriteModifiersDisableSome) {
// Disable Search and Control keys.
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
IntegerPrefMember search;
search.Init(prefs::kLanguageRemapSearchKeyTo, &prefs);
search.SetValue(chromeos::input_method::kVoidKey);
IntegerPrefMember control;
control.Init(prefs::kLanguageRemapControlKeyTo, &prefs);
control.SetValue(chromeos::input_method::kVoidKey);
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase disabled_modifier_tests[] = {
// Press Alt with Shift. This key press shouldn't be affected by the
// pref. Confirm the event is not rewritten.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::ALT,
0},
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::ALT,
0}},
// Press Search. Confirm the event is now VKEY_UNKNOWN.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN, ui::DomCode::OS_LEFT, ui::EF_NONE, ui::DomKey::OS, 0},
{ui::VKEY_UNKNOWN,
ui::DomCode::NONE,
ui::EF_NONE,
ui::DomKey::UNIDENTIFIED,
0}},
// Press Control. Confirm the event is now VKEY_UNKNOWN.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0},
{ui::VKEY_UNKNOWN,
ui::DomCode::NONE,
ui::EF_NONE,
ui::DomKey::UNIDENTIFIED,
0}},
// Press Control+Search. Confirm the event is now VKEY_UNKNOWN
// without any modifiers.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_UNKNOWN,
ui::DomCode::NONE,
ui::EF_NONE,
ui::DomKey::UNIDENTIFIED,
0}},
// Press Control+Search+a. Confirm the event is now VKEY_A without any
// modifiers.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_CONTROL_DOWN,
ui::DomKey::CHARACTER,
'a'},
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'a'}},
// Press Control+Search+Alt+a. Confirm the event is now VKEY_A only with
// the Alt modifier.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'a'},
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'a'}},
};
for (size_t i = 0; i < arraysize(disabled_modifier_tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, disabled_modifier_tests[i]);
}
// Remap Alt to Control.
IntegerPrefMember alt;
alt.Init(prefs::kLanguageRemapAltKeyTo, &prefs);
alt.SetValue(chromeos::input_method::kControlKey);
KeyTestCase tests[] = {
// Press left Alt. Confirm the event is now VKEY_CONTROL
// even though the Control key itself is disabled.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_ALT_DOWN,
ui::DomKey::ALT,
0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0}},
// Press Alt+a. Confirm the event is now Control+a even though the Control
// key itself is disabled.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'a'},
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_CONTROL_DOWN,
ui::DomKey::CHARACTER,
'a'}},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, tests[i]);
}
}
TEST_F(EventRewriterTest, TestRewriteModifiersRemapToControl) {
// Remap Search to Control.
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
IntegerPrefMember search;
search.Init(prefs::kLanguageRemapSearchKeyTo, &prefs);
search.SetValue(chromeos::input_method::kControlKey);
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase s_tests[] = {
// Press Search. Confirm the event is now VKEY_CONTROL.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0}},
};
for (size_t i = 0; i < arraysize(s_tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, s_tests[i]);
}
// Remap Alt to Control too.
IntegerPrefMember alt;
alt.Init(prefs::kLanguageRemapAltKeyTo, &prefs);
alt.SetValue(chromeos::input_method::kControlKey);
KeyTestCase sa_tests[] = {
// Press Alt. Confirm the event is now VKEY_CONTROL.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_ALT_DOWN,
ui::DomKey::ALT,
0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0}},
// Press Alt+Search. Confirm the event is now VKEY_CONTROL.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0}},
// Press Control+Alt+Search. Confirm the event is now VKEY_CONTROL.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0}},
// Press Shift+Control+Alt+Search. Confirm the event is now Control with
// Shift and Control modifiers.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN |
ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0}},
// Press Shift+Control+Alt+Search+B. Confirm the event is now B with Shift
// and Control modifiers.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_B,
ui::DomCode::KEY_B,
ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN |
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'B'},
{ui::VKEY_B,
ui::DomCode::KEY_B,
ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::CHARACTER,
'B'}},
};
for (size_t i = 0; i < arraysize(sa_tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, sa_tests[i]);
}
}
TEST_F(EventRewriterTest, TestRewriteModifiersRemapToEscape) {
// Remap Search to ESC.
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
IntegerPrefMember search;
search.Init(prefs::kLanguageRemapSearchKeyTo, &prefs);
search.SetValue(chromeos::input_method::kEscapeKey);
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase tests[] = {
// Press Search. Confirm the event is now VKEY_ESCAPE.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_ESCAPE,
ui::DomCode::ESCAPE,
ui::EF_NONE,
ui::DomKey::ESCAPE,
0}},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, tests[i]);
}
}
TEST_F(EventRewriterTest, TestRewriteModifiersRemapMany) {
// Remap Search to Alt.
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
IntegerPrefMember search;
search.Init(prefs::kLanguageRemapSearchKeyTo, &prefs);
search.SetValue(chromeos::input_method::kAltKey);
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase s2a_tests[] = {
// Press Search. Confirm the event is now VKEY_MENU.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_ALT_DOWN,
ui::DomKey::ALT,
0}},
};
for (size_t i = 0; i < arraysize(s2a_tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, s2a_tests[i]);
}
// Remap Alt to Control.
IntegerPrefMember alt;
alt.Init(prefs::kLanguageRemapAltKeyTo, &prefs);
alt.SetValue(chromeos::input_method::kControlKey);
KeyTestCase a2c_tests[] = {
// Press left Alt. Confirm the event is now VKEY_CONTROL.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_ALT_DOWN,
ui::DomKey::ALT,
0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0}},
// Press Shift+comma. Verify that only the flags are changed.
// The X11 portion of the test addresses crbug.com/390263 by verifying
// that the X keycode remains that for ',<' and not for 105-key '<>'.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_OEM_COMMA,
ui::DomCode::COMMA,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::UNIDENTIFIED,
0},
{ui::VKEY_OEM_COMMA,
ui::DomCode::COMMA,
ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::UNIDENTIFIED,
0}},
// Press Shift+9. Verify that only the flags are changed.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_9,
ui::DomCode::DIGIT9,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER,
'9'},
{ui::VKEY_9,
ui::DomCode::DIGIT9,
ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::CHARACTER,
'9'}},
};
for (size_t i = 0; i < arraysize(a2c_tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, a2c_tests[i]);
}
// Remap Control to Search.
IntegerPrefMember control;
control.Init(prefs::kLanguageRemapControlKeyTo, &prefs);
control.SetValue(chromeos::input_method::kSearchKey);
KeyTestCase c2s_tests[] = {
// Press left Control. Confirm the event is now VKEY_LWIN.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0},
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0}},
// Then, press all of the three, Control+Alt+Search.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::ALT,
0}},
// Press Shift+Control+Alt+Search.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LWIN,
ui::DomCode::OS_LEFT,
ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN |
ui::EF_COMMAND_DOWN,
ui::DomKey::OS,
0},
{ui::VKEY_MENU,
ui::DomCode::ALT_LEFT,
ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN |
ui::EF_COMMAND_DOWN,
ui::DomKey::ALT,
0}},
// Press Shift+Control+Alt+Search+B
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_B,
ui::DomCode::KEY_B,
ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN |
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'B'},
{ui::VKEY_B,
ui::DomCode::KEY_B,
ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN |
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'B'}},
};
for (size_t i = 0; i < arraysize(c2s_tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, c2s_tests[i]);
}
}
TEST_F(EventRewriterTest, TestRewriteModifiersRemapToCapsLock) {
// Remap Search to Caps Lock.
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
IntegerPrefMember search;
search.Init(prefs::kLanguageRemapSearchKeyTo, &prefs);
search.SetValue(chromeos::input_method::kCapsLockKey);
chromeos::input_method::FakeImeKeyboard ime_keyboard;
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
rewriter.set_ime_keyboard_for_testing(&ime_keyboard);
EXPECT_FALSE(ime_keyboard.caps_lock_is_enabled_);
// Press Search.
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_CAPITAL,
ui::DomCode::CAPS_LOCK,
ui::EF_CAPS_LOCK_DOWN | ui::EF_MOD3_DOWN,
ui::DomKey::CAPS_LOCK, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED,
ui::VKEY_LWIN, ui::DomCode::OS_LEFT,
ui::EF_COMMAND_DOWN, ui::DomKey::OS, 0));
// Confirm that the Caps Lock status is changed.
EXPECT_TRUE(ime_keyboard.caps_lock_is_enabled_);
// Release Search.
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_RELEASED, ui::VKEY_CAPITAL,
ui::DomCode::CAPS_LOCK, ui::EF_NONE,
ui::DomKey::CAPS_LOCK, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_RELEASED,
ui::VKEY_LWIN, ui::DomCode::OS_LEFT,
ui::EF_NONE, ui::DomKey::OS, 0));
// Confirm that the Caps Lock status is not changed.
EXPECT_TRUE(ime_keyboard.caps_lock_is_enabled_);
// Press Search.
EXPECT_EQ(
GetExpectedResultAsString(
ui::ET_KEY_PRESSED, ui::VKEY_CAPITAL, ui::DomCode::CAPS_LOCK,
ui::EF_CAPS_LOCK_DOWN | ui::EF_MOD3_DOWN, ui::DomKey::CAPS_LOCK, 0),
GetRewrittenEventAsString(
&rewriter, ui::ET_KEY_PRESSED, ui::VKEY_LWIN, ui::DomCode::OS_LEFT,
ui::EF_COMMAND_DOWN | ui::EF_CAPS_LOCK_DOWN, ui::DomKey::OS, 0));
// Confirm that the Caps Lock status is changed.
EXPECT_FALSE(ime_keyboard.caps_lock_is_enabled_);
// Release Search.
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_RELEASED, ui::VKEY_CAPITAL,
ui::DomCode::CAPS_LOCK, ui::EF_NONE,
ui::DomKey::CAPS_LOCK, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_RELEASED,
ui::VKEY_LWIN, ui::DomCode::OS_LEFT,
ui::EF_NONE, ui::DomKey::OS, 0));
// Confirm that the Caps Lock status is not changed.
EXPECT_FALSE(ime_keyboard.caps_lock_is_enabled_);
// Press Caps Lock (on an external keyboard).
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_CAPITAL,
ui::DomCode::CAPS_LOCK,
ui::EF_CAPS_LOCK_DOWN | ui::EF_MOD3_DOWN,
ui::DomKey::CAPS_LOCK, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED,
ui::VKEY_CAPITAL, ui::DomCode::CAPS_LOCK,
ui::EF_CAPS_LOCK_DOWN | ui::EF_MOD3_DOWN,
ui::DomKey::CAPS_LOCK, 0));
// Confirm that calling RewriteForTesting() does not change the state of
// |ime_keyboard|. In this case, X Window system itself should change the
// Caps Lock state, not ash::EventRewriter.
EXPECT_FALSE(ime_keyboard.caps_lock_is_enabled_);
// Release Caps Lock (on an external keyboard).
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_RELEASED, ui::VKEY_CAPITAL,
ui::DomCode::CAPS_LOCK, ui::EF_NONE,
ui::DomKey::CAPS_LOCK, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_RELEASED,
ui::VKEY_CAPITAL, ui::DomCode::CAPS_LOCK,
ui::EF_NONE, ui::DomKey::CAPS_LOCK, 0));
EXPECT_FALSE(ime_keyboard.caps_lock_is_enabled_);
}
TEST_F(EventRewriterTest, TestRewriteCapsLock) {
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
chromeos::input_method::FakeImeKeyboard ime_keyboard;
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
rewriter.set_ime_keyboard_for_testing(&ime_keyboard);
EXPECT_FALSE(ime_keyboard.caps_lock_is_enabled_);
// On Chrome OS, CapsLock is mapped to F16 with Mod3Mask.
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_CAPITAL,
ui::DomCode::CAPS_LOCK,
ui::EF_CAPS_LOCK_DOWN | ui::EF_MOD3_DOWN,
ui::DomKey::CAPS_LOCK, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED,
ui::VKEY_F16, ui::DomCode::F16,
ui::EF_MOD3_DOWN, ui::DomKey::F16, 0));
EXPECT_TRUE(ime_keyboard.caps_lock_is_enabled_);
}
TEST_F(EventRewriterTest, TestRewriteDiamondKey) {
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
chromeos::input_method::FakeImeKeyboard ime_keyboard;
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
rewriter.set_ime_keyboard_for_testing(&ime_keyboard);
KeyTestCase tests[] = {
// F15 should work as Ctrl when --has-chromeos-diamond-key is not
// specified.
{KeyTestCase::TEST_VKEY,
ui::ET_KEY_PRESSED,
{ui::VKEY_F15, ui::DomCode::F15, ui::EF_NONE, ui::DomKey::F15, 0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN,
ui::DomKey::CONTROL,
0}},
{KeyTestCase::TEST_VKEY,
ui::ET_KEY_RELEASED,
{ui::VKEY_F15, ui::DomCode::F15, ui::EF_NONE, ui::DomKey::F15, 0},
{ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT,
ui::EF_NONE,
ui::DomKey::CONTROL,
0}},
// However, Mod2Mask should not be rewritten to CtrlMask when
// --has-chromeos-diamond-key is not specified.
{KeyTestCase::TEST_VKEY,
ui::ET_KEY_PRESSED,
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'a'},
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'a'}},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, tests[i]);
}
}
TEST_F(EventRewriterTest, TestRewriteDiamondKeyWithFlag) {
const base::CommandLine original_cl(*base::CommandLine::ForCurrentProcess());
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
chromeos::switches::kHasChromeOSDiamondKey, "");
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
chromeos::input_method::FakeImeKeyboard ime_keyboard;
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
rewriter.set_ime_keyboard_for_testing(&ime_keyboard);
// By default, F15 should work as Control.
EXPECT_EQ(GetExpectedResultAsString(
ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN, ui::DomKey::CONTROL, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED,
ui::VKEY_F15, ui::DomCode::F15,
ui::EF_NONE, ui::DomKey::F15, 0));
// Check that Control is applied to a subsequent key press.
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_CONTROL_DOWN,
ui::DomKey::CHARACTER, 'a'),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'));
// Release F15
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT, ui::EF_NONE,
ui::DomKey::CONTROL, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_RELEASED,
ui::VKEY_F15, ui::DomCode::F15,
ui::EF_NONE, ui::DomKey::F15, 0));
// Check that Control is no longer applied to a subsequent key press.
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'));
IntegerPrefMember diamond;
diamond.Init(prefs::kLanguageRemapDiamondKeyTo, &prefs);
diamond.SetValue(chromeos::input_method::kVoidKey);
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN,
ui::DomCode::NONE, ui::EF_NONE,
ui::DomKey::NONE, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED,
ui::VKEY_F15, ui::DomCode::F15,
ui::EF_NONE, ui::DomKey::F15, 0));
// Check that no modifier is applied to another key.
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'));
diamond.SetValue(chromeos::input_method::kControlKey);
EXPECT_EQ(GetExpectedResultAsString(
ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT,
ui::EF_CONTROL_DOWN, ui::DomKey::CONTROL, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED,
ui::VKEY_F15, ui::DomCode::F15,
ui::EF_NONE, ui::DomKey::F15, 0));
// Check that Control is applied to a subsequent key press.
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_CONTROL_DOWN,
ui::DomKey::CHARACTER, 'a'),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'));
// Release F15
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT, ui::EF_NONE,
ui::DomKey::CONTROL, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_RELEASED,
ui::VKEY_F15, ui::DomCode::F15,
ui::EF_NONE, ui::DomKey::F15, 0));
// Check that Control is no longer applied to a subsequent key press.
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'));
diamond.SetValue(chromeos::input_method::kAltKey);
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_MENU,
ui::DomCode::ALT_LEFT, ui::EF_ALT_DOWN,
ui::DomKey::ALT, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED,
ui::VKEY_F15, ui::DomCode::F15,
ui::EF_NONE, ui::DomKey::F15, 0));
// Check that Alt is applied to a subsequent key press.
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_ALT_DOWN,
ui::DomKey::CHARACTER, 'a'),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'));
// Release F15
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_RELEASED, ui::VKEY_MENU,
ui::DomCode::ALT_LEFT, ui::EF_NONE,
ui::DomKey::ALT, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_RELEASED,
ui::VKEY_F15, ui::DomCode::F15,
ui::EF_NONE, ui::DomKey::F15, 0));
// Check that Alt is no longer applied to a subsequent key press.
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'));
diamond.SetValue(chromeos::input_method::kCapsLockKey);
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_CAPITAL,
ui::DomCode::CAPS_LOCK,
ui::EF_CAPS_LOCK_DOWN | ui::EF_MOD3_DOWN,
ui::DomKey::CAPS_LOCK, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED,
ui::VKEY_F15, ui::DomCode::F15,
ui::EF_NONE, ui::DomKey::F15, 0));
// Check that Caps is applied to a subsequent key press.
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_CAPS_LOCK_DOWN | ui::EF_MOD3_DOWN,
ui::DomKey::CHARACTER, 'a'),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'));
// Release F15
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_RELEASED, ui::VKEY_CAPITAL,
ui::DomCode::CAPS_LOCK, ui::EF_NONE,
ui::DomKey::CAPS_LOCK, 0),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_RELEASED,
ui::VKEY_F15, ui::DomCode::F15,
ui::EF_NONE, ui::DomKey::F15, 0));
// Check that Control is no longer applied to a subsequent key press.
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'));
*base::CommandLine::ForCurrentProcess() = original_cl;
}
TEST_F(EventRewriterTest, TestRewriteCapsLockToControl) {
// Remap CapsLock to Control.
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
IntegerPrefMember control;
control.Init(prefs::kLanguageRemapCapsLockKeyTo, &prefs);
control.SetValue(chromeos::input_method::kControlKey);
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase tests[] = {
// Press CapsLock+a. Confirm that Mod3Mask is rewritten to ControlMask.
// On Chrome OS, CapsLock works as a Mod3 modifier.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_MOD3_DOWN,
ui::DomKey::CHARACTER,
'a'},
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_CONTROL_DOWN,
ui::DomKey::CHARACTER,
'a'}},
// Press Control+CapsLock+a. Confirm that Mod3Mask is rewritten to
// ControlMask
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_CONTROL_DOWN | ui::EF_MOD3_DOWN,
ui::DomKey::CHARACTER,
'a'},
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_CONTROL_DOWN,
ui::DomKey::CHARACTER,
'a'}},
// Press Alt+CapsLock+a. Confirm that Mod3Mask is rewritten to
// ControlMask.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_ALT_DOWN | ui::EF_MOD3_DOWN,
ui::DomKey::CHARACTER,
'a'},
{ui::VKEY_A,
ui::DomCode::KEY_A,
ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::CHARACTER,
'a'}},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, tests[i]);
}
}
TEST_F(EventRewriterTest, TestRewriteCapsLockMod3InUse) {
// Remap CapsLock to Control.
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
IntegerPrefMember control;
control.Init(prefs::kLanguageRemapCapsLockKeyTo, &prefs);
control.SetValue(chromeos::input_method::kControlKey);
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
input_method_manager_mock_->set_mod3_used(true);
// Press CapsLock+a. Confirm that Mod3Mask is NOT rewritten to ControlMask
// when Mod3Mask is already in use by the current XKB layout.
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'),
GetRewrittenEventAsString(&rewriter, ui::ET_KEY_PRESSED, ui::VKEY_A,
ui::DomCode::KEY_A, ui::EF_NONE,
ui::DomKey::CHARACTER, 'a'));
input_method_manager_mock_->set_mod3_used(false);
}
TEST_F(EventRewriterTest, TestRewriteExtendedKeys) {
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_last_keyboard_device_id_for_testing(kKeyboardDeviceId);
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase tests[] = {
// Alt+Backspace -> Delete
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_BACK,
ui::DomCode::BACKSPACE,
ui::EF_ALT_DOWN,
ui::DomKey::BACKSPACE,
0},
{ui::VKEY_DELETE, ui::DomCode::DEL, ui::EF_NONE, ui::DomKey::DEL, 0}},
// Control+Alt+Backspace -> Control+Delete
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_BACK,
ui::DomCode::BACKSPACE,
ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::BACKSPACE,
0},
{ui::VKEY_DELETE,
ui::DomCode::DEL,
ui::EF_CONTROL_DOWN,
ui::DomKey::DEL,
0}},
// Search+Alt+Backspace -> Alt+Backspace
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_BACK,
ui::DomCode::BACKSPACE,
ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::BACKSPACE,
0},
{ui::VKEY_BACK,
ui::DomCode::BACKSPACE,
ui::EF_ALT_DOWN,
ui::DomKey::BACKSPACE,
0}},
// Search+Control+Alt+Backspace -> Control+Alt+Backspace
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_BACK,
ui::DomCode::BACKSPACE,
ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::BACKSPACE,
0},
{ui::VKEY_BACK,
ui::DomCode::BACKSPACE,
ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::BACKSPACE,
0}},
// Alt+Up -> Prior
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_UP,
ui::DomCode::ARROW_UP,
ui::EF_ALT_DOWN,
ui::DomKey::ARROW_UP,
0},
{ui::VKEY_PRIOR,
ui::DomCode::PAGE_UP,
ui::EF_NONE,
ui::DomKey::PAGE_UP,
0}},
// Alt+Down -> Next
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_DOWN,
ui::DomCode::ARROW_DOWN,
ui::EF_ALT_DOWN,
ui::DomKey::ARROW_DOWN,
0},
{ui::VKEY_NEXT,
ui::DomCode::PAGE_DOWN,
ui::EF_NONE,
ui::DomKey::PAGE_DOWN,
0}},
// Ctrl+Alt+Up -> Home
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_UP,
ui::DomCode::ARROW_UP,
ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::ARROW_UP,
0},
{ui::VKEY_HOME, ui::DomCode::HOME, ui::EF_NONE, ui::DomKey::HOME, 0}},
// Ctrl+Alt+Down -> End
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_DOWN,
ui::DomCode::ARROW_DOWN,
ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::ARROW_DOWN,
0},
{ui::VKEY_END, ui::DomCode::END, ui::EF_NONE, ui::DomKey::END, 0}},
// Search+Alt+Up -> Alt+Up
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_UP,
ui::DomCode::ARROW_UP,
ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::ARROW_UP,
0},
{ui::VKEY_UP,
ui::DomCode::ARROW_UP,
ui::EF_ALT_DOWN,
ui::DomKey::ARROW_UP,
0}},
// Search+Alt+Down -> Alt+Down
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_DOWN,
ui::DomCode::ARROW_DOWN,
ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN,
ui::DomKey::ARROW_DOWN,
0},
{ui::VKEY_DOWN,
ui::DomCode::ARROW_DOWN,
ui::EF_ALT_DOWN,
ui::DomKey::ARROW_DOWN,
0}},
// Search+Ctrl+Alt+Up -> Search+Ctrl+Alt+Up
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_UP,
ui::DomCode::ARROW_UP,
ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::ARROW_UP,
0},
{ui::VKEY_UP,
ui::DomCode::ARROW_UP,
ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::ARROW_UP,
0}},
// Search+Ctrl+Alt+Down -> Ctrl+Alt+Down
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_DOWN,
ui::DomCode::ARROW_DOWN,
ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::ARROW_DOWN,
0},
{ui::VKEY_DOWN,
ui::DomCode::ARROW_DOWN,
ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::ARROW_DOWN,
0}},
// Period -> Period
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_OEM_PERIOD,
ui::DomCode::PERIOD,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'.'},
{ui::VKEY_OEM_PERIOD,
ui::DomCode::PERIOD,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'.'}},
// Search+Backspace -> Delete
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_BACK,
ui::DomCode::BACKSPACE,
ui::EF_COMMAND_DOWN,
ui::DomKey::BACKSPACE,
0},
{ui::VKEY_DELETE, ui::DomCode::DEL, ui::EF_NONE, ui::DomKey::DEL, 0}},
// Search+Up -> Prior
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_UP,
ui::DomCode::ARROW_UP,
ui::EF_COMMAND_DOWN,
ui::DomKey::ARROW_UP,
0},
{ui::VKEY_PRIOR,
ui::DomCode::PAGE_UP,
ui::EF_NONE,
ui::DomKey::PAGE_UP,
0}},
// Search+Down -> Next
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_DOWN,
ui::DomCode::ARROW_DOWN,
ui::EF_COMMAND_DOWN,
ui::DomKey::ARROW_DOWN,
0},
{ui::VKEY_NEXT,
ui::DomCode::PAGE_DOWN,
ui::EF_NONE,
ui::DomKey::PAGE_DOWN,
0}},
// Search+Left -> Home
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LEFT,
ui::DomCode::ARROW_LEFT,
ui::EF_COMMAND_DOWN,
ui::DomKey::ARROW_LEFT,
0},
{ui::VKEY_HOME, ui::DomCode::HOME, ui::EF_NONE, ui::DomKey::HOME, 0}},
// Control+Search+Left -> Home
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_LEFT,
ui::DomCode::ARROW_LEFT,
ui::EF_COMMAND_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::ARROW_LEFT,
0},
{ui::VKEY_HOME,
ui::DomCode::HOME,
ui::EF_CONTROL_DOWN,
ui::DomKey::HOME,
0}},
// Search+Right -> End
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_RIGHT,
ui::DomCode::ARROW_RIGHT,
ui::EF_COMMAND_DOWN,
ui::DomKey::ARROW_RIGHT,
0},
{ui::VKEY_END, ui::DomCode::END, ui::EF_NONE, ui::DomKey::END, 0}},
// Control+Search+Right -> End
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_RIGHT,
ui::DomCode::ARROW_RIGHT,
ui::EF_COMMAND_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::ARROW_RIGHT,
0},
{ui::VKEY_END,
ui::DomCode::END,
ui::EF_CONTROL_DOWN,
ui::DomKey::END,
0}},
// Search+Period -> Insert
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_OEM_PERIOD,
ui::DomCode::PERIOD,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'.'},
{ui::VKEY_INSERT,
ui::DomCode::INSERT,
ui::EF_NONE,
ui::DomKey::INSERT,
0}},
// Control+Search+Period -> Control+Insert
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_OEM_PERIOD,
ui::DomCode::PERIOD,
ui::EF_COMMAND_DOWN | ui::EF_CONTROL_DOWN,
ui::DomKey::CHARACTER,
'.'},
{ui::VKEY_INSERT,
ui::DomCode::INSERT,
ui::EF_CONTROL_DOWN,
ui::DomKey::INSERT,
0}}};
for (size_t i = 0; i < arraysize(tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, tests[i]);
}
}
TEST_F(EventRewriterTest, TestRewriteFunctionKeys) {
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase tests[] = {
// F1 -> Back
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F1, ui::DomCode::F1, ui::EF_NONE, ui::DomKey::F1, 0},
{ui::VKEY_BROWSER_BACK,
ui::DomCode::BROWSER_BACK,
ui::EF_NONE,
ui::DomKey::BROWSER_BACK,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F1, ui::DomCode::F1, ui::EF_CONTROL_DOWN, ui::DomKey::F1, 0},
{ui::VKEY_BROWSER_BACK,
ui::DomCode::BROWSER_BACK,
ui::EF_CONTROL_DOWN,
ui::DomKey::BROWSER_BACK,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F1, ui::DomCode::F1, ui::EF_ALT_DOWN, ui::DomKey::F1, 0},
{ui::VKEY_BROWSER_BACK,
ui::DomCode::BROWSER_BACK,
ui::EF_ALT_DOWN,
ui::DomKey::BROWSER_BACK,
0}},
// F2 -> Forward
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F2, ui::DomCode::F2, ui::EF_NONE, ui::DomKey::F2, 0},
{ui::VKEY_BROWSER_FORWARD,
ui::DomCode::BROWSER_FORWARD,
ui::EF_NONE,
ui::DomKey::BROWSER_FORWARD,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F2, ui::DomCode::F2, ui::EF_CONTROL_DOWN, ui::DomKey::F2, 0},
{ui::VKEY_BROWSER_FORWARD,
ui::DomCode::BROWSER_FORWARD,
ui::EF_CONTROL_DOWN,
ui::DomKey::BROWSER_FORWARD,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F2, ui::DomCode::F2, ui::EF_ALT_DOWN, ui::DomKey::F2, 0},
{ui::VKEY_BROWSER_FORWARD,
ui::DomCode::BROWSER_FORWARD,
ui::EF_ALT_DOWN,
ui::DomKey::BROWSER_FORWARD,
0}},
// F3 -> Refresh
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F3, ui::DomCode::F3, ui::EF_NONE, ui::DomKey::F3, 0},
{ui::VKEY_BROWSER_REFRESH,
ui::DomCode::BROWSER_REFRESH,
ui::EF_NONE,
ui::DomKey::BROWSER_REFRESH,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F3, ui::DomCode::F3, ui::EF_CONTROL_DOWN, ui::DomKey::F3, 0},
{ui::VKEY_BROWSER_REFRESH,
ui::DomCode::BROWSER_REFRESH,
ui::EF_CONTROL_DOWN,
ui::DomKey::BROWSER_REFRESH,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F3, ui::DomCode::F3, ui::EF_ALT_DOWN, ui::DomKey::F3, 0},
{ui::VKEY_BROWSER_REFRESH,
ui::DomCode::BROWSER_REFRESH,
ui::EF_ALT_DOWN,
ui::DomKey::BROWSER_REFRESH,
0}},
// F4 -> Launch App 2
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F4, ui::DomCode::F4, ui::EF_NONE, ui::DomKey::F4, 0},
{ui::VKEY_MEDIA_LAUNCH_APP2,
ui::DomCode::ZOOM_TOGGLE,
ui::EF_NONE,
ui::DomKey::ZOOM_TOGGLE,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F4, ui::DomCode::F4, ui::EF_CONTROL_DOWN, ui::DomKey::F4, 0},
{ui::VKEY_MEDIA_LAUNCH_APP2,
ui::DomCode::ZOOM_TOGGLE,
ui::EF_CONTROL_DOWN,
ui::DomKey::ZOOM_TOGGLE,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F4, ui::DomCode::F4, ui::EF_ALT_DOWN, ui::DomKey::F4, 0},
{ui::VKEY_MEDIA_LAUNCH_APP2,
ui::DomCode::ZOOM_TOGGLE,
ui::EF_ALT_DOWN,
ui::DomKey::ZOOM_TOGGLE,
0}},
// F5 -> Launch App 1
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F5, ui::DomCode::F5, ui::EF_NONE, ui::DomKey::F5, 0},
{ui::VKEY_MEDIA_LAUNCH_APP1,
ui::DomCode::SELECT_TASK,
ui::EF_NONE,
ui::DomKey::LAUNCH_MY_COMPUTER,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F5, ui::DomCode::F5, ui::EF_CONTROL_DOWN, ui::DomKey::F5, 0},
{ui::VKEY_MEDIA_LAUNCH_APP1,
ui::DomCode::SELECT_TASK,
ui::EF_CONTROL_DOWN,
ui::DomKey::LAUNCH_MY_COMPUTER,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F5, ui::DomCode::F5, ui::EF_ALT_DOWN, ui::DomKey::F5, 0},
{ui::VKEY_MEDIA_LAUNCH_APP1,
ui::DomCode::SELECT_TASK,
ui::EF_ALT_DOWN,
ui::DomKey::LAUNCH_MY_COMPUTER,
0}},
// F6 -> Brightness down
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F6, ui::DomCode::F6, ui::EF_NONE, ui::DomKey::F6, 0},
{ui::VKEY_BRIGHTNESS_DOWN,
ui::DomCode::BRIGHTNESS_DOWN,
ui::EF_NONE,
ui::DomKey::BRIGHTNESS_DOWN,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F6, ui::DomCode::F6, ui::EF_CONTROL_DOWN, ui::DomKey::F6, 0},
{ui::VKEY_BRIGHTNESS_DOWN,
ui::DomCode::BRIGHTNESS_DOWN,
ui::EF_CONTROL_DOWN,
ui::DomKey::BRIGHTNESS_DOWN,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F6, ui::DomCode::F6, ui::EF_ALT_DOWN, ui::DomKey::F6, 0},
{ui::VKEY_BRIGHTNESS_DOWN,
ui::DomCode::BRIGHTNESS_DOWN,
ui::EF_ALT_DOWN,
ui::DomKey::BRIGHTNESS_DOWN,
0}},
// F7 -> Brightness up
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F7, ui::DomCode::F7, ui::EF_NONE, ui::DomKey::F7, 0},
{ui::VKEY_BRIGHTNESS_UP,
ui::DomCode::BRIGHTNESS_UP,
ui::EF_NONE,
ui::DomKey::BRIGHTNESS_UP,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F7, ui::DomCode::F7, ui::EF_CONTROL_DOWN, ui::DomKey::F7, 0},
{ui::VKEY_BRIGHTNESS_UP,
ui::DomCode::BRIGHTNESS_UP,
ui::EF_CONTROL_DOWN,
ui::DomKey::BRIGHTNESS_UP,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F7, ui::DomCode::F7, ui::EF_ALT_DOWN, ui::DomKey::F7, 0},
{ui::VKEY_BRIGHTNESS_UP,
ui::DomCode::BRIGHTNESS_UP,
ui::EF_ALT_DOWN,
ui::DomKey::BRIGHTNESS_UP,
0}},
// F8 -> Volume Mute
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F8, ui::DomCode::F8, ui::EF_NONE, ui::DomKey::F8, 0},
{ui::VKEY_VOLUME_MUTE,
ui::DomCode::VOLUME_MUTE,
ui::EF_NONE,
ui::DomKey::VOLUME_MUTE,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F8, ui::DomCode::F8, ui::EF_CONTROL_DOWN, ui::DomKey::F8, 0},
{ui::VKEY_VOLUME_MUTE,
ui::DomCode::VOLUME_MUTE,
ui::EF_CONTROL_DOWN,
ui::DomKey::VOLUME_MUTE,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F8, ui::DomCode::F8, ui::EF_ALT_DOWN, ui::DomKey::F8, 0},
{ui::VKEY_VOLUME_MUTE,
ui::DomCode::VOLUME_MUTE,
ui::EF_ALT_DOWN,
ui::DomKey::VOLUME_MUTE,
0}},
// F9 -> Volume Down
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F9, ui::DomCode::F9, ui::EF_NONE, ui::DomKey::F9, 0},
{ui::VKEY_VOLUME_DOWN,
ui::DomCode::VOLUME_DOWN,
ui::EF_NONE,
ui::DomKey::VOLUME_DOWN,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F9, ui::DomCode::F9, ui::EF_CONTROL_DOWN, ui::DomKey::F9, 0},
{ui::VKEY_VOLUME_DOWN,
ui::DomCode::VOLUME_DOWN,
ui::EF_CONTROL_DOWN,
ui::DomKey::VOLUME_DOWN,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F9, ui::DomCode::F9, ui::EF_ALT_DOWN, ui::DomKey::F9, 0},
{ui::VKEY_VOLUME_DOWN,
ui::DomCode::VOLUME_DOWN,
ui::EF_ALT_DOWN,
ui::DomKey::VOLUME_DOWN,
0}},
// F10 -> Volume Up
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F10, ui::DomCode::F10, ui::EF_NONE, ui::DomKey::F10, 0},
{ui::VKEY_VOLUME_UP,
ui::DomCode::VOLUME_UP,
ui::EF_NONE,
ui::DomKey::VOLUME_UP,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F10,
ui::DomCode::F10,
ui::EF_CONTROL_DOWN,
ui::DomKey::F10,
0},
{ui::VKEY_VOLUME_UP,
ui::DomCode::VOLUME_UP,
ui::EF_CONTROL_DOWN,
ui::DomKey::VOLUME_UP,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F10, ui::DomCode::F10, ui::EF_ALT_DOWN, ui::DomKey::F10, 0},
{ui::VKEY_VOLUME_UP,
ui::DomCode::VOLUME_UP,
ui::EF_ALT_DOWN,
ui::DomKey::VOLUME_UP,
0}},
// F11 -> F11
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F11, ui::DomCode::F11, ui::EF_NONE, ui::DomKey::F11, 0},
{ui::VKEY_F11, ui::DomCode::F11, ui::EF_NONE, ui::DomKey::F11, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F11,
ui::DomCode::F11,
ui::EF_CONTROL_DOWN,
ui::DomKey::F11,
0},
{ui::VKEY_F11,
ui::DomCode::F11,
ui::EF_CONTROL_DOWN,
ui::DomKey::F11,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F11, ui::DomCode::F11, ui::EF_ALT_DOWN, ui::DomKey::F11, 0},
{ui::VKEY_F11, ui::DomCode::F11, ui::EF_ALT_DOWN, ui::DomKey::F11, 0}},
// F12 -> F12
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F12, ui::DomCode::F12, ui::EF_NONE, ui::DomKey::F12, 0},
{ui::VKEY_F12, ui::DomCode::F12, ui::EF_NONE, ui::DomKey::F12, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F12,
ui::DomCode::F12,
ui::EF_CONTROL_DOWN,
ui::DomKey::F12,
0},
{ui::VKEY_F12,
ui::DomCode::F12,
ui::EF_CONTROL_DOWN,
ui::DomKey::F12,
0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F12, ui::DomCode::F12, ui::EF_ALT_DOWN, ui::DomKey::F12, 0},
{ui::VKEY_F12, ui::DomCode::F12, ui::EF_ALT_DOWN, ui::DomKey::F12, 0}},
// The number row should not be rewritten without Search key.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_1,
ui::DomCode::DIGIT1,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'1'},
{ui::VKEY_1,
ui::DomCode::DIGIT1,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'1'}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_2,
ui::DomCode::DIGIT2,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'2'},
{ui::VKEY_2,
ui::DomCode::DIGIT2,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'2'}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_3,
ui::DomCode::DIGIT3,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'3'},
{ui::VKEY_3,
ui::DomCode::DIGIT3,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'3'}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_4,
ui::DomCode::DIGIT4,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'4'},
{ui::VKEY_4,
ui::DomCode::DIGIT4,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'4'}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_5,
ui::DomCode::DIGIT5,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'5'},
{ui::VKEY_5,
ui::DomCode::DIGIT5,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'5'}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_6,
ui::DomCode::DIGIT6,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'6'},
{ui::VKEY_6,
ui::DomCode::DIGIT6,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'6'}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_7,
ui::DomCode::DIGIT7,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'7'},
{ui::VKEY_7,
ui::DomCode::DIGIT7,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'7'}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_8,
ui::DomCode::DIGIT8,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'8'},
{ui::VKEY_8,
ui::DomCode::DIGIT8,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'8'}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_9,
ui::DomCode::DIGIT9,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'9'},
{ui::VKEY_9,
ui::DomCode::DIGIT9,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'9'}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_0,
ui::DomCode::DIGIT0,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'0'},
{ui::VKEY_0,
ui::DomCode::DIGIT0,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'0'}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_OEM_MINUS,
ui::DomCode::MINUS,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'-'},
{ui::VKEY_OEM_MINUS,
ui::DomCode::MINUS,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'-'}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_OEM_PLUS,
ui::DomCode::EQUAL,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'='},
{ui::VKEY_OEM_PLUS,
ui::DomCode::EQUAL,
ui::EF_NONE,
ui::DomKey::CHARACTER,
'='}},
// The number row should be rewritten as the F<number> row with Search
// key.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_1,
ui::DomCode::DIGIT1,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'1'},
{ui::VKEY_F1, ui::DomCode::F1, ui::EF_NONE, ui::DomKey::F1, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_2,
ui::DomCode::DIGIT2,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'2'},
{ui::VKEY_F2, ui::DomCode::F2, ui::EF_NONE, ui::DomKey::F2, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_3,
ui::DomCode::DIGIT3,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'3'},
{ui::VKEY_F3, ui::DomCode::F3, ui::EF_NONE, ui::DomKey::F3, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_4,
ui::DomCode::DIGIT4,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'4'},
{ui::VKEY_F4, ui::DomCode::F4, ui::EF_NONE, ui::DomKey::F4, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_5,
ui::DomCode::DIGIT5,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'5'},
{ui::VKEY_F5, ui::DomCode::F5, ui::EF_NONE, ui::DomKey::F5, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_6,
ui::DomCode::DIGIT6,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'6'},
{ui::VKEY_F6, ui::DomCode::F6, ui::EF_NONE, ui::DomKey::F6, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_7,
ui::DomCode::DIGIT7,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'7'},
{ui::VKEY_F7, ui::DomCode::F7, ui::EF_NONE, ui::DomKey::F7, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_8,
ui::DomCode::DIGIT8,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'8'},
{ui::VKEY_F8, ui::DomCode::F8, ui::EF_NONE, ui::DomKey::F8, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_9,
ui::DomCode::DIGIT9,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'9'},
{ui::VKEY_F9, ui::DomCode::F9, ui::EF_NONE, ui::DomKey::F9, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_0,
ui::DomCode::DIGIT0,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'0'},
{ui::VKEY_F10, ui::DomCode::F10, ui::EF_NONE, ui::DomKey::F10, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_OEM_MINUS,
ui::DomCode::MINUS,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'-'},
{ui::VKEY_F11, ui::DomCode::F11, ui::EF_NONE, ui::DomKey::F11, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_OEM_PLUS,
ui::DomCode::EQUAL,
ui::EF_COMMAND_DOWN,
ui::DomKey::CHARACTER,
'='},
{ui::VKEY_F12, ui::DomCode::F12, ui::EF_NONE, ui::DomKey::F12, 0}},
// The function keys should not be rewritten with Search key pressed.
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F1, ui::DomCode::F1, ui::EF_COMMAND_DOWN, ui::DomKey::F1, 0},
{ui::VKEY_F1, ui::DomCode::F1, ui::EF_NONE, ui::DomKey::F1, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F2, ui::DomCode::F2, ui::EF_COMMAND_DOWN, ui::DomKey::F2, 0},
{ui::VKEY_F2, ui::DomCode::F2, ui::EF_NONE, ui::DomKey::F2, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F3, ui::DomCode::F3, ui::EF_COMMAND_DOWN, ui::DomKey::F3, 0},
{ui::VKEY_F3, ui::DomCode::F3, ui::EF_NONE, ui::DomKey::F3, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F4, ui::DomCode::F4, ui::EF_COMMAND_DOWN, ui::DomKey::F4, 0},
{ui::VKEY_F4, ui::DomCode::F4, ui::EF_NONE, ui::DomKey::F4, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F5, ui::DomCode::F5, ui::EF_COMMAND_DOWN, ui::DomKey::F5, 0},
{ui::VKEY_F5, ui::DomCode::F5, ui::EF_NONE, ui::DomKey::F5, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F6, ui::DomCode::F6, ui::EF_COMMAND_DOWN, ui::DomKey::F6, 0},
{ui::VKEY_F6, ui::DomCode::F6, ui::EF_NONE, ui::DomKey::F6, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F7, ui::DomCode::F7, ui::EF_COMMAND_DOWN, ui::DomKey::F7, 0},
{ui::VKEY_F7, ui::DomCode::F7, ui::EF_NONE, ui::DomKey::F7, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F8, ui::DomCode::F8, ui::EF_COMMAND_DOWN, ui::DomKey::F8, 0},
{ui::VKEY_F8, ui::DomCode::F8, ui::EF_NONE, ui::DomKey::F8, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F9, ui::DomCode::F9, ui::EF_COMMAND_DOWN, ui::DomKey::F9, 0},
{ui::VKEY_F9, ui::DomCode::F9, ui::EF_NONE, ui::DomKey::F9, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F10,
ui::DomCode::F10,
ui::EF_COMMAND_DOWN,
ui::DomKey::F10,
0},
{ui::VKEY_F10, ui::DomCode::F10, ui::EF_NONE, ui::DomKey::F10, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F11,
ui::DomCode::F11,
ui::EF_COMMAND_DOWN,
ui::DomKey::F11,
0},
{ui::VKEY_F11, ui::DomCode::F11, ui::EF_NONE, ui::DomKey::F11, 0}},
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_F12,
ui::DomCode::F12,
ui::EF_COMMAND_DOWN,
ui::DomKey::F12,
0},
{ui::VKEY_F12, ui::DomCode::F12, ui::EF_NONE, ui::DomKey::F12, 0}}};
for (size_t i = 0; i < arraysize(tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, tests[i]);
}
}
TEST_F(EventRewriterTest, TestRewriteExtendedKeysWithSearchRemapped) {
const base::CommandLine original_cl(*base::CommandLine::ForCurrentProcess());
// Remap Search to Control.
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
IntegerPrefMember search;
search.Init(prefs::kLanguageRemapSearchKeyTo, &prefs);
search.SetValue(chromeos::input_method::kControlKey);
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
chromeos::switches::kHasChromeOSKeyboard, "");
KeyTestCase tests[] = {
// Alt+Search+Down -> End
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_DOWN,
ui::DomCode::ARROW_DOWN,
ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::ARROW_DOWN,
0},
{ui::VKEY_END, ui::DomCode::END, ui::EF_NONE, ui::DomKey::END, 0}},
// Shift+Alt+Search+Down -> Shift+End
{KeyTestCase::TEST_ALL,
ui::ET_KEY_PRESSED,
{ui::VKEY_DOWN,
ui::DomCode::ARROW_DOWN,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
ui::DomKey::ARROW_DOWN,
0},
{ui::VKEY_END, ui::DomCode::END, ui::EF_SHIFT_DOWN, ui::DomKey::END, 0}},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
SCOPED_TRACE(i);
CheckKeyTestCase(&rewriter, tests[i]);
}
*base::CommandLine::ForCurrentProcess() = original_cl;
}
TEST_F(EventRewriterTest, TestRewriteKeyEventSentByXSendEvent) {
// Remap Control to Alt.
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
IntegerPrefMember control;
control.Init(prefs::kLanguageRemapControlKeyTo, &prefs);
control.SetValue(chromeos::input_method::kAltKey);
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
// Send left control press.
{
ui::KeyEvent keyevent(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL,
ui::DomCode::CONTROL_LEFT, ui::EF_FINAL,
ui::DomKey::CONTROL, 0, ui::EventTimeForNow());
scoped_ptr<ui::Event> new_event;
// Control should NOT be remapped to Alt if EF_FINAL is set.
EXPECT_EQ(ui::EVENT_REWRITE_CONTINUE,
rewriter.RewriteEvent(keyevent, &new_event));
EXPECT_FALSE(new_event);
}
#if defined(USE_X11)
// Send left control press, using XI2 native events.
{
ui::ScopedXI2Event xev;
xev.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, 0);
XEvent* xevent = xev;
xevent->xkey.keycode = XKeysymToKeycode(gfx::GetXDisplay(), XK_Control_L);
xevent->xkey.send_event = True; // XSendEvent() always does this.
ui::KeyEvent keyevent(xev);
scoped_ptr<ui::Event> new_event;
// Control should NOT be remapped to Alt if send_event
// flag in the event is True.
EXPECT_EQ(ui::EVENT_REWRITE_CONTINUE,
rewriter.RewriteEvent(keyevent, &new_event));
EXPECT_FALSE(new_event);
}
#endif
}
TEST_F(EventRewriterTest, TestRewriteNonNativeEvent) {
// Remap Control to Alt.
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
IntegerPrefMember control;
control.Init(prefs::kLanguageRemapControlKeyTo, &prefs);
control.SetValue(chromeos::input_method::kAltKey);
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
const int kTouchId = 2;
gfx::Point location(0, 0);
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, location, kTouchId,
base::TimeDelta());
press.set_flags(ui::EF_CONTROL_DOWN);
#if defined(USE_X11)
ui::UpdateX11EventForFlags(&press);
#endif
scoped_ptr<ui::Event> new_event;
rewriter.RewriteEvent(press, &new_event);
EXPECT_TRUE(new_event);
// Control should be remapped to Alt.
EXPECT_EQ(ui::EF_ALT_DOWN,
new_event->flags() & (ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN));
}
// Keeps a buffer of handled events.
class EventBuffer : public ui::test::TestEventProcessor {
public:
EventBuffer() {}
~EventBuffer() override {}
void PopEvents(ScopedVector<ui::Event>* events) {
events->clear();
events->swap(events_);
}
private:
// ui::EventProcessor overrides:
ui::EventDispatchDetails OnEventFromSource(ui::Event* event) override {
if (event->IsKeyEvent()) {
events_.push_back(new ui::KeyEvent(*static_cast<ui::KeyEvent*>(event)));
} else if (event->IsMouseWheelEvent()) {
events_.push_back(
new ui::MouseWheelEvent(*static_cast<ui::MouseWheelEvent*>(event)));
} else if (event->IsMouseEvent()) {
events_.push_back(
new ui::MouseEvent(*static_cast<ui::MouseEvent*>(event)));
}
return ui::EventDispatchDetails();
}
ScopedVector<ui::Event> events_;
DISALLOW_COPY_AND_ASSIGN(EventBuffer);
};
// Trivial EventSource that does nothing but send events.
class TestEventSource : public ui::EventSource {
public:
explicit TestEventSource(ui::EventProcessor* processor)
: processor_(processor) {}
ui::EventProcessor* GetEventProcessor() override { return processor_; }
ui::EventDispatchDetails Send(ui::Event* event) {
return SendEventToProcessor(event);
}
private:
ui::EventProcessor* processor_;
};
// Tests of event rewriting that depend on the Ash window manager.
class EventRewriterAshTest : public ash::test::AshTestBase {
public:
EventRewriterAshTest()
: source_(&buffer_),
fake_user_manager_(new user_manager::FakeUserManager),
user_manager_enabler_(fake_user_manager_) {}
~EventRewriterAshTest() override {}
bool RewriteFunctionKeys(const ui::Event& event,
scoped_ptr<ui::Event>* rewritten_event) {
return rewriter_->RewriteEvent(event, rewritten_event);
}
ui::EventDispatchDetails Send(ui::Event* event) {
return source_.Send(event);
}
void SendKeyEvent(ui::EventType type,
ui::KeyboardCode key_code,
ui::DomCode code,
ui::DomKey key,
base::char16 character) {
ui::KeyEvent press(type, key_code, code, ui::EF_NONE, key, character,
ui::EventTimeForNow());
ui::EventDispatchDetails details = Send(&press);
CHECK(!details.dispatcher_destroyed);
}
void SendActivateStickyKeyPattern(ui::KeyboardCode key_code,
ui::DomCode code,
ui::DomKey key,
base::char16 character) {
SendKeyEvent(ui::ET_KEY_PRESSED, key_code, code, key, character);
SendKeyEvent(ui::ET_KEY_RELEASED, key_code, code, key, character);
}
protected:
TestingPrefServiceSyncable* prefs() { return &prefs_; }
void PopEvents(ScopedVector<ui::Event>* events) { buffer_.PopEvents(events); }
void SetUp() override {
AshTestBase::SetUp();
sticky_keys_controller_ =
ash::Shell::GetInstance()->sticky_keys_controller();
rewriter_.reset(new EventRewriter(sticky_keys_controller_));
chromeos::Preferences::RegisterProfilePrefs(prefs_.registry());
rewriter_->set_pref_service_for_testing(&prefs_);
#if defined(USE_X11)
ui::SetUpTouchPadForTest(kTouchPadDeviceId);
#endif
source_.AddEventRewriter(rewriter_.get());
sticky_keys_controller_->Enable(true);
}
void TearDown() override {
rewriter_.reset();
AshTestBase::TearDown();
}
protected:
ash::StickyKeysController* sticky_keys_controller_;
private:
scoped_ptr<EventRewriter> rewriter_;
EventBuffer buffer_;
TestEventSource source_;
user_manager::FakeUserManager* fake_user_manager_; // Not owned.
chromeos::ScopedUserManagerEnabler user_manager_enabler_;
TestingPrefServiceSyncable prefs_;
DISALLOW_COPY_AND_ASSIGN(EventRewriterAshTest);
};
TEST_F(EventRewriterAshTest, TopRowKeysAreFunctionKeys) {
scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(1));
ash::wm::WindowState* window_state = ash::wm::GetWindowState(window.get());
window_state->Activate();
ScopedVector<ui::Event> events;
// Create a simulated keypress of F1 targetted at the window.
ui::KeyEvent press_f1(ui::ET_KEY_PRESSED, ui::VKEY_F1, ui::DomCode::F1,
ui::EF_NONE, ui::DomKey::F1, 0, ui::EventTimeForNow());
// Simulate an apps v2 window that has requested top row keys as function
// keys. The event should not be rewritten.
window_state->set_top_row_keys_are_function_keys(true);
ui::EventDispatchDetails details = Send(&press_f1);
ASSERT_FALSE(details.dispatcher_destroyed);
PopEvents(&events);
EXPECT_EQ(1u, events.size());
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_F1,
ui::DomCode::F1, ui::EF_NONE,
ui::DomKey::F1, 0),
GetKeyEventAsString(*static_cast<ui::KeyEvent*>(events[0])));
// The event should also not be rewritten if the send-function-keys pref is
// additionally set, for both apps v2 and regular windows.
BooleanPrefMember send_function_keys_pref;
send_function_keys_pref.Init(prefs::kLanguageSendFunctionKeys, prefs());
send_function_keys_pref.SetValue(true);
window_state->set_top_row_keys_are_function_keys(false);
details = Send(&press_f1);
ASSERT_FALSE(details.dispatcher_destroyed);
PopEvents(&events);
EXPECT_EQ(1u, events.size());
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_F1,
ui::DomCode::F1, ui::EF_NONE,
ui::DomKey::F1, 0),
GetKeyEventAsString(*static_cast<ui::KeyEvent*>(events[0])));
// If the pref isn't set when an event is sent to a regular window, F1 is
// rewritten to the back key.
send_function_keys_pref.SetValue(false);
details = Send(&press_f1);
ASSERT_FALSE(details.dispatcher_destroyed);
PopEvents(&events);
EXPECT_EQ(1u, events.size());
EXPECT_EQ(GetExpectedResultAsString(ui::ET_KEY_PRESSED, ui::VKEY_BROWSER_BACK,
ui::DomCode::BROWSER_BACK, ui::EF_NONE,
ui::DomKey::BROWSER_BACK, 0),
GetKeyEventAsString(*static_cast<ui::KeyEvent*>(events[0])));
}
TEST_F(EventRewriterTest, TestRewrittenModifierClick) {
#if defined(USE_X11)
std::vector<int> device_list;
device_list.push_back(10);
ui::TouchFactory::GetInstance()->SetPointerDeviceForTest(device_list);
// Remap Control to Alt.
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
IntegerPrefMember control;
control.Init(prefs::kLanguageRemapControlKeyTo, &prefs);
control.SetValue(chromeos::input_method::kAltKey);
EventRewriter rewriter(NULL);
rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
rewriter.set_pref_service_for_testing(&prefs);
// Check that Control + Left Button is converted (via Alt + Left Button)
// to Right Button.
ui::ScopedXI2Event xev;
xev.InitGenericButtonEvent(10, ui::ET_MOUSE_PRESSED, gfx::Point(),
ui::EF_LEFT_MOUSE_BUTTON | ui::EF_CONTROL_DOWN);
ui::MouseEvent press(xev);
// Sanity check.
EXPECT_EQ(ui::ET_MOUSE_PRESSED, press.type());
EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON | ui::EF_CONTROL_DOWN, press.flags());
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, press, &new_event);
EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
EXPECT_FALSE(ui::EF_LEFT_MOUSE_BUTTON & result->flags());
EXPECT_FALSE(ui::EF_CONTROL_DOWN & result->flags());
EXPECT_FALSE(ui::EF_ALT_DOWN & result->flags());
EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
#endif
}
TEST_F(EventRewriterTest, DontRewriteIfNotRewritten) {
// TODO(kpschoedel): pending changes for crbug.com/360377
// to |chromeos::EventRewriter::RewriteLocatedEvent()
#if defined(USE_X11)
std::vector<int> device_list;
device_list.push_back(10);
device_list.push_back(11);
ui::TouchFactory::GetInstance()->SetPointerDeviceForTest(device_list);
#endif
TestingPrefServiceSyncable prefs;
EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
const int kLeftAndAltFlag = ui::EF_LEFT_MOUSE_BUTTON | ui::EF_ALT_DOWN;
// Test Alt + Left click.
{
ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), kLeftAndAltFlag,
ui::EF_LEFT_MOUSE_BUTTON);
ui::EventTestApi test_press(&press);
test_press.set_source_device_id(10);
// Sanity check.
EXPECT_EQ(ui::ET_MOUSE_PRESSED, press.type());
EXPECT_EQ(kLeftAndAltFlag, press.flags());
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, press, &new_event);
EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
EXPECT_FALSE(kLeftAndAltFlag & result->flags());
EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
}
{
ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), kLeftAndAltFlag,
ui::EF_LEFT_MOUSE_BUTTON);
ui::EventTestApi test_release(&release);
test_release.set_source_device_id(10);
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, release, &new_event);
EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
EXPECT_FALSE(kLeftAndAltFlag & result->flags());
EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
}
#if defined(USE_X11)
// Test Alt + Left click, using XI2 native events.
{
ui::ScopedXI2Event xev;
xev.InitGenericButtonEvent(10, ui::ET_MOUSE_PRESSED, gfx::Point(),
kLeftAndAltFlag);
ui::MouseEvent press(xev);
// Sanity check.
EXPECT_EQ(ui::ET_MOUSE_PRESSED, press.type());
EXPECT_EQ(kLeftAndAltFlag, press.flags());
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, press, &new_event);
EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
EXPECT_FALSE(kLeftAndAltFlag & result->flags());
EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
}
{
ui::ScopedXI2Event xev;
xev.InitGenericButtonEvent(10, ui::ET_MOUSE_RELEASED, gfx::Point(),
kLeftAndAltFlag);
ui::MouseEvent release(xev);
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, release, &new_event);
EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
EXPECT_FALSE(kLeftAndAltFlag & result->flags());
EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
}
#endif
// No ALT in frst click.
{
ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
ui::EventTestApi test_press(&press);
test_press.set_source_device_id(10);
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, press, &new_event);
EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & result->flags());
EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, result->changed_button_flags());
}
{
ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), kLeftAndAltFlag,
ui::EF_LEFT_MOUSE_BUTTON);
ui::EventTestApi test_release(&release);
test_release.set_source_device_id(10);
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, release, &new_event);
EXPECT_TRUE((ui::EF_LEFT_MOUSE_BUTTON | ui::EF_ALT_DOWN) & result->flags());
EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, result->changed_button_flags());
}
#if defined(USE_X11)
// No ALT in frst click, using XI2 native events.
{
ui::ScopedXI2Event xev;
xev.InitGenericButtonEvent(10, ui::ET_MOUSE_PRESSED, gfx::Point(),
ui::EF_LEFT_MOUSE_BUTTON);
ui::MouseEvent press(xev);
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, press, &new_event);
EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & result->flags());
EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, result->changed_button_flags());
}
{
ui::ScopedXI2Event xev;
xev.InitGenericButtonEvent(10, ui::ET_MOUSE_RELEASED, gfx::Point(),
kLeftAndAltFlag);
ui::MouseEvent release(xev);
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, release, &new_event);
EXPECT_TRUE((ui::EF_LEFT_MOUSE_BUTTON | ui::EF_ALT_DOWN) & result->flags());
EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, result->changed_button_flags());
}
#endif
// ALT on different device.
{
ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), kLeftAndAltFlag,
ui::EF_LEFT_MOUSE_BUTTON);
ui::EventTestApi test_press(&press);
test_press.set_source_device_id(11);
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, press, &new_event);
EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
EXPECT_FALSE(kLeftAndAltFlag & result->flags());
EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
}
{
ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), kLeftAndAltFlag,
ui::EF_LEFT_MOUSE_BUTTON);
ui::EventTestApi test_release(&release);
test_release.set_source_device_id(10);
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, release, &new_event);
EXPECT_TRUE((ui::EF_LEFT_MOUSE_BUTTON | ui::EF_ALT_DOWN) & result->flags());
EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, result->changed_button_flags());
}
{
ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), kLeftAndAltFlag,
ui::EF_LEFT_MOUSE_BUTTON);
ui::EventTestApi test_release(&release);
test_release.set_source_device_id(11);
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, release, &new_event);
EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
EXPECT_FALSE(kLeftAndAltFlag & result->flags());
EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
}
#if defined(USE_X11)
// ALT on different device, using XI2 native events.
{
ui::ScopedXI2Event xev;
xev.InitGenericButtonEvent(11, ui::ET_MOUSE_PRESSED, gfx::Point(),
kLeftAndAltFlag);
ui::MouseEvent press(xev);
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, press, &new_event);
EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
EXPECT_FALSE(kLeftAndAltFlag & result->flags());
EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
}
{
ui::ScopedXI2Event xev;
xev.InitGenericButtonEvent(10, ui::ET_MOUSE_RELEASED, gfx::Point(),
kLeftAndAltFlag);
ui::MouseEvent release(xev);
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, release, &new_event);
EXPECT_TRUE((ui::EF_LEFT_MOUSE_BUTTON | ui::EF_ALT_DOWN) & result->flags());
EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, result->changed_button_flags());
}
{
ui::ScopedXI2Event xev;
xev.InitGenericButtonEvent(11, ui::ET_MOUSE_RELEASED, gfx::Point(),
kLeftAndAltFlag);
ui::MouseEvent release(xev);
scoped_ptr<ui::Event> new_event;
const ui::MouseEvent* result =
RewriteMouseButtonEvent(&rewriter, release, &new_event);
EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
EXPECT_FALSE(kLeftAndAltFlag & result->flags());
EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
}
#endif
}
TEST_F(EventRewriterAshTest, StickyKeyEventDispatchImpl) {
// Test the actual key event dispatch implementation.
ScopedVector<ui::Event> events;
SendActivateStickyKeyPattern(ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT,
ui::DomKey::CONTROL, 0);
PopEvents(&events);
EXPECT_EQ(1u, events.size());
EXPECT_EQ(ui::ET_KEY_PRESSED, events[0]->type());
EXPECT_EQ(ui::VKEY_CONTROL,
static_cast<ui::KeyEvent*>(events[0])->key_code());
// Test key press event is correctly modified and modifier release
// event is sent.
ui::KeyEvent press(ui::ET_KEY_PRESSED, ui::VKEY_C, ui::DomCode::KEY_C,
ui::EF_NONE, ui::DomKey::CHARACTER, 'c',
ui::EventTimeForNow());
ui::EventDispatchDetails details = Send(&press);
PopEvents(&events);
EXPECT_EQ(2u, events.size());
EXPECT_EQ(ui::ET_KEY_PRESSED, events[0]->type());
EXPECT_EQ(ui::VKEY_C, static_cast<ui::KeyEvent*>(events[0])->key_code());
EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
EXPECT_EQ(ui::VKEY_CONTROL,
static_cast<ui::KeyEvent*>(events[1])->key_code());
// Test key release event is not modified.
ui::KeyEvent release(ui::ET_KEY_RELEASED, ui::VKEY_C, ui::DomCode::KEY_C,
ui::EF_NONE, ui::DomKey::CHARACTER, 'c',
ui::EventTimeForNow());
details = Send(&release);
ASSERT_FALSE(details.dispatcher_destroyed);
PopEvents(&events);
EXPECT_EQ(1u, events.size());
EXPECT_EQ(ui::ET_KEY_RELEASED, events[0]->type());
EXPECT_EQ(ui::VKEY_C, static_cast<ui::KeyEvent*>(events[0])->key_code());
EXPECT_FALSE(events[0]->flags() & ui::EF_CONTROL_DOWN);
}
TEST_F(EventRewriterAshTest, MouseEventDispatchImpl) {
ScopedVector<ui::Event> events;
SendActivateStickyKeyPattern(ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT,
ui::DomKey::CONTROL, 0);
PopEvents(&events);
// Test mouse press event is correctly modified.
gfx::Point location(0, 0);
ui::MouseEvent press(ui::ET_MOUSE_PRESSED, location, location,
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
ui::EventDispatchDetails details = Send(&press);
ASSERT_FALSE(details.dispatcher_destroyed);
PopEvents(&events);
EXPECT_EQ(1u, events.size());
EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0]->type());
EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
// Test mouse release event is correctly modified and modifier release
// event is sent. The mouse event should have the correct DIP location.
ui::MouseEvent release(ui::ET_MOUSE_RELEASED, location, location,
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
details = Send(&release);
ASSERT_FALSE(details.dispatcher_destroyed);
PopEvents(&events);
EXPECT_EQ(2u, events.size());
EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[0]->type());
EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
EXPECT_EQ(ui::VKEY_CONTROL,
static_cast<ui::KeyEvent*>(events[1])->key_code());
}
TEST_F(EventRewriterAshTest, MouseWheelEventDispatchImpl) {
ScopedVector<ui::Event> events;
// Test positive mouse wheel event is correctly modified and modifier release
// event is sent.
SendActivateStickyKeyPattern(ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT,
ui::DomKey::CONTROL, 0);
PopEvents(&events);
gfx::Point location(0, 0);
ui::MouseEvent mev(ui::ET_MOUSEWHEEL, location, location,
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
ui::MouseWheelEvent positive(mev, 0, ui::MouseWheelEvent::kWheelDelta);
ui::EventDispatchDetails details = Send(&positive);
ASSERT_FALSE(details.dispatcher_destroyed);
PopEvents(&events);
EXPECT_EQ(2u, events.size());
EXPECT_TRUE(events[0]->IsMouseWheelEvent());
EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
EXPECT_EQ(ui::VKEY_CONTROL,
static_cast<ui::KeyEvent*>(events[1])->key_code());
// Test negative mouse wheel event is correctly modified and modifier release
// event is sent.
SendActivateStickyKeyPattern(ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT,
ui::DomKey::CONTROL, 0);
PopEvents(&events);
ui::MouseWheelEvent negative(mev, 0, -ui::MouseWheelEvent::kWheelDelta);
details = Send(&negative);
ASSERT_FALSE(details.dispatcher_destroyed);
PopEvents(&events);
EXPECT_EQ(2u, events.size());
EXPECT_TRUE(events[0]->IsMouseWheelEvent());
EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
EXPECT_EQ(ui::VKEY_CONTROL,
static_cast<ui::KeyEvent*>(events[1])->key_code());
}
class StickyKeysOverlayTest : public EventRewriterAshTest {
public:
StickyKeysOverlayTest() : overlay_(NULL) {}
~StickyKeysOverlayTest() override {}
void SetUp() override {
EventRewriterAshTest::SetUp();
overlay_ = sticky_keys_controller_->GetOverlayForTest();
ASSERT_TRUE(overlay_);
}
ash::StickyKeysOverlay* overlay_;
};
TEST_F(StickyKeysOverlayTest, OneModifierEnabled) {
EXPECT_FALSE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
// Pressing modifier key should show overlay.
SendActivateStickyKeyPattern(ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT,
ui::DomKey::CONTROL, 0);
EXPECT_TRUE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED,
overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
// Pressing a normal key should hide overlay.
SendActivateStickyKeyPattern(ui::VKEY_T, ui::DomCode::KEY_T,
ui::DomKey::CHARACTER, 't');
EXPECT_FALSE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
}
TEST_F(StickyKeysOverlayTest, TwoModifiersEnabled) {
EXPECT_FALSE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
// Pressing two modifiers should show overlay.
SendActivateStickyKeyPattern(ui::VKEY_SHIFT, ui::DomCode::SHIFT_LEFT,
ui::DomKey::SHIFT, 0);
SendActivateStickyKeyPattern(ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT,
ui::DomKey::CONTROL, 0);
EXPECT_TRUE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED,
overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED,
overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
// Pressing a normal key should hide overlay.
SendActivateStickyKeyPattern(ui::VKEY_N, ui::DomCode::KEY_N,
ui::DomKey::CHARACTER, 'n');
EXPECT_FALSE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
}
TEST_F(StickyKeysOverlayTest, LockedModifier) {
EXPECT_FALSE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
// Pressing a modifier key twice should lock modifier and show overlay.
SendActivateStickyKeyPattern(ui::VKEY_LMENU, ui::DomCode::ALT_LEFT,
ui::DomKey::ALT, 0);
SendActivateStickyKeyPattern(ui::VKEY_LMENU, ui::DomCode::ALT_LEFT,
ui::DomKey::ALT, 0);
EXPECT_TRUE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED,
overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
// Pressing a normal key should not hide overlay.
SendActivateStickyKeyPattern(ui::VKEY_D, ui::DomCode::KEY_D,
ui::DomKey::CHARACTER, 'd');
EXPECT_TRUE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED,
overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
}
TEST_F(StickyKeysOverlayTest, LockedAndNormalModifier) {
EXPECT_FALSE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
// Pressing a modifier key twice should lock modifier and show overlay.
SendActivateStickyKeyPattern(ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT,
ui::DomKey::CONTROL, 0);
SendActivateStickyKeyPattern(ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT,
ui::DomKey::CONTROL, 0);
EXPECT_TRUE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED,
overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
// Pressing another modifier key should still show overlay.
SendActivateStickyKeyPattern(ui::VKEY_SHIFT, ui::DomCode::SHIFT_LEFT,
ui::DomKey::SHIFT, 0);
EXPECT_TRUE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED,
overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED,
overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
// Pressing a normal key should not hide overlay but disable normal modifier.
SendActivateStickyKeyPattern(ui::VKEY_D, ui::DomCode::KEY_D,
ui::DomKey::CHARACTER, 'd');
EXPECT_TRUE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED,
overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
}
TEST_F(StickyKeysOverlayTest, ModifiersDisabled) {
EXPECT_FALSE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_COMMAND_DOWN));
// Enable modifiers.
SendActivateStickyKeyPattern(ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT,
ui::DomKey::CONTROL, 0);
SendActivateStickyKeyPattern(ui::VKEY_SHIFT, ui::DomCode::SHIFT_LEFT,
ui::DomKey::SHIFT, 0);
SendActivateStickyKeyPattern(ui::VKEY_SHIFT, ui::DomCode::SHIFT_LEFT,
ui::DomKey::SHIFT, 0);
SendActivateStickyKeyPattern(ui::VKEY_LMENU, ui::DomCode::ALT_LEFT,
ui::DomKey::ALT, 0);
SendActivateStickyKeyPattern(ui::VKEY_COMMAND, ui::DomCode::OS_LEFT,
ui::DomKey::OS, 0);
SendActivateStickyKeyPattern(ui::VKEY_COMMAND, ui::DomCode::OS_LEFT,
ui::DomKey::OS, 0);
EXPECT_TRUE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED,
overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED,
overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED,
overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED,
overlay_->GetModifierKeyState(ui::EF_COMMAND_DOWN));
// Disable modifiers and overlay should be hidden.
SendActivateStickyKeyPattern(ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT,
ui::DomKey::CONTROL, 0);
SendActivateStickyKeyPattern(ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT,
ui::DomKey::CONTROL, 0);
SendActivateStickyKeyPattern(ui::VKEY_SHIFT, ui::DomCode::SHIFT_LEFT,
ui::DomKey::SHIFT, 0);
SendActivateStickyKeyPattern(ui::VKEY_LMENU, ui::DomCode::ALT_LEFT,
ui::DomKey::ALT, 0);
SendActivateStickyKeyPattern(ui::VKEY_LMENU, ui::DomCode::ALT_LEFT,
ui::DomKey::ALT, 0);
SendActivateStickyKeyPattern(ui::VKEY_COMMAND, ui::DomCode::OS_LEFT,
ui::DomKey::OS, 0);
EXPECT_FALSE(overlay_->is_visible());
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
overlay_->GetModifierKeyState(ui::EF_COMMAND_DOWN));
}
TEST_F(StickyKeysOverlayTest, ModifierVisibility) {
// All but AltGr and Mod3 should initially be visible.
EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_CONTROL_DOWN));
EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_SHIFT_DOWN));
EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_ALT_DOWN));
EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_COMMAND_DOWN));
EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_ALTGR_DOWN));
EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_MOD3_DOWN));
// Turn all modifiers on.
sticky_keys_controller_->SetModifiersEnabled(true, true);
EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_CONTROL_DOWN));
EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_SHIFT_DOWN));
EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_ALT_DOWN));
EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_COMMAND_DOWN));
EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_ALTGR_DOWN));
EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_MOD3_DOWN));
// Turn off Mod3.
sticky_keys_controller_->SetModifiersEnabled(false, true);
EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_ALTGR_DOWN));
EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_MOD3_DOWN));
// Turn off AltGr.
sticky_keys_controller_->SetModifiersEnabled(true, false);
EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_ALTGR_DOWN));
EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_MOD3_DOWN));
// Turn off AltGr and Mod3.
sticky_keys_controller_->SetModifiersEnabled(false, false);
EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_ALTGR_DOWN));
EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_MOD3_DOWN));
}
} // namespace chromeos