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 35static inline bool 36has_disable_while_trackpointing(struct litest_device *device) 37{ 38 return libinput_device_config_dwtp_is_available(device->libinput_device); 39} 40 41START_TEST(trackpoint_middlebutton) 42{ 43 struct litest_device *dev = litest_current_device(); 44 struct libinput *li = dev->libinput; 45 struct libinput_event *event; 46 struct libinput_event_pointer *ptrev; 47 uint64_t ptime, rtime; 48 49 litest_drain_events(li); 50 51 /* A quick middle button click should get reported normally */ 52 litest_button_click_debounced(dev, li, BTN_MIDDLE, 1); 53 msleep(2); 54 litest_button_click_debounced(dev, li, BTN_MIDDLE, 0); 55 56 litest_wait_for_event(li); 57 58 event = libinput_get_event(li); 59 ptrev = litest_is_button_event(event, 60 BTN_MIDDLE, 61 LIBINPUT_BUTTON_STATE_PRESSED); 62 ptime = libinput_event_pointer_get_time(ptrev); 63 libinput_event_destroy(event); 64 65 event = libinput_get_event(li); 66 ptrev = litest_is_button_event(event, 67 BTN_MIDDLE, 68 LIBINPUT_BUTTON_STATE_RELEASED); 69 rtime = libinput_event_pointer_get_time(ptrev); 70 libinput_event_destroy(event); 71 72 ck_assert_int_lt(ptime, rtime); 73 74 litest_assert_empty_queue(li); 75} 76END_TEST 77 78START_TEST(trackpoint_scroll) 79{ 80 struct litest_device *dev = litest_current_device(); 81 struct libinput *li = dev->libinput; 82 83 litest_drain_events(li); 84 85 litest_button_scroll(dev, BTN_MIDDLE, 1, 6); 86 litest_assert_scroll(li, 87 LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, 88 LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 89 6); 90 litest_button_scroll(dev, BTN_MIDDLE, 1, -7); 91 litest_assert_scroll(li, 92 LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, 93 LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 94 -7); 95 litest_button_scroll(dev, BTN_MIDDLE, 8, 1); 96 litest_assert_scroll(li, 97 LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, 98 LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 99 8); 100 litest_button_scroll(dev, BTN_MIDDLE, -9, 1); 101 litest_assert_scroll(li, 102 LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, 103 LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 104 -9); 105 106 /* scroll smaller than the threshold should not generate axis events */ 107 litest_button_scroll(dev, BTN_MIDDLE, 1, 1); 108 109 litest_button_scroll(dev, BTN_MIDDLE, 0, 0); 110 litest_assert_button_event(li, BTN_MIDDLE, 111 LIBINPUT_BUTTON_STATE_PRESSED); 112 litest_assert_button_event(li, 113 BTN_MIDDLE, 114 LIBINPUT_BUTTON_STATE_RELEASED); 115 116 litest_assert_empty_queue(li); 117} 118END_TEST 119 120START_TEST(trackpoint_middlebutton_noscroll) 121{ 122 struct litest_device *dev = litest_current_device(); 123 struct libinput *li = dev->libinput; 124 struct libinput_event *event; 125 126 /* Disable middle button scrolling */ 127 libinput_device_config_scroll_set_method(dev->libinput_device, 128 LIBINPUT_CONFIG_SCROLL_NO_SCROLL); 129 130 litest_drain_events(li); 131 132 /* A long middle button click + motion should get reported normally now */ 133 litest_button_scroll(dev, BTN_MIDDLE, 0, 10); 134 135 litest_assert_button_event(li, BTN_MIDDLE, 1); 136 137 event = libinput_get_event(li); 138 ck_assert_notnull(event); 139 ck_assert_int_eq(libinput_event_get_type(event), LIBINPUT_EVENT_POINTER_MOTION); 140 libinput_event_destroy(event); 141 142 litest_assert_button_event(li, BTN_MIDDLE, 0); 143 144 litest_assert_empty_queue(li); 145 146 /* Restore default scroll behavior */ 147 libinput_device_config_scroll_set_method(dev->libinput_device, 148 libinput_device_config_scroll_get_default_method( 149 dev->libinput_device)); 150} 151END_TEST 152 153START_TEST(trackpoint_scroll_source) 154{ 155 struct litest_device *dev = litest_current_device(); 156 struct libinput *li = dev->libinput; 157 struct libinput_event *event; 158 struct libinput_event_pointer *ptrev; 159 160 litest_drain_events(li); 161 162 litest_button_scroll(dev, BTN_MIDDLE, 0, 6); 163 litest_wait_for_event_of_type(li, LIBINPUT_EVENT_POINTER_AXIS, -1); 164 165 while ((event = libinput_get_event(li))) { 166 ptrev = libinput_event_get_pointer_event(event); 167 168 ck_assert_int_eq(litest_event_pointer_get_axis_source(ptrev), 169 LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS); 170 171 libinput_event_destroy(event); 172 } 173} 174END_TEST 175 176START_TEST(trackpoint_topsoftbuttons_left_handed_trackpoint) 177{ 178 struct litest_device *touchpad = litest_current_device(); 179 struct litest_device *trackpoint; 180 struct libinput *li = touchpad->libinput; 181 enum libinput_config_status status; 182 struct libinput_event *event; 183 struct libinput_device *device; 184 185 litest_disable_hold_gestures(touchpad->libinput_device); 186 187 trackpoint = litest_add_device(li, LITEST_TRACKPOINT); 188 litest_drain_events(li); 189 /* touchpad right-handed, trackpoint left-handed */ 190 status = libinput_device_config_left_handed_set( 191 trackpoint->libinput_device, 1); 192 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); 193 194 litest_touch_down(touchpad, 0, 5, 5); 195 libinput_dispatch(li); 196 litest_button_click_debounced(touchpad, li, BTN_LEFT, true); 197 libinput_dispatch(li); 198 199 event = libinput_get_event(li); 200 litest_is_button_event(event, 201 BTN_RIGHT, 202 LIBINPUT_BUTTON_STATE_PRESSED); 203 device = libinput_event_get_device(event); 204 ck_assert(device == trackpoint->libinput_device); 205 libinput_event_destroy(event); 206 207 litest_button_click_debounced(touchpad, li, BTN_LEFT, false); 208 libinput_dispatch(li); 209 event = libinput_get_event(li); 210 litest_is_button_event(event, 211 BTN_RIGHT, 212 LIBINPUT_BUTTON_STATE_RELEASED); 213 device = libinput_event_get_device(event); 214 ck_assert(device == trackpoint->libinput_device); 215 libinput_event_destroy(event); 216 217 litest_delete_device(trackpoint); 218} 219END_TEST 220 221START_TEST(trackpoint_topsoftbuttons_left_handed_touchpad) 222{ 223 struct litest_device *touchpad = litest_current_device(); 224 struct litest_device *trackpoint; 225 struct libinput *li = touchpad->libinput; 226 enum libinput_config_status status; 227 struct libinput_event *event; 228 struct libinput_device *device; 229 230 litest_disable_hold_gestures(touchpad->libinput_device); 231 232 trackpoint = litest_add_device(li, LITEST_TRACKPOINT); 233 litest_drain_events(li); 234 /* touchpad left-handed, trackpoint right-handed */ 235 status = libinput_device_config_left_handed_set( 236 touchpad->libinput_device, 1); 237 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); 238 239 litest_touch_down(touchpad, 0, 5, 5); 240 libinput_dispatch(li); 241 litest_button_click_debounced(touchpad, li, BTN_LEFT, true); 242 libinput_dispatch(li); 243 244 event = libinput_get_event(li); 245 litest_is_button_event(event, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED); 246 device = libinput_event_get_device(event); 247 ck_assert(device == trackpoint->libinput_device); 248 libinput_event_destroy(event); 249 250 litest_button_click_debounced(touchpad, li, BTN_LEFT, false); 251 libinput_dispatch(li); 252 event = libinput_get_event(li); 253 litest_is_button_event(event, 254 BTN_LEFT, 255 LIBINPUT_BUTTON_STATE_RELEASED); 256 device = libinput_event_get_device(event); 257 ck_assert(device == trackpoint->libinput_device); 258 libinput_event_destroy(event); 259 260 litest_delete_device(trackpoint); 261} 262END_TEST 263 264START_TEST(trackpoint_topsoftbuttons_left_handed_both) 265{ 266 struct litest_device *touchpad = litest_current_device(); 267 struct litest_device *trackpoint; 268 struct libinput *li = touchpad->libinput; 269 enum libinput_config_status status; 270 struct libinput_event *event; 271 struct libinput_device *device; 272 273 litest_disable_hold_gestures(touchpad->libinput_device); 274 275 trackpoint = litest_add_device(li, LITEST_TRACKPOINT); 276 litest_drain_events(li); 277 /* touchpad left-handed, trackpoint left-handed */ 278 status = libinput_device_config_left_handed_set( 279 touchpad->libinput_device, 1); 280 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); 281 status = libinput_device_config_left_handed_set( 282 trackpoint->libinput_device, 1); 283 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); 284 285 litest_touch_down(touchpad, 0, 5, 5); 286 libinput_dispatch(li); 287 litest_button_click_debounced(touchpad, li, BTN_LEFT, true); 288 libinput_dispatch(li); 289 290 event = libinput_get_event(li); 291 litest_is_button_event(event, 292 BTN_RIGHT, 293 LIBINPUT_BUTTON_STATE_PRESSED); 294 device = libinput_event_get_device(event); 295 ck_assert(device == trackpoint->libinput_device); 296 libinput_event_destroy(event); 297 298 litest_button_click_debounced(touchpad, li, BTN_LEFT, false); 299 libinput_dispatch(li); 300 event = libinput_get_event(li); 301 litest_is_button_event(event, 302 BTN_RIGHT, 303 LIBINPUT_BUTTON_STATE_RELEASED); 304 device = libinput_event_get_device(event); 305 ck_assert(device == trackpoint->libinput_device); 306 libinput_event_destroy(event); 307 308 litest_delete_device(trackpoint); 309} 310END_TEST 311 312static inline void 313enable_dwtp(struct litest_device *dev) 314{ 315 enum libinput_config_status status, 316 expected = LIBINPUT_CONFIG_STATUS_SUCCESS; 317 status = libinput_device_config_dwtp_set_enabled(dev->libinput_device, 318 LIBINPUT_CONFIG_DWTP_ENABLED); 319 litest_assert_int_eq(status, expected); 320} 321 322static inline void 323disable_dwtp(struct litest_device *dev) 324{ 325 enum libinput_config_status status, 326 expected = LIBINPUT_CONFIG_STATUS_SUCCESS; 327 status = libinput_device_config_dwtp_set_enabled(dev->libinput_device, 328 LIBINPUT_CONFIG_DWTP_DISABLED); 329 litest_assert_int_eq(status, expected); 330} 331 332 333START_TEST(trackpoint_palmdetect) 334{ 335 struct litest_device *trackpoint = litest_current_device(); 336 struct litest_device *touchpad; 337 struct libinput *li = trackpoint->libinput; 338 int i; 339 340 touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C); 341 if (has_disable_while_trackpointing(touchpad)) 342 enable_dwtp(touchpad); 343 344 litest_disable_hold_gestures(touchpad->libinput_device); 345 litest_drain_events(li); 346 347 for (i = 0; i < 10; i++) { 348 litest_event(trackpoint, EV_REL, REL_X, 1); 349 litest_event(trackpoint, EV_REL, REL_Y, 1); 350 litest_event(trackpoint, EV_SYN, SYN_REPORT, 0); 351 libinput_dispatch(li); 352 } 353 litest_drain_events(li); 354 355 litest_touch_down(touchpad, 0, 30, 30); 356 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10); 357 litest_touch_up(touchpad, 0); 358 litest_assert_empty_queue(li); 359 360 litest_timeout_trackpoint(); 361 libinput_dispatch(li); 362 363 litest_touch_down(touchpad, 0, 30, 30); 364 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10); 365 litest_touch_up(touchpad, 0); 366 litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); 367 368 litest_delete_device(touchpad); 369} 370END_TEST 371 372START_TEST(trackpoint_palmdetect_dwtp_disabled) 373{ 374 struct litest_device *trackpoint = litest_current_device(); 375 struct litest_device *touchpad; 376 struct libinput *li = trackpoint->libinput; 377 int i; 378 379 touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C); 380 if (has_disable_while_trackpointing(touchpad)) 381 disable_dwtp(touchpad); 382 383 litest_disable_hold_gestures(touchpad->libinput_device); 384 litest_drain_events(li); 385 386 for (i = 0; i < 10; i++) { 387 litest_event(trackpoint, EV_REL, REL_X, 1); 388 litest_event(trackpoint, EV_REL, REL_Y, 1); 389 litest_event(trackpoint, EV_SYN, SYN_REPORT, 0); 390 libinput_dispatch(li); 391 } 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} 401END_TEST 402 403START_TEST(trackpoint_palmdetect_resume_touch) 404{ 405 struct litest_device *trackpoint = litest_current_device(); 406 struct litest_device *touchpad; 407 struct libinput *li = trackpoint->libinput; 408 int i; 409 410 touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C); 411 412 if (has_disable_while_trackpointing(touchpad)) 413 enable_dwtp(touchpad); 414 415 litest_disable_hold_gestures(touchpad->libinput_device); 416 litest_drain_events(li); 417 418 for (i = 0; i < 10; i++) { 419 litest_event(trackpoint, EV_REL, REL_X, 1); 420 litest_event(trackpoint, EV_REL, REL_Y, 1); 421 litest_event(trackpoint, EV_SYN, SYN_REPORT, 0); 422 libinput_dispatch(li); 423 } 424 litest_drain_events(li); 425 426 litest_touch_down(touchpad, 0, 30, 30); 427 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10); 428 litest_assert_empty_queue(li); 429 430 litest_timeout_trackpoint(); 431 libinput_dispatch(li); 432 433 /* touch started after last tp event, expect resume */ 434 litest_touch_move_to(touchpad, 0, 80, 80, 30, 30, 10); 435 litest_touch_up(touchpad, 0); 436 litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); 437 438 litest_delete_device(touchpad); 439} 440END_TEST 441 442START_TEST(trackpoint_palmdetect_require_min_events) 443{ 444 struct litest_device *trackpoint = litest_current_device(); 445 struct litest_device *touchpad; 446 struct libinput *li = trackpoint->libinput; 447 448 touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C); 449 450 if (has_disable_while_trackpointing(touchpad)) 451 enable_dwtp(touchpad); 452 453 litest_disable_hold_gestures(touchpad->libinput_device); 454 litest_drain_events(li); 455 456 /* A single event does not trigger palm detection */ 457 litest_event(trackpoint, EV_REL, REL_X, 1); 458 litest_event(trackpoint, EV_REL, REL_Y, 1); 459 litest_event(trackpoint, EV_SYN, SYN_REPORT, 0); 460 libinput_dispatch(li); 461 litest_drain_events(li); 462 463 litest_touch_down(touchpad, 0, 30, 30); 464 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10); 465 litest_touch_up(touchpad, 0); 466 litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); 467 468 litest_delete_device(touchpad); 469} 470END_TEST 471 472START_TEST(trackpoint_palmdetect_require_min_events_timeout) 473{ 474 struct litest_device *trackpoint = litest_current_device(); 475 struct litest_device *touchpad; 476 struct libinput *li = trackpoint->libinput; 477 478 touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C); 479 480 if (has_disable_while_trackpointing(touchpad)) 481 enable_dwtp(touchpad); 482 483 litest_disable_hold_gestures(touchpad->libinput_device); 484 litest_drain_events(li); 485 486 for (int i = 0; i < 10; i++) { 487 /* A single event does not trigger palm detection */ 488 litest_event(trackpoint, EV_REL, REL_X, 1); 489 litest_event(trackpoint, EV_REL, REL_Y, 1); 490 litest_event(trackpoint, EV_SYN, SYN_REPORT, 0); 491 libinput_dispatch(li); 492 litest_drain_events(li); 493 494 litest_touch_down(touchpad, 0, 30, 30); 495 litest_touch_move_to(touchpad, 0, 30, 30, 80, 80, 10); 496 litest_touch_up(touchpad, 0); 497 litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); 498 499 litest_timeout_trackpoint(); 500 } 501 502 litest_delete_device(touchpad); 503} 504END_TEST 505 506TEST_COLLECTION(trackpoint) 507{ 508 litest_add(trackpoint_middlebutton, LITEST_POINTINGSTICK, LITEST_ANY); 509 litest_add(trackpoint_middlebutton_noscroll, LITEST_POINTINGSTICK, LITEST_ANY); 510 litest_add(trackpoint_scroll, LITEST_POINTINGSTICK, LITEST_ANY); 511 litest_add(trackpoint_scroll_source, LITEST_POINTINGSTICK, LITEST_ANY); 512 litest_add(trackpoint_topsoftbuttons_left_handed_trackpoint, LITEST_TOPBUTTONPAD, LITEST_ANY); 513 litest_add(trackpoint_topsoftbuttons_left_handed_touchpad, LITEST_TOPBUTTONPAD, LITEST_ANY); 514 litest_add(trackpoint_topsoftbuttons_left_handed_both, LITEST_TOPBUTTONPAD, LITEST_ANY); 515 516 litest_add(trackpoint_palmdetect, LITEST_POINTINGSTICK, LITEST_ANY); 517 litest_add(trackpoint_palmdetect_dwtp_disabled, LITEST_POINTINGSTICK, LITEST_ANY); 518 litest_add(trackpoint_palmdetect_resume_touch, LITEST_POINTINGSTICK, LITEST_ANY); 519 litest_add(trackpoint_palmdetect_require_min_events, LITEST_POINTINGSTICK, LITEST_ANY); 520 litest_add(trackpoint_palmdetect_require_min_events_timeout, LITEST_POINTINGSTICK, LITEST_ANY); 521} 522