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_mac.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 kUsbCapsLock   = 0x070039;
23const unsigned int kUsbLeftShift  = 0x0700e1;
24const unsigned int kUsbLeftOption = 0x0700e2;
25const unsigned int kUsbLeftCmd    = 0x0700e3;
26const unsigned int kUsbRightCmd   = 0x0700e7;
27
28// A hardcoded value used to verify |lock_states| is preserved.
29static const uint32 kTestLockStates = protocol::KeyEvent::LOCK_STATES_NUMLOCK;
30
31MATCHER_P2(EqualsUsbEvent, usb_keycode, pressed, "") {
32  return arg.usb_keycode() == static_cast<uint32>(usb_keycode) &&
33         arg.pressed() == pressed &&
34         arg.lock_states() == kTestLockStates;
35}
36
37KeyEvent MakeKeyEvent(uint32 keycode, bool pressed) {
38  KeyEvent event;
39  event.set_usb_keycode(keycode);
40  event.set_pressed(pressed);
41  event.set_lock_states(kTestLockStates);
42  return event;
43}
44
45}  // namespace
46
47// Test CapsLock press/release.
48TEST(NormalizingInputFilterMacTest, CapsLock) {
49  MockInputStub stub;
50  scoped_ptr<protocol::InputFilter> processor(
51      new NormalizingInputFilterMac(&stub));
52
53  {
54    InSequence s;
55
56    // Verifies the generated CapsLock up/down events.
57    EXPECT_CALL(stub, InjectKeyEvent(EqualsUsbEvent(kUsbCapsLock, true)));
58    EXPECT_CALL(stub, InjectKeyEvent(EqualsUsbEvent(kUsbCapsLock, false)));
59  }
60
61  // Injecting a CapsLock down event with NumLock on.
62  processor->InjectKeyEvent(MakeKeyEvent(kUsbCapsLock, true));
63}
64
65// Test without pressing command key.
66TEST(NormalizingInputFilterMacTest, NoInjection) {
67  MockInputStub stub;
68  scoped_ptr<protocol::InputFilter> processor(
69      new NormalizingInputFilterMac(&stub));
70
71  {
72    InSequence s;
73
74    EXPECT_CALL(stub, InjectKeyEvent(
75        EqualsUsbEvent('C', true)));
76    EXPECT_CALL(stub, InjectKeyEvent(
77        EqualsUsbEvent('C', false)));
78  }
79
80  // C Down and C Up.
81  processor->InjectKeyEvent(MakeKeyEvent('C', true));
82  processor->InjectKeyEvent(MakeKeyEvent('C', false));
83}
84
85// Test pressing command key and other normal keys.
86TEST(NormalizingInputFilterMacTest, CmdKey) {
87  MockInputStub stub;
88  scoped_ptr<protocol::InputFilter> processor(
89      new NormalizingInputFilterMac(&stub));
90
91  {
92    InSequence s;
93
94    // Left command key.
95    EXPECT_CALL(stub, InjectKeyEvent(
96        EqualsUsbEvent(kUsbLeftCmd, true)));
97    EXPECT_CALL(stub, InjectKeyEvent(
98        EqualsUsbEvent('C', true)));
99    EXPECT_CALL(stub, InjectKeyEvent(
100        EqualsUsbEvent('C', false)));
101    EXPECT_CALL(stub, InjectKeyEvent(
102        EqualsUsbEvent(kUsbLeftCmd, false)));
103
104    // Right command key.
105    EXPECT_CALL(stub, InjectKeyEvent(
106        EqualsUsbEvent(kUsbRightCmd, true)));
107    EXPECT_CALL(stub, InjectKeyEvent(
108        EqualsUsbEvent('C', true)));
109    EXPECT_CALL(stub, InjectKeyEvent(
110        EqualsUsbEvent('C', false)));
111    EXPECT_CALL(stub, InjectKeyEvent(
112        EqualsUsbEvent(kUsbRightCmd, false)));
113
114    // More than one keys after CMD.
115    EXPECT_CALL(stub, InjectKeyEvent(
116        EqualsUsbEvent(kUsbRightCmd, true)));
117    EXPECT_CALL(stub, InjectKeyEvent(
118        EqualsUsbEvent('C', true)));
119    EXPECT_CALL(stub, InjectKeyEvent(
120        EqualsUsbEvent('V', true)));
121    EXPECT_CALL(stub, InjectKeyEvent(
122        EqualsUsbEvent('C', false)));
123    EXPECT_CALL(stub, InjectKeyEvent(
124        EqualsUsbEvent('V', false)));
125    EXPECT_CALL(stub, InjectKeyEvent(
126        EqualsUsbEvent(kUsbRightCmd, false)));
127  }
128
129  // Left command key.
130  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, true));
131  processor->InjectKeyEvent(MakeKeyEvent('C', true));
132  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, false));
133
134  // Right command key.
135  processor->InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, true));
136  processor->InjectKeyEvent(MakeKeyEvent('C', true));
137  processor->InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, false));
138
139  // More than one keys after CMD.
140  processor->InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, true));
141  processor->InjectKeyEvent(MakeKeyEvent('C', true));
142  processor->InjectKeyEvent(MakeKeyEvent('V', true));
143  processor->InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, false));
144}
145
146// Test pressing command and special keys.
147TEST(NormalizingInputFilterMacTest, SpecialKeys) {
148  MockInputStub stub;
149  scoped_ptr<protocol::InputFilter> processor(
150      new NormalizingInputFilterMac(&stub));
151
152  {
153    InSequence s;
154
155    // Command + Shift.
156    EXPECT_CALL(stub, InjectKeyEvent(
157        EqualsUsbEvent(kUsbLeftCmd, true)));
158    EXPECT_CALL(stub, InjectKeyEvent(
159        EqualsUsbEvent(kUsbLeftShift, true)));
160    EXPECT_CALL(stub, InjectKeyEvent(
161        EqualsUsbEvent(kUsbLeftCmd, false)));
162    EXPECT_CALL(stub, InjectKeyEvent(
163        EqualsUsbEvent(kUsbLeftShift, false)));
164
165    // Command + Option.
166    EXPECT_CALL(stub, InjectKeyEvent(
167        EqualsUsbEvent(kUsbLeftCmd, true)));
168    EXPECT_CALL(stub, InjectKeyEvent(
169        EqualsUsbEvent(kUsbLeftOption, true)));
170    EXPECT_CALL(stub, InjectKeyEvent(
171        EqualsUsbEvent(kUsbLeftCmd, false)));
172    EXPECT_CALL(stub, InjectKeyEvent(
173        EqualsUsbEvent(kUsbLeftOption, false)));
174  }
175
176  // Command + Shift.
177  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, true));
178  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftShift, true));
179  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, false));
180  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftShift, false));
181
182  // Command + Option.
183  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, true));
184  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOption, true));
185  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, false));
186  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOption, false));
187}
188
189// Test pressing multiple command keys.
190TEST(NormalizingInputFilterMacTest, MultipleCmdKeys) {
191  MockInputStub stub;
192  scoped_ptr<protocol::InputFilter> processor(
193      new NormalizingInputFilterMac(&stub));
194
195  {
196    InSequence s;
197
198    EXPECT_CALL(stub, InjectKeyEvent(
199        EqualsUsbEvent(kUsbLeftCmd, true)));
200    EXPECT_CALL(stub, InjectKeyEvent(
201        EqualsUsbEvent('C', true)));
202    EXPECT_CALL(stub, InjectKeyEvent(
203        EqualsUsbEvent(kUsbRightCmd, true)));
204    EXPECT_CALL(stub, InjectKeyEvent(
205        EqualsUsbEvent('C', false)));
206    EXPECT_CALL(stub, InjectKeyEvent(
207        EqualsUsbEvent(kUsbLeftCmd, false)));
208  }
209
210  // Test multiple CMD keys at the same time.
211  // L CMD Down, C Down, R CMD Down, L CMD Up.
212  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, true));
213  processor->InjectKeyEvent(MakeKeyEvent('C', true));
214  processor->InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, true));
215  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, false));
216}
217
218// Test press C key before command key.
219TEST(NormalizingInputFilterMacTest, BeforeCmdKey) {
220  MockInputStub stub;
221  scoped_ptr<protocol::InputFilter> processor(
222      new NormalizingInputFilterMac(&stub));
223
224  {
225    InSequence s;
226
227    EXPECT_CALL(stub, InjectKeyEvent(
228        EqualsUsbEvent('C', true)));
229    EXPECT_CALL(stub, InjectKeyEvent(
230        EqualsUsbEvent(kUsbRightCmd, true)));
231    EXPECT_CALL(stub, InjectKeyEvent(
232        EqualsUsbEvent('C', false)));
233    EXPECT_CALL(stub, InjectKeyEvent(
234        EqualsUsbEvent(kUsbRightCmd, false)));
235    EXPECT_CALL(stub, InjectKeyEvent(
236        EqualsUsbEvent('C', false)));
237  }
238
239  // Press C before command key.
240  processor->InjectKeyEvent(MakeKeyEvent('C', true));
241  processor->InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, true));
242  processor->InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, false));
243  processor->InjectKeyEvent(MakeKeyEvent('C', false));
244}
245
246}  // namespace remoting
247