1 /*
2 * Copyright © 2014 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <config.h>
25
26 #include <check.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <libinput.h>
30 #include <unistd.h>
31
32 #include "libinput-util.h"
33 #include "litest.h"
34
START_TEST(trackpoint_middlebutton)35 START_TEST(trackpoint_middlebutton)
36 {
37 struct litest_device *dev = litest_current_device();
38 struct libinput *li = dev->libinput;
39 struct libinput_event *event;
40 struct libinput_event_pointer *ptrev;
41 uint64_t ptime, rtime;
42
43 litest_drain_events(li);
44
45 /* A quick middle button click should get reported normally */
46 litest_button_click_debounced(dev, li, BTN_MIDDLE, 1);
47 msleep(2);
48 litest_button_click_debounced(dev, li, BTN_MIDDLE, 0);
49
50 litest_wait_for_event(li);
51
52 event = libinput_get_event(li);
53 ptrev = litest_is_button_event(event,
54 BTN_MIDDLE,
55 LIBINPUT_BUTTON_STATE_PRESSED);
56 ptime = libinput_event_pointer_get_time(ptrev);
57 libinput_event_destroy(event);
58
59 event = libinput_get_event(li);
60 ptrev = litest_is_button_event(event,
61 BTN_MIDDLE,
62 LIBINPUT_BUTTON_STATE_RELEASED);
63 rtime = libinput_event_pointer_get_time(ptrev);
64 libinput_event_destroy(event);
65
66 ck_assert_int_lt(ptime, rtime);
67
68 litest_assert_empty_queue(li);
69 }
70 END_TEST
71
START_TEST(trackpoint_scroll)72 START_TEST(trackpoint_scroll)
73 {
74 struct litest_device *dev = litest_current_device();
75 struct libinput *li = dev->libinput;
76
77 litest_drain_events(li);
78
79 litest_button_scroll(dev, BTN_MIDDLE, 1, 6);
80 litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 6);
81 litest_button_scroll(dev, BTN_MIDDLE, 1, -7);
82 litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -7);
83 litest_button_scroll(dev, BTN_MIDDLE, 8, 1);
84 litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 8);
85 litest_button_scroll(dev, BTN_MIDDLE, -9, 1);
86 litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -9);
87
88 /* scroll smaller than the threshold should not generate axis events */
89 litest_button_scroll(dev, BTN_MIDDLE, 1, 1);
90
91 litest_button_scroll(dev, BTN_MIDDLE, 0, 0);
92 litest_assert_button_event(li, BTN_MIDDLE,
93 LIBINPUT_BUTTON_STATE_PRESSED);
94 litest_assert_button_event(li,
95 BTN_MIDDLE,
96 LIBINPUT_BUTTON_STATE_RELEASED);
97
98 litest_assert_empty_queue(li);
99 }
100 END_TEST
101
START_TEST(trackpoint_middlebutton_noscroll)102 START_TEST(trackpoint_middlebutton_noscroll)
103 {
104 struct litest_device *dev = litest_current_device();
105 struct libinput *li = dev->libinput;
106 struct libinput_event *event;
107
108 /* Disable middle button scrolling */
109 libinput_device_config_scroll_set_method(dev->libinput_device,
110 LIBINPUT_CONFIG_SCROLL_NO_SCROLL);
111
112 litest_drain_events(li);
113
114 /* A long middle button click + motion should get reported normally now */
115 litest_button_scroll(dev, BTN_MIDDLE, 0, 10);
116
117 litest_assert_button_event(li, BTN_MIDDLE, 1);
118
119 event = libinput_get_event(li);
120 ck_assert_notnull(event);
121 ck_assert_int_eq(libinput_event_get_type(event), LIBINPUT_EVENT_POINTER_MOTION);
122 libinput_event_destroy(event);
123
124 litest_assert_button_event(li, BTN_MIDDLE, 0);
125
126 litest_assert_empty_queue(li);
127
128 /* Restore default scroll behavior */
129 libinput_device_config_scroll_set_method(dev->libinput_device,
130 libinput_device_config_scroll_get_default_method(
131 dev->libinput_device));
132 }
133 END_TEST
134
START_TEST(trackpoint_scroll_source)135 START_TEST(trackpoint_scroll_source)
136 {
137 struct litest_device *dev = litest_current_device();
138 struct libinput *li = dev->libinput;
139 struct libinput_event *event;
140 struct libinput_event_pointer *ptrev;
141
142 litest_drain_events(li);
143
144 litest_button_scroll(dev, BTN_MIDDLE, 0, 6);
145 litest_wait_for_event_of_type(li, LIBINPUT_EVENT_POINTER_AXIS, -1);
146
147 while ((event = libinput_get_event(li))) {
148 ptrev = libinput_event_get_pointer_event(event);
149
150 ck_assert_int_eq(libinput_event_pointer_get_axis_source(ptrev),
151 LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS);
152
153 libinput_event_destroy(event);
154 }
155 }
156 END_TEST
157
START_TEST(trackpoint_topsoftbuttons_left_handed_trackpoint)158 START_TEST(trackpoint_topsoftbuttons_left_handed_trackpoint)
159 {
160 struct litest_device *touchpad = litest_current_device();
161 struct litest_device *trackpoint;
162 struct libinput *li = touchpad->libinput;
163 enum libinput_config_status status;
164 struct libinput_event *event;
165 struct libinput_device *device;
166
167 trackpoint = litest_add_device(li, LITEST_TRACKPOINT);
168 litest_drain_events(li);
169 /* touchpad right-handed, trackpoint left-handed */
170 status = libinput_device_config_left_handed_set(
171 trackpoint->libinput_device, 1);
172 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
173
174 litest_touch_down(touchpad, 0, 5, 5);
175 libinput_dispatch(li);
176 litest_button_click_debounced(touchpad, li, BTN_LEFT, true);
177 libinput_dispatch(li);
178
179 event = libinput_get_event(li);
180 litest_is_button_event(event,
181 BTN_RIGHT,
182 LIBINPUT_BUTTON_STATE_PRESSED);
183 device = libinput_event_get_device(event);
184 ck_assert(device == trackpoint->libinput_device);
185 libinput_event_destroy(event);
186
187 litest_button_click_debounced(touchpad, li, BTN_LEFT, false);
188 libinput_dispatch(li);
189 event = libinput_get_event(li);
190 litest_is_button_event(event,
191 BTN_RIGHT,
192 LIBINPUT_BUTTON_STATE_RELEASED);
193 device = libinput_event_get_device(event);
194 ck_assert(device == trackpoint->libinput_device);
195 libinput_event_destroy(event);
196
197 litest_delete_device(trackpoint);
198 }
199 END_TEST
200
START_TEST(trackpoint_topsoftbuttons_left_handed_touchpad)201 START_TEST(trackpoint_topsoftbuttons_left_handed_touchpad)
202 {
203 struct litest_device *touchpad = litest_current_device();
204 struct litest_device *trackpoint;
205 struct libinput *li = touchpad->libinput;
206 enum libinput_config_status status;
207 struct libinput_event *event;
208 struct libinput_device *device;
209
210 trackpoint = litest_add_device(li, LITEST_TRACKPOINT);
211 litest_drain_events(li);
212 /* touchpad left-handed, trackpoint right-handed */
213 status = libinput_device_config_left_handed_set(
214 touchpad->libinput_device, 1);
215 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
216
217 litest_touch_down(touchpad, 0, 5, 5);
218 libinput_dispatch(li);
219 litest_button_click_debounced(touchpad, li, BTN_LEFT, true);
220 libinput_dispatch(li);
221
222 event = libinput_get_event(li);
223 litest_is_button_event(event, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
224 device = libinput_event_get_device(event);
225 ck_assert(device == trackpoint->libinput_device);
226 libinput_event_destroy(event);
227
228 litest_button_click_debounced(touchpad, li, BTN_LEFT, false);
229 libinput_dispatch(li);
230 event = libinput_get_event(li);
231 litest_is_button_event(event,
232 BTN_LEFT,
233 LIBINPUT_BUTTON_STATE_RELEASED);
234 device = libinput_event_get_device(event);
235 ck_assert(device == trackpoint->libinput_device);
236 libinput_event_destroy(event);
237
238 litest_delete_device(trackpoint);
239 }
240 END_TEST
241
START_TEST(trackpoint_topsoftbuttons_left_handed_both)242 START_TEST(trackpoint_topsoftbuttons_left_handed_both)
243 {
244 struct litest_device *touchpad = litest_current_device();
245 struct litest_device *trackpoint;
246 struct libinput *li = touchpad->libinput;
247 enum libinput_config_status status;
248 struct libinput_event *event;
249 struct libinput_device *device;
250
251 trackpoint = litest_add_device(li, LITEST_TRACKPOINT);
252 litest_drain_events(li);
253 /* touchpad left-handed, trackpoint left-handed */
254 status = libinput_device_config_left_handed_set(
255 touchpad->libinput_device, 1);
256 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
257 status = libinput_device_config_left_handed_set(
258 trackpoint->libinput_device, 1);
259 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
260
261 litest_touch_down(touchpad, 0, 5, 5);
262 libinput_dispatch(li);
263 litest_button_click_debounced(touchpad, li, BTN_LEFT, true);
264 libinput_dispatch(li);
265
266 event = libinput_get_event(li);
267 litest_is_button_event(event,
268 BTN_RIGHT,
269 LIBINPUT_BUTTON_STATE_PRESSED);
270 device = libinput_event_get_device(event);
271 ck_assert(device == trackpoint->libinput_device);
272 libinput_event_destroy(event);
273
274 litest_button_click_debounced(touchpad, li, BTN_LEFT, false);
275 libinput_dispatch(li);
276 event = libinput_get_event(li);
277 litest_is_button_event(event,
278 BTN_RIGHT,
279 LIBINPUT_BUTTON_STATE_RELEASED);
280 device = libinput_event_get_device(event);
281 ck_assert(device == trackpoint->libinput_device);
282 libinput_event_destroy(event);
283
284 litest_delete_device(trackpoint);
285 }
286 END_TEST
287
START_TEST(trackpoint_palmdetect)288 START_TEST(trackpoint_palmdetect)
289 {
290 struct litest_device *trackpoint = litest_current_device();
291 struct litest_device *touchpad;
292 struct libinput *li = trackpoint->libinput;
293 int i;
294
295 touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C);
296 litest_drain_events(li);
297
298 for (i = 0; i < 10; i++) {
299 litest_event(trackpoint, EV_REL, REL_X, 1);
300 litest_event(trackpoint, EV_REL, REL_Y, 1);
301 litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
302 libinput_dispatch(li);
303 }
304 litest_drain_events(li);
305
306 litest_touch_down(touchpad, 0, 30, 30);
307 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10);
308 litest_touch_up(touchpad, 0);
309 litest_assert_empty_queue(li);
310
311 litest_timeout_trackpoint();
312 libinput_dispatch(li);
313
314 litest_touch_down(touchpad, 0, 30, 30);
315 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10);
316 litest_touch_up(touchpad, 0);
317 litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
318
319 litest_delete_device(touchpad);
320 }
321 END_TEST
322
START_TEST(trackpoint_palmdetect_resume_touch)323 START_TEST(trackpoint_palmdetect_resume_touch)
324 {
325 struct litest_device *trackpoint = litest_current_device();
326 struct litest_device *touchpad;
327 struct libinput *li = trackpoint->libinput;
328 int i;
329
330 touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C);
331 litest_drain_events(li);
332
333 for (i = 0; i < 10; i++) {
334 litest_event(trackpoint, EV_REL, REL_X, 1);
335 litest_event(trackpoint, EV_REL, REL_Y, 1);
336 litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
337 libinput_dispatch(li);
338 }
339 litest_drain_events(li);
340
341 litest_touch_down(touchpad, 0, 30, 30);
342 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10);
343 litest_assert_empty_queue(li);
344
345 litest_timeout_trackpoint();
346 libinput_dispatch(li);
347
348 /* touch started after last tp event, expect resume */
349 litest_touch_move_to(touchpad, 0, 80, 80, 30, 30, 10);
350 litest_touch_up(touchpad, 0);
351 litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
352
353 litest_delete_device(touchpad);
354 }
355 END_TEST
356
START_TEST(trackpoint_palmdetect_require_min_events)357 START_TEST(trackpoint_palmdetect_require_min_events)
358 {
359 struct litest_device *trackpoint = litest_current_device();
360 struct litest_device *touchpad;
361 struct libinput *li = trackpoint->libinput;
362
363 touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C);
364 litest_drain_events(li);
365
366 /* A single event does not trigger palm detection */
367 litest_event(trackpoint, EV_REL, REL_X, 1);
368 litest_event(trackpoint, EV_REL, REL_Y, 1);
369 litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
370 libinput_dispatch(li);
371 litest_drain_events(li);
372
373 litest_touch_down(touchpad, 0, 30, 30);
374 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10);
375 litest_touch_up(touchpad, 0);
376 litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
377
378 litest_delete_device(touchpad);
379 }
380 END_TEST
381
START_TEST(trackpoint_palmdetect_require_min_events_timeout)382 START_TEST(trackpoint_palmdetect_require_min_events_timeout)
383 {
384 struct litest_device *trackpoint = litest_current_device();
385 struct litest_device *touchpad;
386 struct libinput *li = trackpoint->libinput;
387
388 touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C);
389 litest_drain_events(li);
390
391 for (int i = 0; i < 10; i++) {
392 /* A single event does not trigger palm detection */
393 litest_event(trackpoint, EV_REL, REL_X, 1);
394 litest_event(trackpoint, EV_REL, REL_Y, 1);
395 litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
396 libinput_dispatch(li);
397 litest_drain_events(li);
398
399 litest_touch_down(touchpad, 0, 30, 30);
400 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10);
401 litest_touch_up(touchpad, 0);
402 litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
403
404 litest_timeout_trackpoint();
405 }
406
407 litest_delete_device(touchpad);
408 }
409 END_TEST
410
TEST_COLLECTION(trackpoint)411 TEST_COLLECTION(trackpoint)
412 {
413 litest_add("trackpoint:middlebutton", trackpoint_middlebutton, LITEST_POINTINGSTICK, LITEST_ANY);
414 litest_add("trackpoint:middlebutton", trackpoint_middlebutton_noscroll, LITEST_POINTINGSTICK, LITEST_ANY);
415 litest_add("trackpoint:scroll", trackpoint_scroll, LITEST_POINTINGSTICK, LITEST_ANY);
416 litest_add("trackpoint:scroll", trackpoint_scroll_source, LITEST_POINTINGSTICK, LITEST_ANY);
417 litest_add("trackpoint:left-handed", trackpoint_topsoftbuttons_left_handed_trackpoint, LITEST_TOPBUTTONPAD, LITEST_ANY);
418 litest_add("trackpoint:left-handed", trackpoint_topsoftbuttons_left_handed_touchpad, LITEST_TOPBUTTONPAD, LITEST_ANY);
419 litest_add("trackpoint:left-handed", trackpoint_topsoftbuttons_left_handed_both, LITEST_TOPBUTTONPAD, LITEST_ANY);
420
421 litest_add("trackpoint:palmdetect", trackpoint_palmdetect, LITEST_POINTINGSTICK, LITEST_ANY);
422 litest_add("trackpoint:palmdetect", trackpoint_palmdetect_resume_touch, LITEST_POINTINGSTICK, LITEST_ANY);
423 litest_add("trackpoint:palmdetect", trackpoint_palmdetect_require_min_events, LITEST_POINTINGSTICK, LITEST_ANY);
424 litest_add("trackpoint:palmdetect", trackpoint_palmdetect_require_min_events_timeout, LITEST_POINTINGSTICK, LITEST_ANY);
425 }
426