1 // Copyright 2012 The ChromiumOS Authors
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 <gtest/gtest.h>
6
7 #include "include/gestures.h"
8 #include "include/mouse_interpreter.h"
9 #include "include/unittest_util.h"
10 #include "include/util.h"
11
12 namespace gestures {
13
make_hwprops_for_mouse(unsigned has_wheel,unsigned wheel_is_hi_res)14 HardwareProperties make_hwprops_for_mouse(
15 unsigned has_wheel, unsigned wheel_is_hi_res) {
16 return {
17 .right = 0,
18 .bottom = 0,
19 .res_x = 0,
20 .res_y = 0,
21 .screen_x_dpi = 0,
22 .screen_y_dpi = 0,
23 .orientation_minimum = 0,
24 .orientation_maximum = 0,
25 .max_finger_cnt = 0,
26 .max_touch_cnt = 0,
27 .supports_t5r2 = 0,
28 .support_semi_mt = 0,
29 .is_button_pad = 0,
30 .has_wheel = has_wheel,
31 .wheel_is_hi_res = wheel_is_hi_res,
32 .is_haptic_pad = 0,
33 };
34 }
35
36 class MouseInterpreterTest : public ::testing::Test {};
37
TEST(MouseInterpreterTest,SimpleTest)38 TEST(MouseInterpreterTest, SimpleTest) {
39 HardwareProperties hwprops = make_hwprops_for_mouse(1, 0);
40 MouseInterpreter mi(nullptr, nullptr);
41 TestInterpreterWrapper wrapper(&mi, &hwprops);
42 Gesture* gs;
43
44 HardwareState hwstates[] = {
45 { 200000, 0, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
46 { 210000, 0, 0, 0, nullptr, 9, -7, 0, 0, 0, 0.0 },
47 { 220000, 1, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
48 { 230000, 0, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
49 { 240000, 0, 0, 0, nullptr, 0, 0, -3, -360, 4, 0.0 },
50 };
51
52 mi.output_mouse_wheel_gestures_.val_ = true;
53
54 gs = wrapper.SyncInterpret(hwstates[0], nullptr);
55 EXPECT_EQ(nullptr, gs);
56
57 gs = wrapper.SyncInterpret(hwstates[1], nullptr);
58 ASSERT_NE(nullptr, gs);
59 EXPECT_EQ(kGestureTypeMove, gs->type);
60 EXPECT_EQ(9, gs->details.move.dx);
61 EXPECT_EQ(-7, gs->details.move.dy);
62 EXPECT_EQ(200000, gs->start_time);
63 EXPECT_EQ(210000, gs->end_time);
64
65 gs = wrapper.SyncInterpret(hwstates[2], nullptr);
66 ASSERT_NE(nullptr, gs);
67 EXPECT_EQ(kGestureTypeButtonsChange, gs->type);
68 EXPECT_EQ(1, gs->details.buttons.down);
69 EXPECT_EQ(0, gs->details.buttons.up);
70 EXPECT_EQ(210000, gs->start_time);
71 EXPECT_EQ(220000, gs->end_time);
72
73 gs = wrapper.SyncInterpret(hwstates[3], nullptr);
74 ASSERT_NE(nullptr, gs);
75 EXPECT_EQ(kGestureTypeButtonsChange, gs->type);
76 EXPECT_EQ(0, gs->details.buttons.down);
77 EXPECT_EQ(1, gs->details.buttons.up);
78 EXPECT_EQ(220000, gs->start_time);
79 EXPECT_EQ(230000, gs->end_time);
80
81 gs = wrapper.SyncInterpret(hwstates[4], nullptr);
82 ASSERT_NE(nullptr, gs);
83 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
84 EXPECT_LT(-1, gs->details.wheel.dx);
85 EXPECT_GT(1, gs->details.wheel.dy);
86 EXPECT_EQ(240000, gs->start_time);
87 EXPECT_EQ(240000, gs->end_time);
88 }
89
TEST(MouseInterpreterTest,HighResolutionVerticalScrollTest)90 TEST(MouseInterpreterTest, HighResolutionVerticalScrollTest) {
91 HardwareProperties hwprops = make_hwprops_for_mouse(1, 1);
92 MouseInterpreter mi(nullptr, nullptr);
93 TestInterpreterWrapper wrapper(&mi, &hwprops);
94 Gesture* gs;
95
96 HardwareState hwstates[] = {
97 { 200000, 0, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
98 { 210000, 0, 0, 0, nullptr, 0, 0, 0, -15, 0, 0.0 },
99 { 220000, 0, 0, 0, nullptr, 0, 0, -1, -15, 0, 0.0 },
100 { 230000, 0, 0, 0, nullptr, 0, 0, 0,-120, 0, 0.0 },
101 { 240000, 0, 0, 0, nullptr, 0, 0, -1, 0, 0, 0.0 },
102 };
103
104 mi.output_mouse_wheel_gestures_.val_ = true;
105 mi.hi_res_scrolling_.val_ = 1;
106 mi.scroll_velocity_buffer_size_.val_ = 1;
107
108 gs = wrapper.SyncInterpret(hwstates[0], nullptr);
109 EXPECT_EQ(nullptr, gs);
110
111 gs = wrapper.SyncInterpret(hwstates[1], nullptr);
112 ASSERT_NE(nullptr, gs);
113 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
114 EXPECT_EQ(0, gs->details.wheel.dx);
115 float offset_of_8th_notch_scroll = gs->details.wheel.dy;
116 EXPECT_LT(1, offset_of_8th_notch_scroll);
117
118 gs = wrapper.SyncInterpret(hwstates[2], nullptr);
119 ASSERT_NE(nullptr, gs);
120 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
121 EXPECT_EQ(0, gs->details.wheel.dx);
122 // Having a low-res scroll event as well as the high-resolution one shouldn't
123 // change the output value.
124 EXPECT_NEAR(offset_of_8th_notch_scroll, gs->details.wheel.dy, 0.1);
125
126 gs = wrapper.SyncInterpret(hwstates[3], nullptr);
127 ASSERT_NE(nullptr, gs);
128 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
129 EXPECT_EQ(0, gs->details.wheel.dx);
130 float offset_of_high_res_scroll = gs->details.wheel.dy;
131
132 mi.hi_res_scrolling_.val_ = 0;
133
134 gs = wrapper.SyncInterpret(hwstates[4], nullptr);
135 ASSERT_NE(nullptr, gs);
136 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
137 EXPECT_EQ(0, gs->details.wheel.dx);
138 // A high-res scroll should yield the same offset as a low-res one with
139 // proper unit conversion.
140 EXPECT_NEAR(offset_of_high_res_scroll, gs->details.wheel.dy, 0.1);
141 }
142
TEST(MouseInterpreterTest,ScrollAccelerationOnAndOffTest)143 TEST(MouseInterpreterTest, ScrollAccelerationOnAndOffTest) {
144 HardwareProperties hwprops = make_hwprops_for_mouse(1, 1);
145 MouseInterpreter mi(nullptr, nullptr);
146 TestInterpreterWrapper wrapper(&mi, &hwprops);
147 Gesture* gs;
148
149 HardwareState hwstates[] = {
150 { 200000, 0, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
151 { 210000, 0, 0, 0, nullptr, 0, 0, 5, 0, 0, 0.0 },
152 { 220000, 0, 0, 0, nullptr, 0, 0, 5, 0, 0, 0.0 },
153 { 230000, 0, 0, 0, nullptr, 0, 0, 10, 0, 0, 0.0 },
154 { 240000, 0, 0, 0, nullptr, 0, 0, 10, 0, 0, 0.0 },
155 };
156
157 // Scroll acceleration is on.
158 mi.scroll_acceleration_.val_ = true;
159 mi.output_mouse_wheel_gestures_.val_ = true;
160 mi.hi_res_scrolling_.val_ = false;
161 mi.scroll_velocity_buffer_size_.val_ = 1;
162
163 gs = wrapper.SyncInterpret(hwstates[0], nullptr);
164 EXPECT_EQ(nullptr, gs);
165
166 gs = wrapper.SyncInterpret(hwstates[1], nullptr);
167 ASSERT_NE(nullptr, gs);
168 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
169 EXPECT_NE(0, gs->details.scroll.dy);
170
171 float offset_when_acceleration_on = gs->details.scroll.dy;
172
173 gs = wrapper.SyncInterpret(hwstates[2], nullptr);
174 ASSERT_NE(nullptr, gs);
175 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
176 EXPECT_NE(0, gs->details.scroll.dy);
177 // When acceleration is on, the offset is related to scroll speed. Though
178 // the wheel displacement are both 5, since the scroll speeds are different,
179 // the offset are different.
180 EXPECT_NE(offset_when_acceleration_on, gs->details.scroll.dy);
181
182 // Turn scroll acceleration off.
183 mi.scroll_acceleration_.val_ = false;
184
185 gs = wrapper.SyncInterpret(hwstates[3], nullptr);
186 ASSERT_NE(nullptr, gs);
187 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
188 EXPECT_NE(0, gs->details.scroll.dy);
189
190 float offset_when_acceleration_off = gs->details.scroll.dy;
191
192 gs = wrapper.SyncInterpret(hwstates[4], nullptr);
193 ASSERT_NE(nullptr, gs);
194 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
195 EXPECT_NE(0, gs->details.scroll.dy);
196 // When acceleration is off, the offset is not related to scroll speed.
197 // Same wheel displacement yields to same offset.
198 EXPECT_EQ(offset_when_acceleration_off, gs->details.scroll.dy);
199 }
200
TEST(MouseInterpreterTest,JankyScrollTest)201 TEST(MouseInterpreterTest, JankyScrollTest) {
202 HardwareProperties hwprops = make_hwprops_for_mouse(1, 0);
203 MouseInterpreter mi(nullptr, nullptr);
204 TestInterpreterWrapper wrapper(&mi, &hwprops);
205 Gesture* gs;
206
207 // Because we do not allow time deltas less than 8ms when calculating scroll
208 // acceleration, the last two scroll events should give the same dy
209 // (timestamp is in units of seconds)
210 HardwareState hwstates[] = {
211 { 200000, 0, 0, 0, nullptr, 0, 0, -1, 0, 0, 0.0 },
212 { 200000.008, 0, 0, 0, nullptr, 0, 0, -1, 0, 0, 0.0 },
213 { 200000.0085, 0, 0, 0, nullptr, 0, 0, -1, 0, 0, 0.0 },
214 };
215
216 mi.output_mouse_wheel_gestures_.val_ = true;
217 mi.scroll_velocity_buffer_size_.val_ = 1;
218
219 gs = wrapper.SyncInterpret(hwstates[0], nullptr);
220 ASSERT_NE(nullptr, gs);
221 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
222 EXPECT_EQ(0, gs->details.wheel.dx);
223 // Ignore the dy from the first scroll event, as the gesture interpreter
224 // hardcodes that time delta to 1 second, making it invalid for this test.
225
226 gs = wrapper.SyncInterpret(hwstates[1], nullptr);
227 ASSERT_NE(nullptr, gs);
228 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
229 EXPECT_EQ(0, gs->details.wheel.dx);
230 float scroll_offset = gs->details.wheel.dy;
231
232 gs = wrapper.SyncInterpret(hwstates[2], nullptr);
233 ASSERT_NE(nullptr, gs);
234 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
235 EXPECT_EQ(0, gs->details.wheel.dx);
236
237 EXPECT_NEAR(scroll_offset, gs->details.wheel.dy, 0.1);
238 }
239
TEST(MouseInterpreterTest,WheelTickReportingHighResTest)240 TEST(MouseInterpreterTest, WheelTickReportingHighResTest) {
241 HardwareProperties hwprops = make_hwprops_for_mouse(1, 1);
242 MouseInterpreter mi(nullptr, nullptr);
243 TestInterpreterWrapper wrapper(&mi, &hwprops);
244 Gesture* gs;
245
246 HardwareState hwstates[] = {
247 { 200000, 0, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
248 { 210000, 0, 0, 0, nullptr, 0, 0, 0, -30, 0, 0.0 },
249 };
250
251 mi.output_mouse_wheel_gestures_.val_ = true;
252 mi.hi_res_scrolling_.val_ = true;
253
254 gs = wrapper.SyncInterpret(hwstates[0], nullptr);
255 EXPECT_EQ(nullptr, gs);
256
257 gs = wrapper.SyncInterpret(hwstates[1], nullptr);
258 ASSERT_NE(nullptr, gs);
259 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
260 EXPECT_EQ( 0, gs->details.wheel.tick_120ths_dx);
261 EXPECT_EQ(30, gs->details.wheel.tick_120ths_dy);
262 }
263
TEST(MouseInterpreterTest,WheelTickReportingLowResTest)264 TEST(MouseInterpreterTest, WheelTickReportingLowResTest) {
265 HardwareProperties hwprops = make_hwprops_for_mouse(1, 0);
266 MouseInterpreter mi(nullptr, nullptr);
267 TestInterpreterWrapper wrapper(&mi, &hwprops);
268 Gesture* gs;
269
270 HardwareState hwstates[] = {
271 { 200000, 0, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
272 { 210000, 0, 0, 0, nullptr, 0, 0, 1, 0, 0, 0.0 },
273 { 210000, 0, 0, 0, nullptr, 0, 0, 0, 0, 1, 0.0 },
274 };
275
276 mi.output_mouse_wheel_gestures_.val_ = true;
277 mi.hi_res_scrolling_.val_ = false;
278
279 gs = wrapper.SyncInterpret(hwstates[0], nullptr);
280 EXPECT_EQ(nullptr, gs);
281
282 gs = wrapper.SyncInterpret(hwstates[1], nullptr);
283 ASSERT_NE(nullptr, gs);
284 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
285 EXPECT_EQ( 0, gs->details.wheel.tick_120ths_dx);
286 EXPECT_EQ(-120, gs->details.wheel.tick_120ths_dy);
287
288 gs = wrapper.SyncInterpret(hwstates[2], nullptr);
289 ASSERT_NE(nullptr, gs);
290 EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
291 EXPECT_EQ(120, gs->details.wheel.tick_120ths_dx);
292 EXPECT_EQ( 0, gs->details.wheel.tick_120ths_dy);
293 }
294
TEST(MouseInterpreterTest,EmulateScrollWheelTest)295 TEST(MouseInterpreterTest, EmulateScrollWheelTest) {
296 HardwareProperties hwprops = make_hwprops_for_mouse(0, 0);
297 MouseInterpreter mi(nullptr, nullptr);
298 TestInterpreterWrapper wrapper(&mi, &hwprops);
299 Gesture* gs;
300
301 HardwareState hwstates[] = {
302 { 200000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
303 { 210000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 9, -7, 0, 0, 0, 0.0 },
304 { 220000, GESTURES_BUTTON_LEFT, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
305 { 230000, GESTURES_BUTTON_LEFT + GESTURES_BUTTON_RIGHT, 0, 0, nullptr,
306 0, 0, 0, 0, 0, 0.0 },
307 { 240000, GESTURES_BUTTON_LEFT + GESTURES_BUTTON_RIGHT, 0, 0, nullptr,
308 2, 2, 0, 0, 0, 0.0 },
309 { 250000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
310 { 260000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 9, -7, 0, 0, 0, 0.0 },
311 { 270000, GESTURES_BUTTON_MIDDLE, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
312 { 280000, GESTURES_BUTTON_MIDDLE, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
313 { 290000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 0, 0, -3, -360, 4, 0.0 },
314 };
315
316 mi.output_mouse_wheel_gestures_.val_ = true;
317
318 gs = wrapper.SyncInterpret(hwstates[0], nullptr);
319 EXPECT_EQ(nullptr, gs);
320
321 gs = wrapper.SyncInterpret(hwstates[1], nullptr);
322 ASSERT_NE(nullptr, gs);
323 EXPECT_EQ(kGestureTypeMove, gs->type);
324 EXPECT_EQ(9, gs->details.move.dx);
325 EXPECT_EQ(-7, gs->details.move.dy);
326 EXPECT_EQ(200000, gs->start_time);
327 EXPECT_EQ(210000, gs->end_time);
328
329 gs = wrapper.SyncInterpret(hwstates[2], nullptr);
330 ASSERT_NE(nullptr, gs);
331 EXPECT_EQ(kGestureTypeButtonsChange, gs->type);
332 EXPECT_EQ(1, gs->details.buttons.down);
333 EXPECT_EQ(0, gs->details.buttons.up);
334 EXPECT_EQ(210000, gs->start_time);
335 EXPECT_EQ(220000, gs->end_time);
336
337 gs = wrapper.SyncInterpret(hwstates[3], nullptr);
338 ASSERT_EQ(nullptr, gs);
339
340 // Temporarily adjust the threshold to force wheel_emulation_active_
341 auto thresh = mi.scroll_wheel_emulation_thresh_.val_;
342 mi.scroll_wheel_emulation_thresh_.val_ = 0.1;
343 EXPECT_FALSE(mi.wheel_emulation_active_);
344 gs = wrapper.SyncInterpret(hwstates[4], nullptr);
345 EXPECT_TRUE(mi.wheel_emulation_active_);
346 ASSERT_NE(nullptr, gs);
347 EXPECT_EQ(kGestureTypeScroll, gs->type);
348 EXPECT_EQ(200, gs->details.scroll.dx);
349 EXPECT_EQ(200, gs->details.scroll.dy);
350 EXPECT_EQ(240000, gs->start_time);
351 EXPECT_EQ(240000, gs->end_time);
352 mi.scroll_wheel_emulation_thresh_.val_ = thresh;
353
354 gs = wrapper.SyncInterpret(hwstates[5], nullptr);
355 ASSERT_NE(nullptr, gs);
356 EXPECT_EQ(kGestureTypeButtonsChange, gs->type);
357 EXPECT_EQ(0, gs->details.buttons.down);
358 EXPECT_EQ(5, gs->details.buttons.up);
359 EXPECT_EQ(240000, gs->start_time);
360 EXPECT_EQ(250000, gs->end_time);
361
362 gs = wrapper.SyncInterpret(hwstates[6], nullptr);
363 ASSERT_NE(nullptr, gs);
364 EXPECT_EQ(kGestureTypeMove, gs->type);
365 EXPECT_EQ(9, gs->details.move.dx);
366 EXPECT_EQ(-7, gs->details.move.dy);
367 EXPECT_EQ(250000, gs->start_time);
368 EXPECT_EQ(260000, gs->end_time);
369
370 gs = wrapper.SyncInterpret(hwstates[7], nullptr);
371 ASSERT_EQ(nullptr, gs);
372
373 gs = wrapper.SyncInterpret(hwstates[8], nullptr);
374 ASSERT_EQ(nullptr, gs);
375
376 gs = wrapper.SyncInterpret(hwstates[9], nullptr);
377 ASSERT_NE(nullptr, gs);
378 EXPECT_EQ(kGestureTypeButtonsChange, gs->type);
379 EXPECT_EQ(0, gs->details.buttons.down);
380 EXPECT_EQ(2, gs->details.buttons.up);
381 EXPECT_EQ(280000, gs->start_time);
382 EXPECT_EQ(290000, gs->end_time);
383 }
384
385 } // namespace gestures
386