1 // Copyright 2015 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.
5 #include "remoting/host/touch_injector_win.h"
9 #include "base/stl_util.h"
10 #include "remoting/proto/event.pb.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
15 using ::testing::AtLeast
;
16 using ::testing::InSequence
;
17 using ::testing::ExpectationSet
;
18 using ::testing::Return
;
22 using protocol::TouchEvent
;
23 using protocol::TouchEventPoint
;
27 // Maps touch pointer ID to expected flags [start, move, end, cancel] listed
29 typedef std::map
<uint32_t, uint32_t> IdFlagMap
;
31 const uint32_t kStartFlag
=
32 POINTER_FLAG_INRANGE
| POINTER_FLAG_INCONTACT
| POINTER_FLAG_DOWN
;
34 const uint32_t kMoveFlag
=
35 POINTER_FLAG_INRANGE
| POINTER_FLAG_INCONTACT
| POINTER_FLAG_UPDATE
;
37 const uint32_t kEndFlag
= POINTER_FLAG_UP
;
39 const uint32_t kCancelFlag
= POINTER_FLAG_UP
| POINTER_FLAG_CANCELED
;
41 MATCHER_P(EqualsSinglePointerTouchInfo
, expected
, "") {
42 return arg
->touchMask
== expected
.touchMask
&&
43 arg
->rcContact
.left
== expected
.rcContact
.left
&&
44 arg
->rcContact
.top
== expected
.rcContact
.top
&&
45 arg
->rcContact
.right
== expected
.rcContact
.right
&&
46 arg
->rcContact
.bottom
== expected
.rcContact
.bottom
&&
47 arg
->orientation
== expected
.orientation
&&
48 arg
->pressure
== expected
.pressure
&&
49 arg
->pointerInfo
.pointerType
== expected
.pointerInfo
.pointerType
&&
50 arg
->pointerInfo
.pointerId
== expected
.pointerInfo
.pointerId
&&
51 arg
->pointerInfo
.ptPixelLocation
.x
==
52 expected
.pointerInfo
.ptPixelLocation
.x
&&
53 arg
->pointerInfo
.ptPixelLocation
.y
==
54 expected
.pointerInfo
.ptPixelLocation
.y
;
57 // Make sure that every touch point has the right flag (pointerFlags).
58 MATCHER_P(EqualsPointerTouchInfoFlag
, id_to_flag_map
, "") {
59 for (size_t i
= 0; i
< id_to_flag_map
.size(); ++i
) {
60 const POINTER_TOUCH_INFO
* touch_info
= arg
+ i
;
61 const uint32_t id
= touch_info
->pointerInfo
.pointerId
;
62 if (!ContainsKey(id_to_flag_map
, id
))
65 if (id_to_flag_map
.find(id
)->second
!= touch_info
->pointerInfo
.pointerFlags
)
71 class TouchInjectorWinDelegateMock
: public TouchInjectorWinDelegate
{
73 TouchInjectorWinDelegateMock()
74 : TouchInjectorWinDelegate(nullptr, nullptr, nullptr) {}
75 ~TouchInjectorWinDelegateMock() override
{};
77 MOCK_METHOD2(InitializeTouchInjection
, BOOL(UINT32 max_count
, DWORD dw_mode
));
78 MOCK_METHOD2(InjectTouchInput
,
79 DWORD(UINT32 count
, const POINTER_TOUCH_INFO
* contacts
));
84 // A test to make sure that the touch event is converted correctly to
85 // POINTER_TOUCH_INFO.
86 TEST(TouchInjectorWinTest
, CheckConversionWithPressure
) {
87 scoped_ptr
<TouchInjectorWinDelegateMock
> delegate_mock(
88 new ::testing::StrictMock
<TouchInjectorWinDelegateMock
>());
91 event
.set_event_type(TouchEvent::TOUCH_POINT_START
);
92 TouchEventPoint
* point
= event
.add_touch_points();
96 point
->set_radius_x(10.0f
);
97 point
->set_radius_y(20.0f
);
98 point
->set_pressure(0.5f
);
99 point
->set_angle(45.0f
);
101 POINTER_TOUCH_INFO expected_touch_info
;
102 expected_touch_info
.touchMask
=
103 TOUCH_MASK_CONTACTAREA
| TOUCH_MASK_ORIENTATION
| TOUCH_MASK_PRESSURE
;
104 expected_touch_info
.rcContact
.left
= 311;
105 expected_touch_info
.rcContact
.top
= 103;
106 expected_touch_info
.rcContact
.right
= 331;
107 expected_touch_info
.rcContact
.bottom
= 143;
108 expected_touch_info
.orientation
= 0;
109 expected_touch_info
.pressure
= 512;
110 expected_touch_info
.orientation
= 45;
112 expected_touch_info
.pointerInfo
.pointerType
= PT_TOUCH
;
113 expected_touch_info
.pointerInfo
.pointerId
= 1234u;
114 expected_touch_info
.pointerInfo
.ptPixelLocation
.x
= 321;
115 expected_touch_info
.pointerInfo
.ptPixelLocation
.y
= 123;
118 EXPECT_CALL(*delegate_mock
, InitializeTouchInjection(_
, _
))
119 .WillOnce(Return(1));
122 InjectTouchInput(1, EqualsSinglePointerTouchInfo(expected_touch_info
)))
123 .WillOnce(Return(1));
125 // Check pressure clamping as well.
126 expected_touch_info
.pressure
= 1024; // Max
129 InjectTouchInput(1, EqualsSinglePointerTouchInfo(expected_touch_info
)))
130 .WillOnce(Return(1));
132 expected_touch_info
.pressure
= 0; // Min
135 InjectTouchInput(1, EqualsSinglePointerTouchInfo(expected_touch_info
)))
136 .WillOnce(Return(1));
138 TouchInjectorWin injector
;
139 injector
.SetInjectorDelegateForTest(delegate_mock
.Pass());
140 EXPECT_TRUE(injector
.Init());
141 injector
.InjectTouchEvent(event
);
143 // Change to MOVE so that there still only one point.
144 event
.set_event_type(TouchEvent::TOUCH_POINT_MOVE
);
145 point
->set_pressure(2.0f
);
146 injector
.InjectTouchEvent(event
);
148 point
->set_pressure(-3.0f
);
149 injector
.InjectTouchEvent(event
);
152 // Some devices don't detect pressure. This test is a conversion check for
154 TEST(TouchInjectorWinTest
, CheckConversionNoPressure
) {
155 scoped_ptr
<TouchInjectorWinDelegateMock
> delegate_mock(
156 new ::testing::StrictMock
<TouchInjectorWinDelegateMock
>());
159 event
.set_event_type(TouchEvent::TOUCH_POINT_START
);
160 TouchEventPoint
* point
= event
.add_touch_points();
161 point
->set_id(1234u);
162 point
->set_x(321.0f
);
163 point
->set_y(123.0f
);
164 point
->set_radius_x(10.0f
);
165 point
->set_radius_y(20.0f
);
166 point
->set_angle(45.0f
);
168 POINTER_TOUCH_INFO expected_touch_info
;
169 expected_touch_info
.touchMask
=
170 TOUCH_MASK_CONTACTAREA
| TOUCH_MASK_ORIENTATION
;
171 expected_touch_info
.rcContact
.left
= 311;
172 expected_touch_info
.rcContact
.top
= 103;
173 expected_touch_info
.rcContact
.right
= 331;
174 expected_touch_info
.rcContact
.bottom
= 143;
175 expected_touch_info
.orientation
= 0;
176 expected_touch_info
.pressure
= 0;
177 expected_touch_info
.orientation
= 45;
179 expected_touch_info
.pointerInfo
.pointerType
= PT_TOUCH
;
180 expected_touch_info
.pointerInfo
.pointerId
= 1234u;
181 expected_touch_info
.pointerInfo
.ptPixelLocation
.x
= 321;
182 expected_touch_info
.pointerInfo
.ptPixelLocation
.y
= 123;
185 EXPECT_CALL(*delegate_mock
, InitializeTouchInjection(_
, _
))
186 .WillOnce(Return(1));
189 InjectTouchInput(1, EqualsSinglePointerTouchInfo(expected_touch_info
)))
190 .WillOnce(Return(1));
192 TouchInjectorWin injector
;
193 injector
.SetInjectorDelegateForTest(delegate_mock
.Pass());
194 EXPECT_TRUE(injector
.Init());
195 injector
.InjectTouchEvent(event
);
198 // If initialization fails, it should not call any touch injection functions.
199 TEST(TouchInjectorWinTest
, InitFailed
) {
200 scoped_ptr
<TouchInjectorWinDelegateMock
> delegate_mock(
201 new ::testing::StrictMock
<TouchInjectorWinDelegateMock
>());
204 event
.set_event_type(TouchEvent::TOUCH_POINT_START
);
207 EXPECT_CALL(*delegate_mock
, InitializeTouchInjection(_
, _
))
208 .WillOnce(Return(0));
209 EXPECT_CALL(*delegate_mock
, InjectTouchInput(_
, _
)).Times(0);
211 TouchInjectorWin injector
;
212 injector
.SetInjectorDelegateForTest(delegate_mock
.Pass());
213 EXPECT_FALSE(injector
.Init());
214 injector
.InjectTouchEvent(event
);
217 // Deinitialize and initialize should clean the state.
218 TEST(TouchInjectorWinTest
, Reinitialize
) {
219 scoped_ptr
<TouchInjectorWinDelegateMock
> delegate_mock_before_deinitialize(
220 new ::testing::StrictMock
<TouchInjectorWinDelegateMock
>());
221 scoped_ptr
<TouchInjectorWinDelegateMock
> delegate_mock_after_deinitialize(
222 new ::testing::StrictMock
<TouchInjectorWinDelegateMock
>());
224 TouchEvent first_event
;
225 first_event
.set_event_type(TouchEvent::TOUCH_POINT_START
);
226 TouchEventPoint
* point0
= first_event
.add_touch_points();
229 TouchEvent second_event
;
230 second_event
.set_event_type(TouchEvent::TOUCH_POINT_START
);
231 TouchEventPoint
* point1
= second_event
.add_touch_points();
235 EXPECT_CALL(*delegate_mock_before_deinitialize
,
236 InitializeTouchInjection(_
, _
)).WillOnce(Return(1));
238 IdFlagMap id_to_flags
;
239 id_to_flags
[0u] = kStartFlag
;
241 *delegate_mock_before_deinitialize
,
242 InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags
)))
243 .WillOnce(Return(1));
245 EXPECT_CALL(*delegate_mock_after_deinitialize
,
246 InitializeTouchInjection(_
, _
)).WillOnce(Return(1));
248 // After deinitializing and then initializing, previous touch points should be
251 id_to_flags
[1u] = kStartFlag
;
253 *delegate_mock_after_deinitialize
,
254 InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags
)))
255 .WillOnce(Return(1));
257 TouchInjectorWin injector
;
258 injector
.SetInjectorDelegateForTest(delegate_mock_before_deinitialize
.Pass());
260 EXPECT_TRUE(injector
.Init());
261 injector
.InjectTouchEvent(first_event
);
262 injector
.Deinitialize();
264 injector
.SetInjectorDelegateForTest(delegate_mock_after_deinitialize
.Pass());
265 EXPECT_TRUE(injector
.Init());
266 injector
.InjectTouchEvent(second_event
);
269 // Make sure that the flag is set to kStartFlag.
270 TEST(TouchInjectorWinTest
, StartTouchPoint
) {
271 scoped_ptr
<TouchInjectorWinDelegateMock
> delegate_mock(
272 new ::testing::StrictMock
<TouchInjectorWinDelegateMock
>());
275 event
.set_event_type(TouchEvent::TOUCH_POINT_START
);
276 TouchEventPoint
* point
= event
.add_touch_points();
280 EXPECT_CALL(*delegate_mock
, InitializeTouchInjection(_
, _
))
281 .WillOnce(Return(1));
283 IdFlagMap id_to_flags
;
284 id_to_flags
[0u] = kStartFlag
;
287 InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags
)))
288 .WillOnce(Return(1));
290 TouchInjectorWin injector
;
291 injector
.SetInjectorDelegateForTest(delegate_mock
.Pass());
292 EXPECT_TRUE(injector
.Init());
293 injector
.InjectTouchEvent(event
);
296 // Start a point and then move, make sure the flag is set to kMoveFlag.
297 TEST(TouchInjectorWinTest
, MoveTouchPoint
) {
298 scoped_ptr
<TouchInjectorWinDelegateMock
> delegate_mock(
299 new ::testing::StrictMock
<TouchInjectorWinDelegateMock
>());
302 event
.set_event_type(TouchEvent::TOUCH_POINT_START
);
303 TouchEventPoint
* point
= event
.add_touch_points();
308 EXPECT_CALL(*delegate_mock
, InitializeTouchInjection(_
, _
))
309 .WillOnce(Return(1));
311 IdFlagMap id_to_flags
;
312 id_to_flags
[0u] = kStartFlag
;
315 InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags
)))
316 .WillOnce(Return(1));
318 id_to_flags
[0u] = kMoveFlag
;
321 InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags
)))
322 .WillOnce(Return(1));
324 TouchInjectorWin injector
;
325 injector
.SetInjectorDelegateForTest(delegate_mock
.Pass());
326 EXPECT_TRUE(injector
.Init());
327 injector
.InjectTouchEvent(event
);
328 event
.set_event_type(TouchEvent::TOUCH_POINT_MOVE
);
329 injector
.InjectTouchEvent(event
);
332 // Start a point and then move, make sure the flag is set to kEndFlag.
333 TEST(TouchInjectorWinTest
, EndTouchPoint
) {
334 scoped_ptr
<TouchInjectorWinDelegateMock
> delegate_mock(
335 new ::testing::StrictMock
<TouchInjectorWinDelegateMock
>());
338 event
.set_event_type(TouchEvent::TOUCH_POINT_START
);
339 TouchEventPoint
* point
= event
.add_touch_points();
343 EXPECT_CALL(*delegate_mock
, InitializeTouchInjection(_
, _
))
344 .WillOnce(Return(1));
346 IdFlagMap id_to_flags
;
347 id_to_flags
[0u] = kStartFlag
;
350 InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags
)))
351 .WillOnce(Return(1));
353 id_to_flags
[0u] = kEndFlag
;
356 InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags
)))
357 .WillOnce(Return(1));
359 TouchInjectorWin injector
;
360 injector
.SetInjectorDelegateForTest(delegate_mock
.Pass());
361 EXPECT_TRUE(injector
.Init());
362 injector
.InjectTouchEvent(event
);
363 event
.set_event_type(TouchEvent::TOUCH_POINT_END
);
364 injector
.InjectTouchEvent(event
);
367 // Start a point and then move, make sure the flag is set to kCancelFlag.
368 TEST(TouchInjectorWinTest
, CancelTouchPoint
) {
369 scoped_ptr
<TouchInjectorWinDelegateMock
> delegate_mock(
370 new ::testing::StrictMock
<TouchInjectorWinDelegateMock
>());
373 event
.set_event_type(TouchEvent::TOUCH_POINT_START
);
374 TouchEventPoint
* point
= event
.add_touch_points();
378 EXPECT_CALL(*delegate_mock
, InitializeTouchInjection(_
, _
))
379 .WillOnce(Return(1));
381 IdFlagMap id_to_flags
;
382 id_to_flags
[0u] = kStartFlag
;
385 InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags
)))
386 .WillOnce(Return(1));
388 id_to_flags
[0u] = kCancelFlag
;
391 InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags
)))
392 .WillOnce(Return(1));
394 TouchInjectorWin injector
;
395 injector
.SetInjectorDelegateForTest(delegate_mock
.Pass());
396 EXPECT_TRUE(injector
.Init());
397 injector
.InjectTouchEvent(event
);
398 event
.set_event_type(TouchEvent::TOUCH_POINT_CANCEL
);
399 injector
.InjectTouchEvent(event
);
402 // Note that points that haven't changed should be injected as MOVE.
404 // 1. Start first touch point.
405 // 2. Start second touch point.
406 // 3. Move both touch points.
407 // 4. Start third touch point.
408 // 5. End second touch point.
409 // 6. Cancel remaining (first and third) touch points.
410 TEST(TouchInjectorWinTest
, MultiTouch
) {
411 scoped_ptr
<TouchInjectorWinDelegateMock
> delegate_mock(
412 new ::testing::StrictMock
<TouchInjectorWinDelegateMock
>());
415 EXPECT_CALL(*delegate_mock
, InitializeTouchInjection(_
, _
))
416 .WillOnce(Return(1));
418 IdFlagMap id_to_flags
;
419 id_to_flags
[0u] = kStartFlag
;
422 InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags
)))
423 .WillOnce(Return(1));
425 id_to_flags
[0u] = kMoveFlag
;
426 id_to_flags
[1u] = kStartFlag
;
429 InjectTouchInput(2, EqualsPointerTouchInfoFlag(id_to_flags
)))
430 .WillOnce(Return(1));
432 id_to_flags
[0u] = kMoveFlag
;
433 id_to_flags
[1u] = kMoveFlag
;
436 InjectTouchInput(2, EqualsPointerTouchInfoFlag(id_to_flags
)))
437 .WillOnce(Return(1));
439 id_to_flags
[0u] = kMoveFlag
;
440 id_to_flags
[1u] = kMoveFlag
;
441 id_to_flags
[2u] = kStartFlag
;
444 InjectTouchInput(3, EqualsPointerTouchInfoFlag(id_to_flags
)))
445 .WillOnce(Return(1));
447 id_to_flags
[0u] = kMoveFlag
;
448 id_to_flags
[1u] = kEndFlag
;
449 id_to_flags
[2u] = kMoveFlag
;
452 InjectTouchInput(3, EqualsPointerTouchInfoFlag(id_to_flags
)))
453 .WillOnce(Return(1));
455 id_to_flags
.erase(1u);
456 id_to_flags
[0u] = kCancelFlag
;
457 id_to_flags
[2u] = kCancelFlag
;
460 InjectTouchInput(2, EqualsPointerTouchInfoFlag(id_to_flags
)))
461 .WillOnce(Return(1));
463 TouchInjectorWin injector
;
464 injector
.SetInjectorDelegateForTest(delegate_mock
.Pass());
465 EXPECT_TRUE(injector
.Init());
467 // Start first touch point.
468 TouchEvent first_touch_start
;
469 first_touch_start
.set_event_type(TouchEvent::TOUCH_POINT_START
);
470 TouchEventPoint
* point0
= first_touch_start
.add_touch_points();
472 injector
.InjectTouchEvent(first_touch_start
);
474 // Add second touch point.
475 TouchEvent second_touch_start
;
476 second_touch_start
.set_event_type(TouchEvent::TOUCH_POINT_START
);
477 TouchEventPoint
* point1
= second_touch_start
.add_touch_points();
479 injector
.InjectTouchEvent(second_touch_start
);
481 // Move both touch points.
482 TouchEvent move_both
;
483 move_both
.set_event_type(TouchEvent::TOUCH_POINT_MOVE
);
484 point0
= second_touch_start
.add_touch_points();
485 point1
= second_touch_start
.add_touch_points();
488 injector
.InjectTouchEvent(move_both
);
491 TouchEvent third_touch_start
;
492 third_touch_start
.set_event_type(TouchEvent::TOUCH_POINT_START
);
493 TouchEventPoint
* point2
= third_touch_start
.add_touch_points();
495 injector
.InjectTouchEvent(third_touch_start
);
497 // Release second touch point.
498 TouchEvent release_second
;
499 release_second
.set_event_type(TouchEvent::TOUCH_POINT_END
);
500 point1
= release_second
.add_touch_points();
502 injector
.InjectTouchEvent(release_second
);
504 // Cancel the remaining two points.
505 TouchEvent cancel_rest
;
506 cancel_rest
.set_event_type(TouchEvent::TOUCH_POINT_CANCEL
);
507 point0
= cancel_rest
.add_touch_points();
509 point2
= cancel_rest
.add_touch_points();
511 injector
.InjectTouchEvent(cancel_rest
);
514 } // namespace remoting