1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "remoting/client/plugin/normalizing_input_filter_cros.h" 6 7#include "remoting/proto/event.pb.h" 8#include "remoting/protocol/protocol_mock_objects.h" 9#include "testing/gmock/include/gmock/gmock.h" 10#include "testing/gtest/include/gtest/gtest.h" 11 12using ::testing::InSequence; 13using remoting::protocol::InputStub; 14using remoting::protocol::KeyEvent; 15using remoting::protocol::MockInputStub; 16using remoting::protocol::MouseEvent; 17 18namespace remoting { 19 20namespace { 21 22const unsigned int kUsbLeftOsKey = 0x0700e3; 23const unsigned int kUsbRightOsKey = 0x0700e7; 24const unsigned int kUsbLeftAltKey = 0x0700e2; 25const unsigned int kUsbRightAltKey = 0x0700e6; 26 27const unsigned int kUsbFunctionKey = 0x07003a; // F1 28const unsigned int kUsbExtendedKey = 0x070049; // Insert 29const unsigned int kUsbOtherKey = 0x07002b; // Tab 30 31// A hardcoded value used to verify |lock_states| is preserved. 32static const uint32 kTestLockStates = protocol::KeyEvent::LOCK_STATES_NUMLOCK; 33 34MATCHER_P2(EqualsKeyEvent, usb_keycode, pressed, "") { 35 return arg.usb_keycode() == static_cast<uint32>(usb_keycode) && 36 arg.pressed() == pressed && 37 arg.lock_states() == kTestLockStates; 38} 39 40KeyEvent MakeKeyEvent(uint32 keycode, bool pressed) { 41 KeyEvent event; 42 event.set_usb_keycode(keycode); 43 event.set_pressed(pressed); 44 event.set_lock_states(kTestLockStates); 45 return event; 46} 47 48void PressAndReleaseKey(InputStub* input_stub, uint32 keycode) { 49 input_stub->InjectKeyEvent(MakeKeyEvent(keycode, true)); 50 input_stub->InjectKeyEvent(MakeKeyEvent(keycode, false)); 51} 52 53MATCHER_P2(EqualsMouseMoveEvent, x, y, "") { 54 return arg.x() == x && arg.y() == y; 55} 56 57MATCHER_P2(EqualsMouseButtonEvent, button, button_down, "") { 58 return arg.button() == button && arg.button_down() == button_down; 59} 60 61static MouseEvent MakeMouseMoveEvent(int x, int y) { 62 MouseEvent event; 63 event.set_x(x); 64 event.set_y(y); 65 return event; 66} 67 68static MouseEvent MakeMouseButtonEvent(MouseEvent::MouseButton button, 69 bool button_down) { 70 MouseEvent event; 71 event.set_button(button); 72 event.set_button_down(button_down); 73 return event; 74} 75 76} // namespace 77 78// Test OSKey press/release. 79TEST(NormalizingInputFilterCrosTest, PressReleaseOsKey) { 80 MockInputStub stub; 81 scoped_ptr<protocol::InputFilter> processor( 82 new NormalizingInputFilterCros(&stub)); 83 84 { 85 InSequence s; 86 87 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, true))); 88 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, false))); 89 90 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbRightOsKey, true))); 91 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbRightOsKey, false))); 92 } 93 94 // Inject press & release events for left & right OSKeys. 95 PressAndReleaseKey(processor.get(), kUsbLeftOsKey); 96 PressAndReleaseKey(processor.get(), kUsbRightOsKey); 97} 98 99// Test OSKey key repeat switches it to "modifying" mode. 100TEST(NormalizingInputFilterCrosTest, OSKeyRepeats) { 101 MockInputStub stub; 102 scoped_ptr<protocol::InputFilter> processor( 103 new NormalizingInputFilterCros(&stub)); 104 105 { 106 InSequence s; 107 108 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, true))); 109 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, true))); 110 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, true))); 111 } 112 113 // Inject a press and repeats for the left OSKey, but don't release it, and 114 // verify that the repeats result in press events. 115 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true)); 116 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true)); 117 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true)); 118} 119 120// Test OSKey press followed by function key press and release results in 121// just the function key events. 122TEST(NormalizingInputFilterCrosTest, FunctionKey) { 123 MockInputStub stub; 124 scoped_ptr<protocol::InputFilter> processor( 125 new NormalizingInputFilterCros(&stub)); 126 127 { 128 InSequence s; 129 130 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbFunctionKey, true))); 131 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbFunctionKey, false))); 132 } 133 134 // Hold the left OSKey while pressing & releasing the function key. 135 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true)); 136 PressAndReleaseKey(processor.get(), kUsbFunctionKey); 137 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, false)); 138} 139 140// Test OSKey press followed by extended key press and release results in 141// just the function key events. 142TEST(NormalizingInputFilterCrosTest, ExtendedKey) { 143 MockInputStub stub; 144 scoped_ptr<protocol::InputFilter> processor( 145 new NormalizingInputFilterCros(&stub)); 146 147 { 148 InSequence s; 149 150 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbExtendedKey, true))); 151 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbExtendedKey, false))); 152 } 153 154 // Hold the left OSKey while pressing & releasing the function key. 155 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true)); 156 PressAndReleaseKey(processor.get(), kUsbExtendedKey); 157 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, false)); 158} 159 160// Test OSKey press followed by non-function, non-extended key press and release 161// results in normal-looking sequence. 162TEST(NormalizingInputFilterCrosTest, OtherKey) { 163 MockInputStub stub; 164 scoped_ptr<protocol::InputFilter> processor( 165 new NormalizingInputFilterCros(&stub)); 166 167 { 168 InSequence s; 169 170 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, true))); 171 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbOtherKey, true))); 172 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbOtherKey, false))); 173 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, false))); 174 } 175 176 // Hold the left OSKey while pressing & releasing the function key. 177 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true)); 178 PressAndReleaseKey(processor.get(), kUsbOtherKey); 179 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, false)); 180} 181 182// Test OSKey press followed by extended key press, then normal key press 183// results in OSKey switching to modifying mode for the normal key. 184TEST(NormalizingInputFilterCrosTest, ExtendedThenOtherKey) { 185 MockInputStub stub; 186 scoped_ptr<protocol::InputFilter> processor( 187 new NormalizingInputFilterCros(&stub)); 188 189 { 190 InSequence s; 191 192 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbExtendedKey, true))); 193 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbExtendedKey, false))); 194 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, true))); 195 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbOtherKey, true))); 196 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbOtherKey, false))); 197 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, false))); 198 } 199 200 // Hold the left OSKey while pressing & releasing the function key. 201 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true)); 202 PressAndReleaseKey(processor.get(), kUsbExtendedKey); 203 PressAndReleaseKey(processor.get(), kUsbOtherKey); 204 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, false)); 205} 206 207// Test OSKey press followed by mouse event puts the OSKey into modifying mode. 208TEST(NormalizingInputFilterCrosTest, MouseEvent) { 209 MockInputStub stub; 210 scoped_ptr<protocol::InputFilter> processor( 211 new NormalizingInputFilterCros(&stub)); 212 213 { 214 InSequence s; 215 216 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, true))); 217 EXPECT_CALL(stub, InjectMouseEvent(EqualsMouseMoveEvent(0, 0))); 218 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, false))); 219 } 220 221 // Hold the left OSKey while pressing & releasing the function key. 222 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true)); 223 processor->InjectMouseEvent(MakeMouseMoveEvent(0, 0)); 224 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, false)); 225} 226 227// Test left alt + right click is remapped to left alt + left click. 228TEST(NormalizingInputFilterCrosTest, LeftAltClick) { 229 MockInputStub stub; 230 scoped_ptr<protocol::InputFilter> processor( 231 new NormalizingInputFilterCros(&stub)); 232 233 { 234 InSequence s; 235 236 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftAltKey, true))); 237 EXPECT_CALL(stub, InjectMouseEvent( 238 EqualsMouseButtonEvent(MouseEvent::BUTTON_LEFT, true))); 239 EXPECT_CALL(stub, InjectMouseEvent( 240 EqualsMouseButtonEvent(MouseEvent::BUTTON_LEFT, false))); 241 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftAltKey, false))); 242 } 243 244 // Hold the left alt key while left-clicking. ChromeOS will rewrite this as 245 // Alt+RightClick 246 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftAltKey, true)); 247 processor->InjectMouseEvent( 248 MakeMouseButtonEvent(MouseEvent::BUTTON_RIGHT, true)); 249 processor->InjectMouseEvent( 250 MakeMouseButtonEvent(MouseEvent::BUTTON_RIGHT, false)); 251 processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftAltKey, false)); 252} 253 254// Test that right alt + right click is unchanged. 255TEST(NormalizingInputFilterCrosTest, RightAltClick) { 256 MockInputStub stub; 257 scoped_ptr<protocol::InputFilter> processor( 258 new NormalizingInputFilterCros(&stub)); 259 260 { 261 InSequence s; 262 263 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbRightAltKey, true))); 264 EXPECT_CALL(stub, InjectMouseEvent( 265 EqualsMouseButtonEvent(MouseEvent::BUTTON_RIGHT, true))); 266 EXPECT_CALL(stub, InjectMouseEvent( 267 EqualsMouseButtonEvent(MouseEvent::BUTTON_RIGHT, false))); 268 EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbRightAltKey, false))); 269 } 270 271 // Hold the right alt key while left-clicking. ChromeOS will rewrite this as 272 // Alt+RightClick 273 processor->InjectKeyEvent(MakeKeyEvent(kUsbRightAltKey, true)); 274 processor->InjectMouseEvent( 275 MakeMouseButtonEvent(MouseEvent::BUTTON_RIGHT, true)); 276 processor->InjectMouseEvent( 277 MakeMouseButtonEvent(MouseEvent::BUTTON_RIGHT, false)); 278 processor->InjectKeyEvent(MakeKeyEvent(kUsbRightAltKey, false)); 279} 280 281} // namespace remoting 282