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