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,
81 LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS,
82 LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
83 6);
84 litest_button_scroll(dev, BTN_MIDDLE, 1, -7);
85 litest_assert_scroll(li,
86 LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS,
87 LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
88 -7);
89 litest_button_scroll(dev, BTN_MIDDLE, 8, 1);
90 litest_assert_scroll(li,
91 LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS,
92 LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
93 8);
94 litest_button_scroll(dev, BTN_MIDDLE, -9, 1);
95 litest_assert_scroll(li,
96 LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS,
97 LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
98 -9);
99
100 /* scroll smaller than the threshold should not generate axis events */
101 litest_button_scroll(dev, BTN_MIDDLE, 1, 1);
102
103 litest_button_scroll(dev, BTN_MIDDLE, 0, 0);
104 litest_assert_button_event(li, BTN_MIDDLE,
105 LIBINPUT_BUTTON_STATE_PRESSED);
106 litest_assert_button_event(li,
107 BTN_MIDDLE,
108 LIBINPUT_BUTTON_STATE_RELEASED);
109
110 litest_assert_empty_queue(li);
111 }
112 END_TEST
113
START_TEST(trackpoint_middlebutton_noscroll)114 START_TEST(trackpoint_middlebutton_noscroll)
115 {
116 struct litest_device *dev = litest_current_device();
117 struct libinput *li = dev->libinput;
118 struct libinput_event *event;
119
120 /* Disable middle button scrolling */
121 libinput_device_config_scroll_set_method(dev->libinput_device,
122 LIBINPUT_CONFIG_SCROLL_NO_SCROLL);
123
124 litest_drain_events(li);
125
126 /* A long middle button click + motion should get reported normally now */
127 litest_button_scroll(dev, BTN_MIDDLE, 0, 10);
128
129 litest_assert_button_event(li, BTN_MIDDLE, 1);
130
131 event = libinput_get_event(li);
132 ck_assert_notnull(event);
133 ck_assert_int_eq(libinput_event_get_type(event), LIBINPUT_EVENT_POINTER_MOTION);
134 libinput_event_destroy(event);
135
136 litest_assert_button_event(li, BTN_MIDDLE, 0);
137
138 litest_assert_empty_queue(li);
139
140 /* Restore default scroll behavior */
141 libinput_device_config_scroll_set_method(dev->libinput_device,
142 libinput_device_config_scroll_get_default_method(
143 dev->libinput_device));
144 }
145 END_TEST
146
START_TEST(trackpoint_scroll_source)147 START_TEST(trackpoint_scroll_source)
148 {
149 struct litest_device *dev = litest_current_device();
150 struct libinput *li = dev->libinput;
151 struct libinput_event *event;
152 struct libinput_event_pointer *ptrev;
153
154 litest_drain_events(li);
155
156 litest_button_scroll(dev, BTN_MIDDLE, 0, 6);
157 litest_wait_for_event_of_type(li, LIBINPUT_EVENT_POINTER_AXIS, -1);
158
159 while ((event = libinput_get_event(li))) {
160 ptrev = libinput_event_get_pointer_event(event);
161
162 ck_assert_int_eq(litest_event_pointer_get_axis_source(ptrev),
163 LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS);
164
165 libinput_event_destroy(event);
166 }
167 }
168 END_TEST
169
START_TEST(trackpoint_topsoftbuttons_left_handed_trackpoint)170 START_TEST(trackpoint_topsoftbuttons_left_handed_trackpoint)
171 {
172 struct litest_device *touchpad = litest_current_device();
173 struct litest_device *trackpoint;
174 struct libinput *li = touchpad->libinput;
175 enum libinput_config_status status;
176 struct libinput_event *event;
177 struct libinput_device *device;
178
179 litest_disable_hold_gestures(touchpad->libinput_device);
180
181 trackpoint = litest_add_device(li, LITEST_TRACKPOINT);
182 litest_drain_events(li);
183 /* touchpad right-handed, trackpoint left-handed */
184 status = libinput_device_config_left_handed_set(
185 trackpoint->libinput_device, 1);
186 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
187
188 litest_touch_down(touchpad, 0, 5, 5);
189 libinput_dispatch(li);
190 litest_button_click_debounced(touchpad, li, BTN_LEFT, true);
191 libinput_dispatch(li);
192
193 event = libinput_get_event(li);
194 litest_is_button_event(event,
195 BTN_RIGHT,
196 LIBINPUT_BUTTON_STATE_PRESSED);
197 device = libinput_event_get_device(event);
198 ck_assert(device == trackpoint->libinput_device);
199 libinput_event_destroy(event);
200
201 litest_button_click_debounced(touchpad, li, BTN_LEFT, false);
202 libinput_dispatch(li);
203 event = libinput_get_event(li);
204 litest_is_button_event(event,
205 BTN_RIGHT,
206 LIBINPUT_BUTTON_STATE_RELEASED);
207 device = libinput_event_get_device(event);
208 ck_assert(device == trackpoint->libinput_device);
209 libinput_event_destroy(event);
210
211 litest_delete_device(trackpoint);
212 }
213 END_TEST
214
START_TEST(trackpoint_topsoftbuttons_left_handed_touchpad)215 START_TEST(trackpoint_topsoftbuttons_left_handed_touchpad)
216 {
217 struct litest_device *touchpad = litest_current_device();
218 struct litest_device *trackpoint;
219 struct libinput *li = touchpad->libinput;
220 enum libinput_config_status status;
221 struct libinput_event *event;
222 struct libinput_device *device;
223
224 litest_disable_hold_gestures(touchpad->libinput_device);
225
226 trackpoint = litest_add_device(li, LITEST_TRACKPOINT);
227 litest_drain_events(li);
228 /* touchpad left-handed, trackpoint right-handed */
229 status = libinput_device_config_left_handed_set(
230 touchpad->libinput_device, 1);
231 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
232
233 litest_touch_down(touchpad, 0, 5, 5);
234 libinput_dispatch(li);
235 litest_button_click_debounced(touchpad, li, BTN_LEFT, true);
236 libinput_dispatch(li);
237
238 event = libinput_get_event(li);
239 litest_is_button_event(event, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
240 device = libinput_event_get_device(event);
241 ck_assert(device == trackpoint->libinput_device);
242 libinput_event_destroy(event);
243
244 litest_button_click_debounced(touchpad, li, BTN_LEFT, false);
245 libinput_dispatch(li);
246 event = libinput_get_event(li);
247 litest_is_button_event(event,
248 BTN_LEFT,
249 LIBINPUT_BUTTON_STATE_RELEASED);
250 device = libinput_event_get_device(event);
251 ck_assert(device == trackpoint->libinput_device);
252 libinput_event_destroy(event);
253
254 litest_delete_device(trackpoint);
255 }
256 END_TEST
257
START_TEST(trackpoint_topsoftbuttons_left_handed_both)258 START_TEST(trackpoint_topsoftbuttons_left_handed_both)
259 {
260 struct litest_device *touchpad = litest_current_device();
261 struct litest_device *trackpoint;
262 struct libinput *li = touchpad->libinput;
263 enum libinput_config_status status;
264 struct libinput_event *event;
265 struct libinput_device *device;
266
267 litest_disable_hold_gestures(touchpad->libinput_device);
268
269 trackpoint = litest_add_device(li, LITEST_TRACKPOINT);
270 litest_drain_events(li);
271 /* touchpad left-handed, trackpoint left-handed */
272 status = libinput_device_config_left_handed_set(
273 touchpad->libinput_device, 1);
274 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
275 status = libinput_device_config_left_handed_set(
276 trackpoint->libinput_device, 1);
277 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
278
279 litest_touch_down(touchpad, 0, 5, 5);
280 libinput_dispatch(li);
281 litest_button_click_debounced(touchpad, li, BTN_LEFT, true);
282 libinput_dispatch(li);
283
284 event = libinput_get_event(li);
285 litest_is_button_event(event,
286 BTN_RIGHT,
287 LIBINPUT_BUTTON_STATE_PRESSED);
288 device = libinput_event_get_device(event);
289 ck_assert(device == trackpoint->libinput_device);
290 libinput_event_destroy(event);
291
292 litest_button_click_debounced(touchpad, li, BTN_LEFT, false);
293 libinput_dispatch(li);
294 event = libinput_get_event(li);
295 litest_is_button_event(event,
296 BTN_RIGHT,
297 LIBINPUT_BUTTON_STATE_RELEASED);
298 device = libinput_event_get_device(event);
299 ck_assert(device == trackpoint->libinput_device);
300 libinput_event_destroy(event);
301
302 litest_delete_device(trackpoint);
303 }
304 END_TEST
305
START_TEST(trackpoint_palmdetect)306 START_TEST(trackpoint_palmdetect)
307 {
308 struct litest_device *trackpoint = litest_current_device();
309 struct litest_device *touchpad;
310 struct libinput *li = trackpoint->libinput;
311 int i;
312
313 touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C);
314 litest_disable_hold_gestures(touchpad->libinput_device);
315 litest_drain_events(li);
316
317 for (i = 0; i < 10; i++) {
318 litest_event(trackpoint, EV_REL, REL_X, 1);
319 litest_event(trackpoint, EV_REL, REL_Y, 1);
320 litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
321 libinput_dispatch(li);
322 }
323 litest_drain_events(li);
324
325 litest_touch_down(touchpad, 0, 30, 30);
326 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10);
327 litest_touch_up(touchpad, 0);
328 litest_assert_empty_queue(li);
329
330 litest_timeout_trackpoint();
331 libinput_dispatch(li);
332
333 litest_touch_down(touchpad, 0, 30, 30);
334 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10);
335 litest_touch_up(touchpad, 0);
336 litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
337
338 litest_delete_device(touchpad);
339 }
340 END_TEST
341
START_TEST(trackpoint_palmdetect_resume_touch)342 START_TEST(trackpoint_palmdetect_resume_touch)
343 {
344 struct litest_device *trackpoint = litest_current_device();
345 struct litest_device *touchpad;
346 struct libinput *li = trackpoint->libinput;
347 int i;
348
349 touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C);
350 litest_disable_hold_gestures(touchpad->libinput_device);
351 litest_drain_events(li);
352
353 for (i = 0; i < 10; i++) {
354 litest_event(trackpoint, EV_REL, REL_X, 1);
355 litest_event(trackpoint, EV_REL, REL_Y, 1);
356 litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
357 libinput_dispatch(li);
358 }
359 litest_drain_events(li);
360
361 litest_touch_down(touchpad, 0, 30, 30);
362 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10);
363 litest_assert_empty_queue(li);
364
365 litest_timeout_trackpoint();
366 libinput_dispatch(li);
367
368 /* touch started after last tp event, expect resume */
369 litest_touch_move_to(touchpad, 0, 80, 80, 30, 30, 10);
370 litest_touch_up(touchpad, 0);
371 litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
372
373 litest_delete_device(touchpad);
374 }
375 END_TEST
376
START_TEST(trackpoint_palmdetect_require_min_events)377 START_TEST(trackpoint_palmdetect_require_min_events)
378 {
379 struct litest_device *trackpoint = litest_current_device();
380 struct litest_device *touchpad;
381 struct libinput *li = trackpoint->libinput;
382
383 touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C);
384 litest_disable_hold_gestures(touchpad->libinput_device);
385 litest_drain_events(li);
386
387 /* A single event does not trigger palm detection */
388 litest_event(trackpoint, EV_REL, REL_X, 1);
389 litest_event(trackpoint, EV_REL, REL_Y, 1);
390 litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
391 libinput_dispatch(li);
392 litest_drain_events(li);
393
394 litest_touch_down(touchpad, 0, 30, 30);
395 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10);
396 litest_touch_up(touchpad, 0);
397 litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
398
399 litest_delete_device(touchpad);
400 }
401 END_TEST
402
START_TEST(trackpoint_palmdetect_require_min_events_timeout)403 START_TEST(trackpoint_palmdetect_require_min_events_timeout)
404 {
405 struct litest_device *trackpoint = litest_current_device();
406 struct litest_device *touchpad;
407 struct libinput *li = trackpoint->libinput;
408
409 touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C);
410 litest_disable_hold_gestures(touchpad->libinput_device);
411 litest_drain_events(li);
412
413 for (int i = 0; i < 10; i++) {
414 /* A single event does not trigger palm detection */
415 litest_event(trackpoint, EV_REL, REL_X, 1);
416 litest_event(trackpoint, EV_REL, REL_Y, 1);
417 litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
418 libinput_dispatch(li);
419 litest_drain_events(li);
420
421 litest_touch_down(touchpad, 0, 30, 30);
422 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10);
423 litest_touch_up(touchpad, 0);
424 litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
425
426 litest_timeout_trackpoint();
427 }
428
429 litest_delete_device(touchpad);
430 }
431 END_TEST
432
TEST_COLLECTION(trackpoint)433 TEST_COLLECTION(trackpoint)
434 {
435 litest_add(trackpoint_middlebutton, LITEST_POINTINGSTICK, LITEST_ANY);
436 litest_add(trackpoint_middlebutton_noscroll, LITEST_POINTINGSTICK, LITEST_ANY);
437 litest_add(trackpoint_scroll, LITEST_POINTINGSTICK, LITEST_ANY);
438 litest_add(trackpoint_scroll_source, LITEST_POINTINGSTICK, LITEST_ANY);
439 litest_add(trackpoint_topsoftbuttons_left_handed_trackpoint, LITEST_TOPBUTTONPAD, LITEST_ANY);
440 litest_add(trackpoint_topsoftbuttons_left_handed_touchpad, LITEST_TOPBUTTONPAD, LITEST_ANY);
441 litest_add(trackpoint_topsoftbuttons_left_handed_both, LITEST_TOPBUTTONPAD, LITEST_ANY);
442
443 litest_add(trackpoint_palmdetect, LITEST_POINTINGSTICK, LITEST_ANY);
444 litest_add(trackpoint_palmdetect_resume_touch, LITEST_POINTINGSTICK, LITEST_ANY);
445 litest_add(trackpoint_palmdetect_require_min_events, LITEST_POINTINGSTICK, LITEST_ANY);
446 litest_add(trackpoint_palmdetect_require_min_events_timeout, LITEST_POINTINGSTICK, LITEST_ANY);
447 }
448