1/* 2 * Copyright © 2018 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#include <stdbool.h> 32#include <stdarg.h> 33 34#include "libinput-util.h" 35#include "evdev-tablet.h" 36#include "litest.h" 37#include "util-input-event.h" 38 39START_TEST(totem_type) 40{ 41 struct litest_device *dev = litest_current_device(); 42 struct libinput *li = dev->libinput; 43 struct libinput_event *event; 44 struct libinput_event_tablet_tool *t; 45 struct libinput_tablet_tool *tool; 46 47 litest_drain_events(li); 48 49 litest_tablet_proximity_in(dev, 50, 50, NULL); 50 libinput_dispatch(li); 51 52 event = libinput_get_event(li); 53 t = litest_is_tablet_event(event, 54 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); 55 tool = libinput_event_tablet_tool_get_tool(t); 56 57 ck_assert_int_eq(libinput_tablet_tool_get_type(tool), 58 LIBINPUT_TABLET_TOOL_TYPE_TOTEM); 59 libinput_event_destroy(event); 60} 61END_TEST 62 63START_TEST(totem_axes) 64{ 65 struct litest_device *dev = litest_current_device(); 66 struct libinput *li = dev->libinput; 67 struct libinput_event *event; 68 struct libinput_event_tablet_tool *t; 69 struct libinput_tablet_tool *tool; 70 71 litest_drain_events(li); 72 73 litest_tablet_proximity_in(dev, 50, 50, NULL); 74 libinput_dispatch(li); 75 76 event = libinput_get_event(li); 77 t = litest_is_tablet_event(event, 78 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); 79 tool = libinput_event_tablet_tool_get_tool(t); 80 81 ck_assert(libinput_tablet_tool_has_rotation(tool)); 82 ck_assert(libinput_tablet_tool_has_size(tool)); 83 ck_assert(libinput_tablet_tool_has_button(tool, BTN_0)); 84 85 libinput_event_destroy(event); 86} 87END_TEST 88 89START_TEST(totem_proximity_in_out) 90{ 91 struct litest_device *dev = litest_current_device(); 92 struct libinput *li = dev->libinput; 93 struct libinput_event *event; 94 struct libinput_event_tablet_tool *t; 95 96 litest_drain_events(li); 97 98 litest_tablet_proximity_in(dev, 50, 50, NULL); 99 libinput_dispatch(li); 100 101 event = libinput_get_event(li); 102 t = litest_is_tablet_event(event, 103 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); 104 ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t), 105 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN); 106 libinput_event_destroy(event); 107 108 event = libinput_get_event(li); 109 t = litest_is_tablet_event(event, 110 LIBINPUT_EVENT_TABLET_TOOL_TIP); 111 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t), 112 LIBINPUT_TABLET_TOOL_TIP_DOWN); 113 libinput_event_destroy(event); 114 115 litest_assert_empty_queue(li); 116 litest_tablet_proximity_out(dev); 117 libinput_dispatch(li); 118 119 event = libinput_get_event(li); 120 t = litest_is_tablet_event(event, 121 LIBINPUT_EVENT_TABLET_TOOL_TIP); 122 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t), 123 LIBINPUT_TABLET_TOOL_TIP_UP); 124 libinput_event_destroy(event); 125 126 event = libinput_get_event(li); 127 t = litest_is_tablet_event(event, 128 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); 129 ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t), 130 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT); 131 libinput_event_destroy(event); 132} 133END_TEST 134 135START_TEST(totem_proximity_in_on_init) 136{ 137 struct litest_device *dev = litest_current_device(); 138 struct libinput *li; 139 struct libinput_event *event; 140 struct libinput_event_tablet_tool *t; 141 const char *devnode; 142 double x, y; 143 double w, h; 144 const struct input_absinfo *abs; 145 146 abs = libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_X); 147 w = absinfo_range(abs)/abs->resolution; 148 abs = libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_Y); 149 h = absinfo_range(abs)/abs->resolution; 150 151 litest_tablet_proximity_in(dev, 50, 50, NULL); 152 153 /* for simplicity, we create a new litest context */ 154 devnode = libevdev_uinput_get_devnode(dev->uinput); 155 li = litest_create_context(); 156 libinput_path_add_device(li, devnode); 157 libinput_dispatch(li); 158 159 litest_wait_for_event_of_type(li, 160 LIBINPUT_EVENT_DEVICE_ADDED, 161 -1); 162 event = libinput_get_event(li); 163 libinput_event_destroy(event); 164 165 event = libinput_get_event(li); 166 t = litest_is_tablet_event(event, 167 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); 168 ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t), 169 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN); 170 x = libinput_event_tablet_tool_get_x(t); 171 y = libinput_event_tablet_tool_get_y(t); 172 173 ck_assert_double_gt(x, w/2 - 1); 174 ck_assert_double_lt(x, w/2 + 1); 175 ck_assert_double_gt(y, h/2 - 1); 176 ck_assert_double_lt(y, h/2 + 1); 177 178 libinput_event_destroy(event); 179 180 event = libinput_get_event(li); 181 t = litest_is_tablet_event(event, 182 LIBINPUT_EVENT_TABLET_TOOL_TIP); 183 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t), 184 LIBINPUT_TABLET_TOOL_TIP_DOWN); 185 x = libinput_event_tablet_tool_get_x(t); 186 y = libinput_event_tablet_tool_get_y(t); 187 188 ck_assert_double_gt(x, w/2 - 1); 189 ck_assert_double_lt(x, w/2 + 1); 190 ck_assert_double_gt(y, h/2 - 1); 191 ck_assert_double_lt(y, h/2 + 1); 192 193 libinput_event_destroy(event); 194 195 litest_assert_empty_queue(li); 196 197 litest_destroy_context(li); 198} 199END_TEST 200 201START_TEST(totem_proximity_out_on_suspend) 202{ 203 struct litest_device *dev = litest_current_device(); 204 struct libinput *li; 205 struct libinput_event *event; 206 struct libinput_event_tablet_tool *t; 207 const char *devnode; 208 209 /* for simplicity, we create a new litest context */ 210 devnode = libevdev_uinput_get_devnode(dev->uinput); 211 li = litest_create_context(); 212 libinput_path_add_device(li, devnode); 213 214 litest_tablet_proximity_in(dev, 50, 50, NULL); 215 litest_drain_events(li); 216 217 libinput_suspend(li); 218 219 libinput_dispatch(li); 220 event = libinput_get_event(li); 221 t = litest_is_tablet_event(event, 222 LIBINPUT_EVENT_TABLET_TOOL_TIP); 223 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t), 224 LIBINPUT_TABLET_TOOL_TIP_UP); 225 libinput_event_destroy(event); 226 227 event = libinput_get_event(li); 228 t = litest_is_tablet_event(event, 229 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); 230 ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t), 231 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT); 232 libinput_event_destroy(event); 233 234 litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_REMOVED); 235 litest_destroy_context(li); 236} 237END_TEST 238 239START_TEST(totem_motion) 240{ 241 struct litest_device *dev = litest_current_device(); 242 struct libinput *li = dev->libinput; 243 struct libinput_event *event; 244 double x = 50, y = 50; 245 double current_x, current_y, old_x, old_y; 246 247 litest_tablet_proximity_in(dev, x, y, NULL); 248 litest_drain_events(li); 249 250 for (int i = 0; i < 30; i++, x++, y--) { 251 struct libinput_event_tablet_tool *t; 252 253 litest_tablet_motion(dev, x + 1, y + 1, NULL); 254 libinput_dispatch(li); 255 256 event = libinput_get_event(li); 257 t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS); 258 259 ck_assert(libinput_event_tablet_tool_x_has_changed(t)); 260 ck_assert(libinput_event_tablet_tool_y_has_changed(t)); 261 262 current_x = libinput_event_tablet_tool_get_x(t); 263 current_y = libinput_event_tablet_tool_get_y(t); 264 if (i != 0) { 265 ck_assert_double_gt(current_x, old_x); 266 ck_assert_double_lt(current_y, old_y); 267 } 268 old_x = current_x; 269 old_y = current_y; 270 271 libinput_event_destroy(event); 272 } 273} 274END_TEST 275 276START_TEST(totem_rotation) 277{ 278 struct litest_device *dev = litest_current_device(); 279 struct libinput *li = dev->libinput; 280 struct libinput_event *event; 281 double r, old_r; 282 struct axis_replacement axes[] = { 283 { ABS_MT_ORIENTATION, 50 }, /* mid-point is 0 */ 284 { -1, -1 } 285 }; 286 287 litest_tablet_proximity_in(dev, 50, 50, axes); 288 litest_drain_events(li); 289 290 old_r = 360; 291 292 for (int i = 1; i < 30; i++) { 293 struct libinput_event_tablet_tool *t; 294 295 296 litest_axis_set_value(axes, ABS_MT_ORIENTATION, 50 + i); 297 litest_tablet_motion(dev, 50, 50, axes); 298 libinput_dispatch(li); 299 300 event = libinput_get_event(li); 301 t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS); 302 303 ck_assert(!libinput_event_tablet_tool_x_has_changed(t)); 304 ck_assert(!libinput_event_tablet_tool_y_has_changed(t)); 305 ck_assert(libinput_event_tablet_tool_rotation_has_changed(t)); 306 307 r = libinput_event_tablet_tool_get_rotation(t); 308 ck_assert_double_lt(r, old_r); 309 old_r = r; 310 311 libinput_event_destroy(event); 312 } 313 314 old_r = 0; 315 316 for (int i = 1; i < 30; i++) { 317 struct libinput_event_tablet_tool *t; 318 319 320 litest_axis_set_value(axes, ABS_MT_ORIENTATION, 50 - i); 321 litest_tablet_motion(dev, 50, 50, axes); 322 libinput_dispatch(li); 323 324 event = libinput_get_event(li); 325 t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS); 326 327 ck_assert(!libinput_event_tablet_tool_x_has_changed(t)); 328 ck_assert(!libinput_event_tablet_tool_y_has_changed(t)); 329 ck_assert(libinput_event_tablet_tool_rotation_has_changed(t)); 330 331 r = libinput_event_tablet_tool_get_rotation(t); 332 ck_assert_double_gt(r, old_r); 333 old_r = r; 334 335 libinput_event_destroy(event); 336 } 337} 338END_TEST 339 340START_TEST(totem_size) 341{ 342 struct litest_device *dev = litest_current_device(); 343 struct libinput *li = dev->libinput; 344 struct libinput_event *event; 345 struct libinput_event_tablet_tool *t; 346 double smin, smaj; 347 348 litest_drain_events(li); 349 350 litest_tablet_proximity_in(dev, 50, 50, NULL); 351 libinput_dispatch(li); 352 353 event = libinput_get_event(li); 354 t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); 355 ck_assert(libinput_event_tablet_tool_size_major_has_changed(t)); 356 ck_assert(libinput_event_tablet_tool_size_minor_has_changed(t)); 357 smaj = libinput_event_tablet_tool_get_size_major(t); 358 smin = libinput_event_tablet_tool_get_size_minor(t); 359 libinput_event_destroy(event); 360 361 ck_assert_double_eq(smaj, 71.8); 362 ck_assert_double_eq(smin, 71.8); 363 364 litest_drain_events(li); 365} 366END_TEST 367 368START_TEST(totem_button) 369{ 370 struct litest_device *dev = litest_current_device(); 371 struct libinput *li = dev->libinput; 372 struct libinput_event *event; 373 struct libinput_event_tablet_tool *t; 374 375 litest_tablet_proximity_in(dev, 30, 40, NULL); 376 litest_drain_events(li); 377 378 litest_button_click(dev, BTN_0, true); 379 libinput_dispatch(li); 380 event = libinput_get_event(li); 381 t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON); 382 ck_assert_int_eq(libinput_event_tablet_tool_get_button(t), BTN_0); 383 ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(t), 384 LIBINPUT_BUTTON_STATE_PRESSED); 385 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t), 386 LIBINPUT_TABLET_TOOL_TIP_DOWN); 387 libinput_event_destroy(event); 388 389 litest_button_click(dev, BTN_0, false); 390 libinput_dispatch(li); 391 392 event = libinput_get_event(li); 393 t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON); 394 ck_assert_int_eq(libinput_event_tablet_tool_get_button(t), BTN_0); 395 ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(t), 396 LIBINPUT_BUTTON_STATE_RELEASED); 397 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t), 398 LIBINPUT_TABLET_TOOL_TIP_DOWN); 399 libinput_event_destroy(event); 400} 401END_TEST 402 403START_TEST(totem_button_down_on_init) 404{ 405 struct litest_device *dev = litest_current_device(); 406 struct libinput *li; 407 struct libinput_event *event; 408 struct libinput_event_tablet_tool *t; 409 const char *devnode; 410 411 litest_tablet_proximity_in(dev, 50, 50, NULL); 412 litest_button_click(dev, BTN_0, true); 413 414 /* for simplicity, we create a new litest context */ 415 devnode = libevdev_uinput_get_devnode(dev->uinput); 416 li = litest_create_context(); 417 libinput_path_add_device(li, devnode); 418 libinput_dispatch(li); 419 420 litest_wait_for_event_of_type(li, 421 LIBINPUT_EVENT_DEVICE_ADDED, 422 -1); 423 event = libinput_get_event(li); 424 libinput_event_destroy(event); 425 426 event = libinput_get_event(li); 427 t = litest_is_tablet_event(event, 428 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); 429 ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t), 430 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN); 431 432 libinput_event_destroy(event); 433 434 event = libinput_get_event(li); 435 t = litest_is_tablet_event(event, 436 LIBINPUT_EVENT_TABLET_TOOL_TIP); 437 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t), 438 LIBINPUT_TABLET_TOOL_TIP_DOWN); 439 440 libinput_event_destroy(event); 441 442 /* The button is down on init but we don't expect an event */ 443 litest_assert_empty_queue(li); 444 445 litest_button_click(dev, BTN_0, false); 446 libinput_dispatch(li); 447 litest_assert_empty_queue(li); 448 449 /* but buttons after this should be sent */ 450 litest_button_click(dev, BTN_0, true); 451 libinput_dispatch(li); 452 litest_assert_tablet_button_event(li, BTN_0, LIBINPUT_BUTTON_STATE_PRESSED); 453 litest_button_click(dev, BTN_0, false); 454 libinput_dispatch(li); 455 litest_assert_tablet_button_event(li, BTN_0, LIBINPUT_BUTTON_STATE_RELEASED); 456 457 litest_destroy_context(li); 458} 459END_TEST 460 461START_TEST(totem_button_up_on_delete) 462{ 463 struct libinput *li = litest_create_context(); 464 struct litest_device *dev = litest_add_device(li, LITEST_DELL_CANVAS_TOTEM); 465 struct libevdev *evdev = libevdev_new(); 466 467 litest_tablet_proximity_in(dev, 10, 10, NULL); 468 litest_drain_events(li); 469 470 litest_button_click(dev, BTN_0, true); 471 litest_drain_events(li); 472 473 litest_delete_device(dev); 474 libinput_dispatch(li); 475 476 litest_assert_tablet_button_event(li, 477 BTN_0, 478 LIBINPUT_BUTTON_STATE_RELEASED); 479 480 litest_assert_tablet_tip_event(li, LIBINPUT_TABLET_TOOL_TIP_UP); 481 litest_assert_tablet_proximity_event(li, 482 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT); 483 libevdev_free(evdev); 484 litest_destroy_context(li); 485} 486END_TEST 487 488START_TEST(totem_arbitration_below) 489{ 490 struct litest_device *totem = litest_current_device(); 491 struct litest_device *touch; 492 struct libinput *li = totem->libinput; 493 494 touch = litest_add_device(li, LITEST_DELL_CANVAS_TOTEM_TOUCH); 495 litest_drain_events(li); 496 497 /* touches below the totem, cancelled once the totem is down */ 498 litest_touch_down(touch, 0, 50, 50); 499 libinput_dispatch(li); 500 litest_assert_touch_down_frame(li); 501 litest_touch_move_to(touch, 0, 50, 50, 50, 70, 10); 502 libinput_dispatch(li); 503 while (libinput_next_event_type(li)) { 504 litest_assert_touch_motion_frame(li); 505 } 506 507 litest_tablet_proximity_in(totem, 50, 70, NULL); 508 libinput_dispatch(li); 509 510 litest_assert_tablet_proximity_event(li, LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN); 511 litest_assert_tablet_tip_event(li, LIBINPUT_TABLET_TOOL_TIP_DOWN); 512 litest_assert_touch_cancel(li); 513 514 litest_touch_move_to(touch, 0, 50, 70, 20, 50, 10); 515 litest_assert_empty_queue(li); 516 517 litest_tablet_motion(totem, 20, 50, NULL); 518 litest_assert_only_typed_events(li, LIBINPUT_EVENT_TABLET_TOOL_AXIS); 519 520 litest_touch_up(touch, 0); 521 litest_assert_empty_queue(li); 522 523 litest_delete_device(touch); 524} 525END_TEST 526 527START_TEST(totem_arbitration_during) 528{ 529 struct litest_device *totem = litest_current_device(); 530 struct litest_device *touch; 531 struct libinput *li = totem->libinput; 532 533 touch = litest_add_device(li, LITEST_DELL_CANVAS_TOTEM_TOUCH); 534 litest_drain_events(li); 535 536 litest_tablet_proximity_in(totem, 50, 50, NULL); 537 libinput_dispatch(li); 538 539 litest_drain_events(li); 540 541 for (int i = 0; i < 3; i++) { 542 litest_touch_down(touch, 0, 51, 51); 543 litest_touch_move_to(touch, 0, 51, 50, 90, 80, 10); 544 litest_touch_up(touch, 0); 545 546 litest_assert_empty_queue(li); 547 } 548 549 litest_delete_device(touch); 550} 551END_TEST 552 553START_TEST(totem_arbitration_outside_rect) 554{ 555 struct litest_device *totem = litest_current_device(); 556 struct litest_device *touch; 557 struct libinput *li = totem->libinput; 558 559 touch = litest_add_device(li, LITEST_DELL_CANVAS_TOTEM_TOUCH); 560 litest_drain_events(li); 561 562 litest_tablet_proximity_in(totem, 50, 50, NULL); 563 libinput_dispatch(li); 564 565 litest_drain_events(li); 566 567 for (int i = 0; i < 3; i++) { 568 litest_touch_down(touch, 0, 81, 51); 569 litest_touch_move_to(touch, 0, 81, 50, 90, 80, 10); 570 litest_touch_up(touch, 0); 571 libinput_dispatch(li); 572 573 litest_assert_touch_sequence(li); 574 } 575 576 /* moving onto the totem is fine */ 577 litest_touch_down(touch, 0, 81, 51); 578 litest_touch_move_to(touch, 0, 81, 50, 50, 50, 10); 579 litest_touch_up(touch, 0); 580 libinput_dispatch(li); 581 582 litest_assert_touch_sequence(li); 583 584 litest_delete_device(touch); 585} 586END_TEST 587 588TEST_COLLECTION(totem) 589{ 590 litest_add(totem_type, LITEST_TOTEM, LITEST_ANY); 591 litest_add(totem_axes, LITEST_TOTEM, LITEST_ANY); 592 litest_add(totem_proximity_in_out, LITEST_TOTEM, LITEST_ANY); 593 litest_add(totem_proximity_in_on_init, LITEST_TOTEM, LITEST_ANY); 594 litest_add(totem_proximity_out_on_suspend, LITEST_TOTEM, LITEST_ANY); 595 596 litest_add(totem_motion, LITEST_TOTEM, LITEST_ANY); 597 litest_add(totem_rotation, LITEST_TOTEM, LITEST_ANY); 598 litest_add(totem_size, LITEST_TOTEM, LITEST_ANY); 599 litest_add(totem_button, LITEST_TOTEM, LITEST_ANY); 600 litest_add(totem_button_down_on_init, LITEST_TOTEM, LITEST_ANY); 601 litest_add_no_device(totem_button_up_on_delete); 602 603 litest_add(totem_arbitration_below, LITEST_TOTEM, LITEST_ANY); 604 litest_add(totem_arbitration_during, LITEST_TOTEM, LITEST_ANY); 605 litest_add(totem_arbitration_outside_rect, LITEST_TOTEM, LITEST_ANY); 606} 607