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.
4 
5 #include "remoting/host/touch_injector_win.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <map>
11 #include <utility>
12 
13 #include "base/stl_util.h"
14 #include "remoting/proto/event.pb.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 using ::testing::_;
19 using ::testing::AtLeast;
20 using ::testing::InSequence;
21 using ::testing::ExpectationSet;
22 using ::testing::Return;
23 
24 namespace remoting {
25 
26 using protocol::TouchEvent;
27 using protocol::TouchEventPoint;
28 
29 namespace {
30 
31 // Maps touch pointer ID to expected flags [start, move, end, cancel] listed
32 // below.
33 typedef std::map<uint32_t, uint32_t> IdFlagMap;
34 
35 const uint32_t kStartFlag =
36     POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT | POINTER_FLAG_DOWN;
37 
38 const uint32_t kMoveFlag =
39     POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT | POINTER_FLAG_UPDATE;
40 
41 const uint32_t kEndFlag = POINTER_FLAG_UP;
42 
43 const uint32_t kCancelFlag = POINTER_FLAG_UP | POINTER_FLAG_CANCELED;
44 
45 MATCHER_P(EqualsSinglePointerTouchInfo, expected, "") {
46   return arg->touchMask == expected.touchMask &&
47          arg->rcContact.left == expected.rcContact.left &&
48          arg->rcContact.top == expected.rcContact.top &&
49          arg->rcContact.right == expected.rcContact.right &&
50          arg->rcContact.bottom == expected.rcContact.bottom &&
51          arg->orientation == expected.orientation &&
52          arg->pressure == expected.pressure &&
53          arg->pointerInfo.pointerType == expected.pointerInfo.pointerType &&
54          arg->pointerInfo.pointerId == expected.pointerInfo.pointerId &&
55          arg->pointerInfo.ptPixelLocation.x ==
56              expected.pointerInfo.ptPixelLocation.x &&
57          arg->pointerInfo.ptPixelLocation.y ==
58              expected.pointerInfo.ptPixelLocation.y;
59 }
60 
61 // Make sure that every touch point has the right flag (pointerFlags).
62 MATCHER_P(EqualsPointerTouchInfoFlag, id_to_flag_map, "") {
63   for (size_t i = 0; i < id_to_flag_map.size(); ++i) {
64     const POINTER_TOUCH_INFO* touch_info = arg + i;
65     const uint32_t id = touch_info->pointerInfo.pointerId;
66     if (!base::Contains(id_to_flag_map, id))
67       return false;
68 
69     if (id_to_flag_map.find(id)->second != touch_info->pointerInfo.pointerFlags)
70       return false;
71   }
72   return true;
73 }
74 
75 class TouchInjectorWinDelegateMock : public TouchInjectorWinDelegate {
76  public:
TouchInjectorWinDelegateMock()77   TouchInjectorWinDelegateMock()
78       : TouchInjectorWinDelegate(nullptr, nullptr, nullptr) {}
~TouchInjectorWinDelegateMock()79   ~TouchInjectorWinDelegateMock() override {}
80 
81   MOCK_METHOD2(InitializeTouchInjection, BOOL(UINT32 max_count, DWORD dw_mode));
82   MOCK_METHOD2(InjectTouchInput,
83                DWORD(UINT32 count, const POINTER_TOUCH_INFO* contacts));
84 };
85 
86 }  // namespace
87 
88 // A test to make sure that the touch event is converted correctly to
89 // POINTER_TOUCH_INFO.
TEST(TouchInjectorWinTest,CheckConversionWithPressure)90 TEST(TouchInjectorWinTest, CheckConversionWithPressure) {
91   std::unique_ptr<TouchInjectorWinDelegateMock> delegate_mock(
92       new ::testing::StrictMock<TouchInjectorWinDelegateMock>());
93 
94   TouchEvent event;
95   event.set_event_type(TouchEvent::TOUCH_POINT_START);
96   TouchEventPoint* point = event.add_touch_points();
97   point->set_id(1234u);
98   point->set_x(321.0f);
99   point->set_y(123.0f);
100   point->set_radius_x(10.0f);
101   point->set_radius_y(20.0f);
102   point->set_pressure(0.5f);
103   point->set_angle(45.0f);
104 
105   POINTER_TOUCH_INFO expected_touch_info;
106   expected_touch_info.touchMask =
107       TOUCH_MASK_CONTACTAREA | TOUCH_MASK_ORIENTATION | TOUCH_MASK_PRESSURE;
108   expected_touch_info.rcContact.left = 311;
109   expected_touch_info.rcContact.top = 103;
110   expected_touch_info.rcContact.right = 331;
111   expected_touch_info.rcContact.bottom = 143;
112   expected_touch_info.orientation = 0;
113   expected_touch_info.pressure = 512;
114   expected_touch_info.orientation = 45;
115 
116   expected_touch_info.pointerInfo.pointerType = PT_TOUCH;
117   expected_touch_info.pointerInfo.pointerId = 1234u;
118   expected_touch_info.pointerInfo.ptPixelLocation.x = 321;
119   expected_touch_info.pointerInfo.ptPixelLocation.y = 123;
120 
121   InSequence s;
122   EXPECT_CALL(*delegate_mock, InitializeTouchInjection(_, _))
123       .WillOnce(Return(1));
124   EXPECT_CALL(
125       *delegate_mock,
126       InjectTouchInput(1, EqualsSinglePointerTouchInfo(expected_touch_info)))
127       .WillOnce(Return(1));
128 
129   // Check pressure clamping as well.
130   expected_touch_info.pressure = 1024;  // Max
131   EXPECT_CALL(
132       *delegate_mock,
133       InjectTouchInput(1, EqualsSinglePointerTouchInfo(expected_touch_info)))
134       .WillOnce(Return(1));
135 
136   expected_touch_info.pressure = 0;  // Min
137   EXPECT_CALL(
138       *delegate_mock,
139       InjectTouchInput(1, EqualsSinglePointerTouchInfo(expected_touch_info)))
140       .WillOnce(Return(1));
141 
142   TouchInjectorWin injector;
143   injector.SetInjectorDelegateForTest(std::move(delegate_mock));
144   EXPECT_TRUE(injector.Init());
145   injector.InjectTouchEvent(event);
146 
147   // Change to MOVE so that there still only one point.
148   event.set_event_type(TouchEvent::TOUCH_POINT_MOVE);
149   point->set_pressure(2.0f);
150   injector.InjectTouchEvent(event);
151 
152   point->set_pressure(-3.0f);
153   injector.InjectTouchEvent(event);
154 }
155 
156 // Some devices don't detect pressure. This test is a conversion check for
157 // such devices.
TEST(TouchInjectorWinTest,CheckConversionNoPressure)158 TEST(TouchInjectorWinTest, CheckConversionNoPressure) {
159   std::unique_ptr<TouchInjectorWinDelegateMock> delegate_mock(
160       new ::testing::StrictMock<TouchInjectorWinDelegateMock>());
161 
162   TouchEvent event;
163   event.set_event_type(TouchEvent::TOUCH_POINT_START);
164   TouchEventPoint* point = event.add_touch_points();
165   point->set_id(1234u);
166   point->set_x(321.0f);
167   point->set_y(123.0f);
168   point->set_radius_x(10.0f);
169   point->set_radius_y(20.0f);
170   point->set_angle(45.0f);
171 
172   POINTER_TOUCH_INFO expected_touch_info;
173   expected_touch_info.touchMask =
174       TOUCH_MASK_CONTACTAREA | TOUCH_MASK_ORIENTATION;
175   expected_touch_info.rcContact.left = 311;
176   expected_touch_info.rcContact.top = 103;
177   expected_touch_info.rcContact.right = 331;
178   expected_touch_info.rcContact.bottom = 143;
179   expected_touch_info.orientation = 0;
180   expected_touch_info.pressure = 0;
181   expected_touch_info.orientation = 45;
182 
183   expected_touch_info.pointerInfo.pointerType = PT_TOUCH;
184   expected_touch_info.pointerInfo.pointerId = 1234u;
185   expected_touch_info.pointerInfo.ptPixelLocation.x = 321;
186   expected_touch_info.pointerInfo.ptPixelLocation.y = 123;
187 
188   InSequence s;
189   EXPECT_CALL(*delegate_mock, InitializeTouchInjection(_, _))
190       .WillOnce(Return(1));
191   EXPECT_CALL(
192       *delegate_mock,
193       InjectTouchInput(1, EqualsSinglePointerTouchInfo(expected_touch_info)))
194       .WillOnce(Return(1));
195 
196   TouchInjectorWin injector;
197   injector.SetInjectorDelegateForTest(std::move(delegate_mock));
198   EXPECT_TRUE(injector.Init());
199   injector.InjectTouchEvent(event);
200 }
201 
202 // If initialization fails, it should not call any touch injection functions.
TEST(TouchInjectorWinTest,InitFailed)203 TEST(TouchInjectorWinTest, InitFailed) {
204   std::unique_ptr<TouchInjectorWinDelegateMock> delegate_mock(
205       new ::testing::StrictMock<TouchInjectorWinDelegateMock>());
206 
207   TouchEvent event;
208   event.set_event_type(TouchEvent::TOUCH_POINT_START);
209 
210   InSequence s;
211   EXPECT_CALL(*delegate_mock, InitializeTouchInjection(_, _))
212       .WillOnce(Return(0));
213   EXPECT_CALL(*delegate_mock, InjectTouchInput(_, _)).Times(0);
214 
215   TouchInjectorWin injector;
216   injector.SetInjectorDelegateForTest(std::move(delegate_mock));
217   EXPECT_FALSE(injector.Init());
218   injector.InjectTouchEvent(event);
219 }
220 
221 // Deinitialize and initialize should clean the state.
TEST(TouchInjectorWinTest,Reinitialize)222 TEST(TouchInjectorWinTest, Reinitialize) {
223   std::unique_ptr<TouchInjectorWinDelegateMock>
224       delegate_mock_before_deinitialize(
225           new ::testing::StrictMock<TouchInjectorWinDelegateMock>());
226   std::unique_ptr<TouchInjectorWinDelegateMock>
227       delegate_mock_after_deinitialize(
228           new ::testing::StrictMock<TouchInjectorWinDelegateMock>());
229 
230   TouchEvent first_event;
231   first_event.set_event_type(TouchEvent::TOUCH_POINT_START);
232   TouchEventPoint* point0 = first_event.add_touch_points();
233   point0->set_id(0u);
234 
235   TouchEvent second_event;
236   second_event.set_event_type(TouchEvent::TOUCH_POINT_START);
237   TouchEventPoint* point1 = second_event.add_touch_points();
238   point1->set_id(1u);
239 
240   InSequence s;
241   EXPECT_CALL(*delegate_mock_before_deinitialize,
242               InitializeTouchInjection(_, _)).WillOnce(Return(1));
243 
244   IdFlagMap id_to_flags;
245   id_to_flags[0u] = kStartFlag;
246   EXPECT_CALL(
247       *delegate_mock_before_deinitialize,
248       InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags)))
249       .WillOnce(Return(1));
250 
251   EXPECT_CALL(*delegate_mock_after_deinitialize,
252               InitializeTouchInjection(_, _)).WillOnce(Return(1));
253 
254   // After deinitializing and then initializing, previous touch points should be
255   // gone.
256   id_to_flags.clear();
257   id_to_flags[1u] = kStartFlag;
258   EXPECT_CALL(
259       *delegate_mock_after_deinitialize,
260       InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags)))
261       .WillOnce(Return(1));
262 
263   TouchInjectorWin injector;
264   injector.SetInjectorDelegateForTest(
265       std::move(delegate_mock_before_deinitialize));
266 
267   EXPECT_TRUE(injector.Init());
268   injector.InjectTouchEvent(first_event);
269   injector.Deinitialize();
270 
271   injector.SetInjectorDelegateForTest(
272       std::move(delegate_mock_after_deinitialize));
273   EXPECT_TRUE(injector.Init());
274   injector.InjectTouchEvent(second_event);
275 }
276 
277 // Make sure that the flag is set to kStartFlag.
TEST(TouchInjectorWinTest,StartTouchPoint)278 TEST(TouchInjectorWinTest, StartTouchPoint) {
279   std::unique_ptr<TouchInjectorWinDelegateMock> delegate_mock(
280       new ::testing::StrictMock<TouchInjectorWinDelegateMock>());
281 
282   TouchEvent event;
283   event.set_event_type(TouchEvent::TOUCH_POINT_START);
284   TouchEventPoint* point = event.add_touch_points();
285   point->set_id(0u);
286 
287   InSequence s;
288   EXPECT_CALL(*delegate_mock, InitializeTouchInjection(_, _))
289       .WillOnce(Return(1));
290 
291   IdFlagMap id_to_flags;
292   id_to_flags[0u] = kStartFlag;
293   EXPECT_CALL(
294       *delegate_mock,
295       InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags)))
296       .WillOnce(Return(1));
297 
298   TouchInjectorWin injector;
299   injector.SetInjectorDelegateForTest(std::move(delegate_mock));
300   EXPECT_TRUE(injector.Init());
301   injector.InjectTouchEvent(event);
302 }
303 
304 // Start a point and then move, make sure the flag is set to kMoveFlag.
TEST(TouchInjectorWinTest,MoveTouchPoint)305 TEST(TouchInjectorWinTest, MoveTouchPoint) {
306   std::unique_ptr<TouchInjectorWinDelegateMock> delegate_mock(
307       new ::testing::StrictMock<TouchInjectorWinDelegateMock>());
308 
309   TouchEvent event;
310   event.set_event_type(TouchEvent::TOUCH_POINT_START);
311   TouchEventPoint* point = event.add_touch_points();
312   point->set_id(0u);
313 
314 
315   InSequence s;
316   EXPECT_CALL(*delegate_mock, InitializeTouchInjection(_, _))
317       .WillOnce(Return(1));
318 
319   IdFlagMap id_to_flags;
320   id_to_flags[0u] = kStartFlag;
321   EXPECT_CALL(
322       *delegate_mock,
323       InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags)))
324       .WillOnce(Return(1));
325 
326   id_to_flags[0u] = kMoveFlag;
327   EXPECT_CALL(
328       *delegate_mock,
329       InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags)))
330       .WillOnce(Return(1));
331 
332   TouchInjectorWin injector;
333   injector.SetInjectorDelegateForTest(std::move(delegate_mock));
334   EXPECT_TRUE(injector.Init());
335   injector.InjectTouchEvent(event);
336   event.set_event_type(TouchEvent::TOUCH_POINT_MOVE);
337   injector.InjectTouchEvent(event);
338 }
339 
340 // Start a point and then move, make sure the flag is set to kEndFlag.
TEST(TouchInjectorWinTest,EndTouchPoint)341 TEST(TouchInjectorWinTest, EndTouchPoint) {
342   std::unique_ptr<TouchInjectorWinDelegateMock> delegate_mock(
343       new ::testing::StrictMock<TouchInjectorWinDelegateMock>());
344 
345   TouchEvent event;
346   event.set_event_type(TouchEvent::TOUCH_POINT_START);
347   TouchEventPoint* point = event.add_touch_points();
348   point->set_id(0u);
349 
350   InSequence s;
351   EXPECT_CALL(*delegate_mock, InitializeTouchInjection(_, _))
352       .WillOnce(Return(1));
353 
354   IdFlagMap id_to_flags;
355   id_to_flags[0u] = kStartFlag;
356   EXPECT_CALL(
357       *delegate_mock,
358       InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags)))
359       .WillOnce(Return(1));
360 
361   id_to_flags[0u] = kEndFlag;
362   EXPECT_CALL(
363       *delegate_mock,
364       InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags)))
365       .WillOnce(Return(1));
366 
367   TouchInjectorWin injector;
368   injector.SetInjectorDelegateForTest(std::move(delegate_mock));
369   EXPECT_TRUE(injector.Init());
370   injector.InjectTouchEvent(event);
371   event.set_event_type(TouchEvent::TOUCH_POINT_END);
372   injector.InjectTouchEvent(event);
373 }
374 
375 // Start a point and then move, make sure the flag is set to kCancelFlag.
TEST(TouchInjectorWinTest,CancelTouchPoint)376 TEST(TouchInjectorWinTest, CancelTouchPoint) {
377   std::unique_ptr<TouchInjectorWinDelegateMock> delegate_mock(
378       new ::testing::StrictMock<TouchInjectorWinDelegateMock>());
379 
380   TouchEvent event;
381   event.set_event_type(TouchEvent::TOUCH_POINT_START);
382   TouchEventPoint* point = event.add_touch_points();
383   point->set_id(0u);
384 
385   InSequence s;
386   EXPECT_CALL(*delegate_mock, InitializeTouchInjection(_, _))
387       .WillOnce(Return(1));
388 
389   IdFlagMap id_to_flags;
390   id_to_flags[0u] = kStartFlag;
391   EXPECT_CALL(
392       *delegate_mock,
393       InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags)))
394       .WillOnce(Return(1));
395 
396   id_to_flags[0u] = kCancelFlag;
397   EXPECT_CALL(
398       *delegate_mock,
399       InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags)))
400       .WillOnce(Return(1));
401 
402   TouchInjectorWin injector;
403   injector.SetInjectorDelegateForTest(std::move(delegate_mock));
404   EXPECT_TRUE(injector.Init());
405   injector.InjectTouchEvent(event);
406   event.set_event_type(TouchEvent::TOUCH_POINT_CANCEL);
407   injector.InjectTouchEvent(event);
408 }
409 
410 // Note that points that haven't changed should be injected as MOVE.
411 // This tests:
412 // 1. Start first touch point.
413 // 2. Start second touch point.
414 // 3. Move both touch points.
415 // 4. Start third touch point.
416 // 5. End second touch point.
417 // 6. Cancel remaining (first and third) touch points.
TEST(TouchInjectorWinTest,MultiTouch)418 TEST(TouchInjectorWinTest, MultiTouch) {
419   std::unique_ptr<TouchInjectorWinDelegateMock> delegate_mock(
420       new ::testing::StrictMock<TouchInjectorWinDelegateMock>());
421 
422   InSequence s;
423   EXPECT_CALL(*delegate_mock, InitializeTouchInjection(_, _))
424       .WillOnce(Return(1));
425 
426   IdFlagMap id_to_flags;
427   id_to_flags[0u] = kStartFlag;
428   EXPECT_CALL(
429       *delegate_mock,
430       InjectTouchInput(1, EqualsPointerTouchInfoFlag(id_to_flags)))
431       .WillOnce(Return(1));
432 
433   id_to_flags[0u] = kMoveFlag;
434   id_to_flags[1u] = kStartFlag;
435   EXPECT_CALL(
436       *delegate_mock,
437       InjectTouchInput(2, EqualsPointerTouchInfoFlag(id_to_flags)))
438       .WillOnce(Return(1));
439 
440   id_to_flags[0u] = kMoveFlag;
441   id_to_flags[1u] = kMoveFlag;
442   EXPECT_CALL(
443       *delegate_mock,
444       InjectTouchInput(2, EqualsPointerTouchInfoFlag(id_to_flags)))
445       .WillOnce(Return(1));
446 
447   id_to_flags[0u] = kMoveFlag;
448   id_to_flags[1u] = kMoveFlag;
449   id_to_flags[2u] = kStartFlag;
450   EXPECT_CALL(
451       *delegate_mock,
452       InjectTouchInput(3, EqualsPointerTouchInfoFlag(id_to_flags)))
453       .WillOnce(Return(1));
454 
455   id_to_flags[0u] = kMoveFlag;
456   id_to_flags[1u] = kEndFlag;
457   id_to_flags[2u] = kMoveFlag;
458   EXPECT_CALL(
459       *delegate_mock,
460       InjectTouchInput(3, EqualsPointerTouchInfoFlag(id_to_flags)))
461       .WillOnce(Return(1));
462 
463   id_to_flags.erase(1u);
464   id_to_flags[0u] = kCancelFlag;
465   id_to_flags[2u] = kCancelFlag;
466   EXPECT_CALL(
467       *delegate_mock,
468       InjectTouchInput(2, EqualsPointerTouchInfoFlag(id_to_flags)))
469       .WillOnce(Return(1));
470 
471   TouchInjectorWin injector;
472   injector.SetInjectorDelegateForTest(std::move(delegate_mock));
473   EXPECT_TRUE(injector.Init());
474 
475   // Start first touch point.
476   TouchEvent first_touch_start;
477   first_touch_start.set_event_type(TouchEvent::TOUCH_POINT_START);
478   TouchEventPoint* point0 = first_touch_start.add_touch_points();
479   point0->set_id(0u);
480   injector.InjectTouchEvent(first_touch_start);
481 
482   // Add second touch point.
483   TouchEvent second_touch_start;
484   second_touch_start.set_event_type(TouchEvent::TOUCH_POINT_START);
485   TouchEventPoint* point1 = second_touch_start.add_touch_points();
486   point1->set_id(1u);
487   injector.InjectTouchEvent(second_touch_start);
488 
489   // Move both touch points.
490   TouchEvent move_both;
491   move_both.set_event_type(TouchEvent::TOUCH_POINT_MOVE);
492   point0 = second_touch_start.add_touch_points();
493   point1 = second_touch_start.add_touch_points();
494   point0->set_id(0u);
495   point1->set_id(1u);
496   injector.InjectTouchEvent(move_both);
497 
498   // Add another.
499   TouchEvent third_touch_start;
500   third_touch_start.set_event_type(TouchEvent::TOUCH_POINT_START);
501   TouchEventPoint* point2 = third_touch_start.add_touch_points();
502   point2->set_id(2u);
503   injector.InjectTouchEvent(third_touch_start);
504 
505   // Release second touch point.
506   TouchEvent release_second;
507   release_second.set_event_type(TouchEvent::TOUCH_POINT_END);
508   point1 = release_second.add_touch_points();
509   point1->set_id(1u);
510   injector.InjectTouchEvent(release_second);
511 
512   // Cancel the remaining two points.
513   TouchEvent cancel_rest;
514   cancel_rest.set_event_type(TouchEvent::TOUCH_POINT_CANCEL);
515   point0 = cancel_rest.add_touch_points();
516   point0->set_id(0u);
517   point2 = cancel_rest.add_touch_points();
518   point2->set_id(2u);
519   injector.InjectTouchEvent(cancel_rest);
520 }
521 
522 }  // namespace remoting
523