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/protocol/input_event_tracker.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::_;
13using ::testing::ExpectationSet;
14using ::testing::InSequence;
15
16namespace remoting {
17namespace protocol {
18
19namespace {
20
21static const MouseEvent::MouseButton BUTTON_LEFT = MouseEvent::BUTTON_LEFT;
22static const MouseEvent::MouseButton BUTTON_RIGHT = MouseEvent::BUTTON_RIGHT;
23
24// A hardcoded value used to verify |lock_states| is preserved.
25static const uint32 kTestLockStates = protocol::KeyEvent::LOCK_STATES_CAPSLOCK;
26
27// Verify the usb key code and the "pressed" state.
28// Also verify that the event doesn't have |lock_states| set.
29MATCHER_P2(EqualsUsbEventWithoutLockStates, usb_keycode, pressed, "") {
30  return arg.usb_keycode() == static_cast<uint32>(usb_keycode) &&
31         arg.pressed() == pressed &&
32         !arg.has_lock_states();
33}
34
35// Verify the usb key code, the "pressed" state, and the lock states.
36MATCHER_P2(EqualsUsbEvent, usb_keycode, pressed, "") {
37  return arg.usb_keycode() == static_cast<uint32>(usb_keycode) &&
38          arg.pressed() == pressed &&
39          arg.lock_states() == kTestLockStates;
40}
41
42MATCHER_P4(EqualsMouseEvent, x, y, button, down, "") {
43  return arg.x() == x && arg.y() == y && arg.button() == button &&
44         arg.button_down() == down;
45}
46
47static KeyEvent NewUsbEvent(uint32 usb_keycode,
48                            bool pressed) {
49  KeyEvent event;
50  event.set_usb_keycode(usb_keycode);
51  event.set_pressed(pressed);
52  // Create all key events with the hardcoded |lock_state| in this test.
53  event.set_lock_states(kTestLockStates);
54  return event;
55}
56
57static void PressAndReleaseUsb(InputStub* input_stub,
58                               uint32 usb_keycode) {
59  input_stub->InjectKeyEvent(NewUsbEvent(usb_keycode, true));
60  input_stub->InjectKeyEvent(NewUsbEvent(usb_keycode, false));
61}
62
63static MouseEvent NewMouseEvent(int x, int y,
64    MouseEvent::MouseButton button, bool down) {
65  MouseEvent event;
66  event.set_x(x);
67  event.set_y(y);
68  event.set_button(button);
69  event.set_button_down(down);
70  return event;
71}
72
73}
74
75// Verify that keys that were pressed and released aren't re-released.
76TEST(InputEventTrackerTest, NothingToRelease) {
77  MockInputStub mock_stub;
78  InputEventTracker input_tracker(&mock_stub);
79
80  {
81    InSequence s;
82
83    EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(1, true)));
84    EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(1, false)));
85    EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(2, true)));
86    EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(2, false)));
87
88    EXPECT_CALL(mock_stub,
89        InjectMouseEvent(EqualsMouseEvent(0, 0, BUTTON_LEFT, true)));
90    EXPECT_CALL(mock_stub,
91        InjectMouseEvent(EqualsMouseEvent(0, 0, BUTTON_LEFT, false)));
92  }
93
94  PressAndReleaseUsb(&input_tracker, 1);
95  PressAndReleaseUsb(&input_tracker, 2);
96
97  input_tracker.InjectMouseEvent(NewMouseEvent(0, 0, BUTTON_LEFT, true));
98  input_tracker.InjectMouseEvent(NewMouseEvent(0, 0, BUTTON_LEFT, false));
99
100  input_tracker.ReleaseAll();
101}
102
103// Verify that keys that were left pressed get released.
104TEST(InputEventTrackerTest, ReleaseAllKeys) {
105  MockInputStub mock_stub;
106  InputEventTracker input_tracker(&mock_stub);
107  ExpectationSet injects;
108
109  {
110    InSequence s;
111
112    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(3, true)));
113    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(1, true)));
114    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(1, false)));
115    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(2, true)));
116    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(2, false)));
117
118    injects += EXPECT_CALL(mock_stub,
119        InjectMouseEvent(EqualsMouseEvent(0, 0, BUTTON_RIGHT, true)));
120    injects += EXPECT_CALL(mock_stub,
121        InjectMouseEvent(EqualsMouseEvent(0, 0, BUTTON_LEFT, true)));
122    injects += EXPECT_CALL(mock_stub,
123        InjectMouseEvent(EqualsMouseEvent(1, 1, BUTTON_LEFT, false)));
124  }
125
126  // The key should be released but |lock_states| should not be set.
127  EXPECT_CALL(mock_stub,
128              InjectKeyEvent(EqualsUsbEventWithoutLockStates(3, false)))
129      .After(injects);
130  EXPECT_CALL(mock_stub,
131              InjectMouseEvent(EqualsMouseEvent(1, 1, BUTTON_RIGHT, false)))
132      .After(injects);
133
134  input_tracker.InjectKeyEvent(NewUsbEvent(3, true));
135  PressAndReleaseUsb(&input_tracker, 1);
136  PressAndReleaseUsb(&input_tracker, 2);
137
138  input_tracker.InjectMouseEvent(NewMouseEvent(0, 0, BUTTON_RIGHT, true));
139  input_tracker.InjectMouseEvent(NewMouseEvent(0, 0, BUTTON_LEFT, true));
140  input_tracker.InjectMouseEvent(NewMouseEvent(1, 1, BUTTON_LEFT, false));
141
142  EXPECT_FALSE(input_tracker.IsKeyPressed(1));
143  EXPECT_FALSE(input_tracker.IsKeyPressed(2));
144  EXPECT_TRUE(input_tracker.IsKeyPressed(3));
145  EXPECT_EQ(1, input_tracker.PressedKeyCount());
146
147  input_tracker.ReleaseAll();
148}
149
150// Verify that we track both USB-based key events correctly.
151TEST(InputEventTrackerTest, TrackUsbKeyEvents) {
152  MockInputStub mock_stub;
153  InputEventTracker input_tracker(&mock_stub);
154  ExpectationSet injects;
155
156  {
157    InSequence s;
158
159    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(3, true)));
160    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(6, true)));
161    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(7, true)));
162    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(5, true)));
163    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(5, true)));
164    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(2, true)));
165    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(2, false)));
166  }
167
168  // The key should be auto released with no |lock_states|.
169  EXPECT_CALL(mock_stub,
170              InjectKeyEvent(EqualsUsbEventWithoutLockStates(3, false)))
171      .After(injects);
172  EXPECT_CALL(mock_stub,
173              InjectKeyEvent(EqualsUsbEventWithoutLockStates(6, false)))
174      .After(injects);
175  EXPECT_CALL(mock_stub,
176              InjectKeyEvent(EqualsUsbEventWithoutLockStates(7, false)))
177      .After(injects);
178  EXPECT_CALL(mock_stub,
179              InjectKeyEvent(EqualsUsbEventWithoutLockStates(5, false)))
180      .After(injects);
181
182  input_tracker.InjectKeyEvent(NewUsbEvent(3, true));
183  input_tracker.InjectKeyEvent(NewUsbEvent(6, true));
184  input_tracker.InjectKeyEvent(NewUsbEvent(7, true));
185  input_tracker.InjectKeyEvent(NewUsbEvent(5, true));
186  input_tracker.InjectKeyEvent(NewUsbEvent(5, true));
187  PressAndReleaseUsb(&input_tracker, 2);
188
189  EXPECT_FALSE(input_tracker.IsKeyPressed(1));
190  EXPECT_FALSE(input_tracker.IsKeyPressed(2));
191  EXPECT_TRUE(input_tracker.IsKeyPressed(3));
192  EXPECT_TRUE(input_tracker.IsKeyPressed(5));
193  EXPECT_TRUE(input_tracker.IsKeyPressed(6));
194  EXPECT_TRUE(input_tracker.IsKeyPressed(7));
195  EXPECT_EQ(4, input_tracker.PressedKeyCount());
196
197  input_tracker.ReleaseAll();
198}
199
200// Verify that invalid events get passed through but not tracked.
201TEST(InputEventTrackerTest, InvalidEventsNotTracked) {
202  MockInputStub mock_stub;
203  InputEventTracker input_tracker(&mock_stub);
204  ExpectationSet injects;
205
206  {
207    InSequence s;
208
209    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(3, true)));
210    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(1, true)));
211    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(1, false)));
212    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(_)).Times(2);
213    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(2, true)));
214    injects += EXPECT_CALL(mock_stub, InjectKeyEvent(EqualsUsbEvent(2, false)));
215  }
216
217  EXPECT_CALL(mock_stub,
218              InjectKeyEvent(EqualsUsbEventWithoutLockStates(3, false)))
219      .After(injects);
220
221  input_tracker.InjectKeyEvent(NewUsbEvent(3, true));
222  PressAndReleaseUsb(&input_tracker, 1);
223
224  KeyEvent invalid_event1;
225  invalid_event1.set_pressed(true);
226  input_tracker.InjectKeyEvent(invalid_event1);
227
228  KeyEvent invalid_event2;
229  invalid_event2.set_usb_keycode(6);
230  input_tracker.InjectKeyEvent(invalid_event2);
231
232  PressAndReleaseUsb(&input_tracker, 2);
233
234  EXPECT_FALSE(input_tracker.IsKeyPressed(1));
235  EXPECT_FALSE(input_tracker.IsKeyPressed(2));
236  EXPECT_TRUE(input_tracker.IsKeyPressed(3));
237  EXPECT_EQ(1, input_tracker.PressedKeyCount());
238
239  input_tracker.ReleaseAll();
240}
241
242}  // namespace protocol
243}  // namespace remoting
244