1 /* $OpenBSD: wstpad.c,v 1.30 2021/03/24 18:28:24 bru Exp $ */ 2 3 /* 4 * Copyright (c) 2015, 2016 Ulf Brosziewski 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * touchpad input processing 21 */ 22 23 #include <sys/param.h> 24 #include <sys/kernel.h> 25 #include <sys/malloc.h> 26 #include <sys/proc.h> 27 #include <sys/systm.h> 28 #include <sys/signalvar.h> 29 #include <sys/timeout.h> 30 31 #include <dev/wscons/wsconsio.h> 32 #include <dev/wscons/wsmousevar.h> 33 #include <dev/wscons/wseventvar.h> 34 #include <dev/wscons/wsmouseinput.h> 35 36 #define BTNMASK(n) ((n) > 0 && (n) <= 32 ? 1 << ((n) - 1) : 0) 37 38 #define LEFTBTN BTNMASK(1) 39 #define MIDDLEBTN BTNMASK(2) 40 #define RIGHTBTN BTNMASK(3) 41 42 #define PRIMARYBTN LEFTBTN 43 44 #define PRIMARYBTN_CLICKED(tp) ((tp)->btns_sync & PRIMARYBTN & (tp)->btns) 45 #define PRIMARYBTN_RELEASED(tp) ((tp)->btns_sync & PRIMARYBTN & ~(tp)->btns) 46 47 #define IS_MT(tp) ((tp)->features & WSTPAD_MT) 48 #define DISABLE(tp) ((tp)->features & WSTPAD_DISABLE) 49 50 /* 51 * Ratios to the height or width of the touchpad surface, in 52 * [*.12] fixed-point format: 53 */ 54 #define V_EDGE_RATIO_DEFAULT 205 55 #define B_EDGE_RATIO_DEFAULT 410 56 #define T_EDGE_RATIO_DEFAULT 512 57 #define CENTER_RATIO_DEFAULT 512 58 59 #define TAP_MAXTIME_DEFAULT 180 60 #define TAP_CLICKTIME_DEFAULT 180 61 #define TAP_LOCKTIME_DEFAULT 0 62 #define TAP_BTNMAP_SIZE 3 63 64 #define CLICKDELAY_MS 20 65 #define FREEZE_MS 100 66 #define MATCHINTERVAL_MS 45 67 #define STOPINTERVAL_MS 55 68 69 #define MAG_LOW (10 << 12) 70 #define MAG_MEDIUM (18 << 12) 71 72 enum tpad_handlers { 73 SOFTBUTTON_HDLR, 74 TOPBUTTON_HDLR, 75 TAP_HDLR, 76 F2SCROLL_HDLR, 77 EDGESCROLL_HDLR, 78 CLICK_HDLR, 79 }; 80 81 enum tap_state { 82 TAP_DETECT, 83 TAP_IGNORE, 84 TAP_LIFTED, 85 TAP_2ND_TOUCH, 86 TAP_LOCKED, 87 TAP_NTH_TOUCH, 88 }; 89 90 enum tpad_cmd { 91 CLEAR_MOTION_DELTAS, 92 SOFTBUTTON_DOWN, 93 SOFTBUTTON_UP, 94 TAPBUTTON_DOWN, 95 TAPBUTTON_UP, 96 TAPBUTTON_DOUBLECLK, 97 VSCROLL, 98 HSCROLL, 99 }; 100 101 /* 102 * tpad_touch.flags: 103 */ 104 #define L_EDGE (1 << 0) 105 #define R_EDGE (1 << 1) 106 #define T_EDGE (1 << 2) 107 #define B_EDGE (1 << 3) 108 #define THUMB (1 << 4) 109 110 #define EDGES (L_EDGE | R_EDGE | T_EDGE | B_EDGE) 111 112 /* 113 * A touch is "centered" if it does not start and remain at the top 114 * edge or one of the vertical edges. Two-finger scrolling and tapping 115 * require that at least one touch is centered. 116 */ 117 #define CENTERED(t) (((t)->flags & (L_EDGE | R_EDGE | T_EDGE)) == 0) 118 119 enum touchstates { 120 TOUCH_NONE, 121 TOUCH_BEGIN, 122 TOUCH_UPDATE, 123 TOUCH_END, 124 }; 125 126 struct tpad_touch { 127 u_int flags; 128 enum touchstates state; 129 int x; 130 int y; 131 int dir; 132 struct timespec start; 133 struct timespec match; 134 struct position *pos; 135 struct { 136 int x; 137 int y; 138 struct timespec time; 139 } orig; 140 }; 141 142 /* 143 * wstpad.features 144 */ 145 #define WSTPAD_SOFTBUTTONS (1 << 0) 146 #define WSTPAD_SOFTMBTN (1 << 1) 147 #define WSTPAD_TOPBUTTONS (1 << 2) 148 #define WSTPAD_TWOFINGERSCROLL (1 << 3) 149 #define WSTPAD_EDGESCROLL (1 << 4) 150 #define WSTPAD_HORIZSCROLL (1 << 5) 151 #define WSTPAD_SWAPSIDES (1 << 6) 152 #define WSTPAD_DISABLE (1 << 7) 153 154 #define WSTPAD_MT (1 << 31) 155 156 157 struct wstpad { 158 u_int features; 159 u_int handlers; 160 161 /* 162 * t always points into the tpad_touches array, which has at 163 * least one element. If there is more than one, t selects 164 * the pointer-controlling touch. 165 */ 166 struct tpad_touch *t; 167 struct tpad_touch *tpad_touches; 168 169 u_int mtcycle; 170 u_int ignore; 171 172 int contacts; 173 int prev_contacts; 174 u_int btns; 175 u_int btns_sync; 176 int ratio; 177 178 struct timespec time; 179 180 u_int freeze; 181 struct timespec freeze_ts; 182 183 /* edge coordinates */ 184 struct { 185 int left; 186 int right; 187 int top; 188 int bottom; 189 int center; 190 int center_left; 191 int center_right; 192 int low; 193 } edge; 194 195 struct { 196 /* ratios to the surface width or height */ 197 int left_edge; 198 int right_edge; 199 int top_edge; 200 int bottom_edge; 201 int center_width; 202 /* two-finger contacts */ 203 int f2pressure; 204 int f2width; 205 } params; 206 207 /* handler state and configuration: */ 208 209 u_int softbutton; 210 u_int sbtnswap; 211 212 struct { 213 enum tap_state state; 214 int contacts; 215 int centered; 216 u_int button; 217 int maxdist; 218 struct timeout to; 219 /* parameters: */ 220 struct timespec maxtime; 221 int clicktime; 222 int locktime; 223 u_int btnmap[TAP_BTNMAP_SIZE]; 224 } tap; 225 226 struct { 227 int dz; 228 int dw; 229 int hdist; 230 int vdist; 231 int mag; 232 } scroll; 233 }; 234 235 static const struct timespec match_interval = 236 { .tv_sec = 0, .tv_nsec = MATCHINTERVAL_MS * 1000000 }; 237 238 static const struct timespec stop_interval = 239 { .tv_sec = 0, .tv_nsec = STOPINTERVAL_MS * 1000000 }; 240 241 /* 242 * Coordinates in the wstpad struct are "normalized" device coordinates, 243 * the orientation is left-to-right and upward. 244 */ 245 static inline int 246 normalize_abs(struct axis_filter *filter, int val) 247 { 248 return (filter->inv ? filter->inv - val : val); 249 } 250 251 static inline int 252 normalize_rel(struct axis_filter *filter, int val) 253 { 254 return (filter->inv ? -val : val); 255 } 256 257 /* 258 * Directions of motion are represented by numbers in the range 0 - 11, 259 * corresponding to clockwise counted circle sectors: 260 * 261 * 11 | 0 262 * 10 | 1 263 * 9 | 2 264 * -------+------- 265 * 8 | 3 266 * 7 | 4 267 * 6 | 5 268 * 269 */ 270 /* Tangent constants in [*.12] fixed-point format: */ 271 #define TAN_DEG_60 7094 272 #define TAN_DEG_30 2365 273 274 #define NORTH(d) ((d) == 0 || (d) == 11) 275 #define SOUTH(d) ((d) == 5 || (d) == 6) 276 #define EAST(d) ((d) == 2 || (d) == 3) 277 #define WEST(d) ((d) == 8 || (d) == 9) 278 279 static inline int 280 direction(int dx, int dy, int ratio) 281 { 282 int rdy, dir = -1; 283 284 if (dx || dy) { 285 rdy = abs(dy) * ratio; 286 if (abs(dx) * TAN_DEG_60 < rdy) 287 dir = 0; 288 else if (abs(dx) * TAN_DEG_30 < rdy) 289 dir = 1; 290 else 291 dir = 2; 292 if ((dx < 0) != (dy < 0)) 293 dir = 5 - dir; 294 if (dx < 0) 295 dir += 6; 296 } 297 return dir; 298 } 299 300 static inline int 301 dircmp(int dir1, int dir2) 302 { 303 int diff = abs(dir1 - dir2); 304 return (diff <= 6 ? diff : 12 - diff); 305 } 306 307 /* 308 * Update direction and timespec attributes for a touch. They are used to 309 * determine whether it is moving - or resting - stably. 310 * 311 * The callers pass touches from the current frame and the touches that are 312 * no longer present in the update cycle to this function. Even though this 313 * ensures that pairs of zero deltas do not result from stale coordinates, 314 * zero deltas do not reset the state immediately. A short time span - the 315 * "stop interval" - must pass before the state is cleared, which is 316 * necessary because some touchpads report intermediate stops when a touch 317 * is moving very slowly. 318 */ 319 void 320 wstpad_set_direction(struct wstpad *tp, struct tpad_touch *t, int dx, int dy) 321 { 322 int dir; 323 struct timespec ts; 324 325 if (t->state != TOUCH_UPDATE) { 326 t->dir = -1; 327 memcpy(&t->start, &tp->time, sizeof(struct timespec)); 328 return; 329 } 330 331 dir = direction(dx, dy, tp->ratio); 332 if (dir >= 0) { 333 if (t->dir < 0 || dircmp(dir, t->dir) > 1) { 334 memcpy(&t->start, &tp->time, sizeof(struct timespec)); 335 } 336 t->dir = dir; 337 memcpy(&t->match, &tp->time, sizeof(struct timespec)); 338 } else if (t->dir >= 0) { 339 timespecsub(&tp->time, &t->match, &ts); 340 if (timespeccmp(&ts, &stop_interval, >=)) { 341 t->dir = -1; 342 memcpy(&t->start, &t->match, sizeof(struct timespec)); 343 } 344 } 345 } 346 347 /* 348 * Make a rough, but quick estimation of the speed of a touch. Its 349 * distance to the previous position is scaled by factors derived 350 * from the average update rate and the deceleration parameter 351 * (filter.dclr). The unit of the result is: 352 * (filter.dclr / 100) device units per millisecond 353 * 354 * Magnitudes are returned in [*.12] fixed-point format. For purposes 355 * of filtering, they are divided into medium and high speeds 356 * (> MAG_MEDIUM), low speeds, and very low speeds (< MAG_LOW). 357 * 358 * The scale factors are not affected if deceleration is turned off. 359 */ 360 static inline int 361 magnitude(struct wsmouseinput *input, int dx, int dy) 362 { 363 int h, v; 364 365 h = abs(dx) * input->filter.h.mag_scale; 366 v = abs(dy) * input->filter.v.mag_scale; 367 /* Return an "alpha-max-plus-beta-min" approximation: */ 368 return (h >= v ? h + 3 * v / 8 : v + 3 * h / 8); 369 } 370 371 /* 372 * Treat a touch as stable if it is moving at a medium or high speed, 373 * if it is moving continuously, or if it has stopped for a certain 374 * time span. 375 */ 376 int 377 wstpad_is_stable(struct wsmouseinput *input, struct tpad_touch *t) 378 { 379 struct timespec ts; 380 381 if (t->dir >= 0) { 382 if (magnitude(input, t->pos->dx, t->pos->dy) > MAG_MEDIUM) 383 return (1); 384 timespecsub(&t->match, &t->start, &ts); 385 } else { 386 timespecsub(&input->tp->time, &t->start, &ts); 387 } 388 389 return (timespeccmp(&ts, &match_interval, >=)); 390 } 391 392 /* 393 * If a touch starts in an edge area, pointer movement will be 394 * suppressed as long as it stays in that area. 395 */ 396 static inline u_int 397 edge_flags(struct wstpad *tp, int x, int y) 398 { 399 u_int flags = 0; 400 401 if (x < tp->edge.left) 402 flags |= L_EDGE; 403 else if (x >= tp->edge.right) 404 flags |= R_EDGE; 405 if (y < tp->edge.bottom) 406 flags |= B_EDGE; 407 else if (y >= tp->edge.top) 408 flags |= T_EDGE; 409 410 return (flags); 411 } 412 413 static inline struct tpad_touch * 414 get_2nd_touch(struct wsmouseinput *input) 415 { 416 struct wstpad *tp = input->tp; 417 int slot; 418 419 if (IS_MT(tp)) { 420 slot = ffs(input->mt.touches & ~(input->mt.ptr | tp->ignore)); 421 if (slot) 422 return &tp->tpad_touches[--slot]; 423 } 424 return NULL; 425 } 426 427 /* Suppress pointer motion for a short period of time. */ 428 static inline void 429 set_freeze_ts(struct wstpad *tp, int sec, int ms) 430 { 431 tp->freeze_ts.tv_sec = sec; 432 tp->freeze_ts.tv_nsec = ms * 1000000; 433 timespecadd(&tp->time, &tp->freeze_ts, &tp->freeze_ts); 434 } 435 436 437 /* Return TRUE if two-finger- or edge-scrolling would be valid. */ 438 int 439 wstpad_scroll_coords(struct wsmouseinput *input, int *dx, int *dy) 440 { 441 struct wstpad *tp = input->tp; 442 443 if (tp->contacts != tp->prev_contacts || tp->btns || tp->btns_sync) { 444 tp->scroll.dz = 0; 445 tp->scroll.dw = 0; 446 return (0); 447 } 448 if ((input->motion.sync & SYNC_POSITION) == 0) 449 return (0); 450 /* 451 * Try to exclude accidental scroll events by checking whether the 452 * pointer-controlling touch is stable. The check, which may cause 453 * a short delay, is only applied initially, a touch that stops and 454 * resumes scrolling is not affected. 455 */ 456 if (tp->scroll.dz || tp->scroll.dw || wstpad_is_stable(input, tp->t)) { 457 *dx = normalize_rel(&input->filter.h, input->motion.pos.dx); 458 *dy = normalize_rel(&input->filter.v, input->motion.pos.dy); 459 return (*dx || *dy); 460 } 461 462 return (0); 463 } 464 465 void 466 wstpad_scroll(struct wstpad *tp, int dx, int dy, int mag, u_int *cmds) 467 { 468 int dz, dw, n = 1; 469 470 /* 471 * The function applies strong deceleration, but only to input with 472 * very low speeds. A higher threshold might make applications 473 * without support for precision scrolling appear unresponsive. 474 */ 475 mag = tp->scroll.mag = imin(MAG_MEDIUM, 476 (mag + 3 * tp->scroll.mag) / 4); 477 if (mag < MAG_LOW) 478 n = (MAG_LOW - mag) / 4096 + 1; 479 480 if (dy && tp->scroll.vdist) { 481 if (tp->scroll.dw) { 482 /* 483 * Before switching the axis, wstpad_scroll_coords() 484 * should check again whether the movement is stable. 485 */ 486 tp->scroll.dw = 0; 487 return; 488 } 489 dz = -dy * 4096 / (tp->scroll.vdist * n); 490 if (tp->scroll.dz) { 491 if ((dy < 0) != (tp->scroll.dz > 0)) 492 tp->scroll.dz = -tp->scroll.dz; 493 dz = (dz + 3 * tp->scroll.dz) / 4; 494 } 495 if (dz) { 496 tp->scroll.dz = dz; 497 *cmds |= 1 << VSCROLL; 498 } 499 500 } else if (dx && tp->scroll.hdist) { 501 if (tp->scroll.dz) { 502 tp->scroll.dz = 0; 503 return; 504 } 505 dw = dx * 4096 / (tp->scroll.hdist * n); 506 if (tp->scroll.dw) { 507 if ((dx > 0) != (tp->scroll.dw > 0)) 508 tp->scroll.dw = -tp->scroll.dw; 509 dw = (dw + 3 * tp->scroll.dw) / 4; 510 } 511 if (dw) { 512 tp->scroll.dw = dw; 513 *cmds |= 1 << HSCROLL; 514 } 515 } 516 } 517 518 void 519 wstpad_f2scroll(struct wsmouseinput *input, u_int *cmds) 520 { 521 struct wstpad *tp = input->tp; 522 struct tpad_touch *t2; 523 int dir, dx, dy, centered; 524 525 if (tp->ignore == 0) { 526 if (tp->contacts != 2) 527 return; 528 } else if (tp->contacts != 3 || (tp->ignore == input->mt.ptr)) { 529 return; 530 } 531 532 if (!wstpad_scroll_coords(input, &dx, &dy)) 533 return; 534 535 dir = tp->t->dir; 536 if (!(NORTH(dir) || SOUTH(dir))) 537 dy = 0; 538 if (!(EAST(dir) || WEST(dir))) 539 dx = 0; 540 541 if (dx || dy) { 542 centered = CENTERED(tp->t); 543 if (IS_MT(tp)) { 544 t2 = get_2nd_touch(input); 545 if (t2 == NULL) 546 return; 547 dir = t2->dir; 548 if ((dy > 0 && !NORTH(dir)) || (dy < 0 && !SOUTH(dir))) 549 return; 550 if ((dx > 0 && !EAST(dir)) || (dx < 0 && !WEST(dir))) 551 return; 552 if (!wstpad_is_stable(input, t2) && 553 !(tp->scroll.dz || tp->scroll.dw)) 554 return; 555 centered |= CENTERED(t2); 556 } 557 if (centered) { 558 wstpad_scroll(tp, dx, dy, 559 magnitude(input, dx, dy), cmds); 560 set_freeze_ts(tp, 0, FREEZE_MS); 561 } 562 } 563 } 564 565 void 566 wstpad_edgescroll(struct wsmouseinput *input, u_int *cmds) 567 { 568 struct wstpad *tp = input->tp; 569 struct tpad_touch *t = tp->t; 570 u_int v_edge, b_edge; 571 int dx, dy; 572 573 if (!wstpad_scroll_coords(input, &dx, &dy) || tp->contacts != 1) 574 return; 575 576 v_edge = (tp->features & WSTPAD_SWAPSIDES) ? L_EDGE : R_EDGE; 577 b_edge = (tp->features & WSTPAD_HORIZSCROLL) ? B_EDGE : 0; 578 579 if ((t->flags & v_edge) == 0) 580 dy = 0; 581 if ((t->flags & b_edge) == 0) 582 dx = 0; 583 584 if (dx || dy) 585 wstpad_scroll(tp, dx, dy, magnitude(input, dx, dy), cmds); 586 } 587 588 static inline u_int 589 sbtn(struct wstpad *tp, int x, int y) 590 { 591 if (y >= tp->edge.bottom) 592 return (0); 593 if ((tp->features & WSTPAD_SOFTMBTN) 594 && x >= tp->edge.center_left 595 && x < tp->edge.center_right) 596 return (MIDDLEBTN); 597 return ((x < tp->edge.center ? LEFTBTN : RIGHTBTN) ^ tp->sbtnswap); 598 } 599 600 static inline u_int 601 top_sbtn(struct wstpad *tp, int x, int y) 602 { 603 if (y < tp->edge.top) 604 return (0); 605 if (x < tp->edge.center_left) 606 return (LEFTBTN ^ tp->sbtnswap); 607 return (x > tp->edge.center_right 608 ? (RIGHTBTN ^ tp->sbtnswap) : MIDDLEBTN); 609 } 610 611 u_int 612 wstpad_get_sbtn(struct wsmouseinput *input, int top) 613 { 614 struct wstpad *tp = input->tp; 615 struct tpad_touch *t = tp->t; 616 u_int btn; 617 618 btn = 0; 619 if (tp->contacts) { 620 btn = top ? top_sbtn(tp, t->x, t->y) : sbtn(tp, t->x, t->y); 621 /* 622 * If there is no middle-button area, but contacts in both 623 * halves of the edge zone, generate a middle-button event: 624 */ 625 if (btn && IS_MT(tp) && tp->contacts == 2 626 && !top && !(tp->features & WSTPAD_SOFTMBTN)) { 627 if ((t = get_2nd_touch(input)) != NULL) 628 btn |= sbtn(tp, t->x, t->y); 629 if (btn == (LEFTBTN | RIGHTBTN)) 630 btn = MIDDLEBTN; 631 } 632 } 633 return (btn != PRIMARYBTN ? btn : 0); 634 } 635 636 void 637 wstpad_softbuttons(struct wsmouseinput *input, u_int *cmds, int hdlr) 638 { 639 struct wstpad *tp = input->tp; 640 int top = (hdlr == TOPBUTTON_HDLR); 641 642 if (tp->softbutton && PRIMARYBTN_RELEASED(tp)) { 643 *cmds |= 1 << SOFTBUTTON_UP; 644 return; 645 } 646 647 if (tp->softbutton == 0 && PRIMARYBTN_CLICKED(tp)) { 648 tp->softbutton = wstpad_get_sbtn(input, top); 649 if (tp->softbutton) 650 *cmds |= 1 << SOFTBUTTON_DOWN; 651 } 652 } 653 654 int 655 wstpad_is_tap(struct wstpad *tp, struct tpad_touch *t) 656 { 657 struct timespec ts; 658 659 timespecsub(&tp->time, &t->orig.time, &ts); 660 return (timespeccmp(&ts, &tp->tap.maxtime, <)); 661 } 662 663 /* 664 * At least one MT touch must remain close to its origin and end 665 * in the main area. The same conditions apply to one-finger taps 666 * on single-touch devices. 667 */ 668 void 669 wstpad_tap_filter(struct wstpad *tp, struct tpad_touch *t) 670 { 671 int dx, dy, dist = 0; 672 673 if (IS_MT(tp) || tp->tap.contacts == 1) { 674 dx = abs(t->x - t->orig.x) << 12; 675 dy = abs(t->y - t->orig.y) * tp->ratio; 676 dist = (dx >= dy ? dx + 3 * dy / 8 : dy + 3 * dx / 8); 677 } 678 tp->tap.centered = (CENTERED(t) && dist <= (tp->tap.maxdist << 12)); 679 } 680 681 682 /* 683 * Return the oldest touch in the TOUCH_END state, or NULL. 684 */ 685 struct tpad_touch * 686 wstpad_tap_touch(struct wsmouseinput *input) 687 { 688 struct wstpad *tp = input->tp; 689 struct tpad_touch *s, *t = NULL; 690 u_int lifted; 691 int slot; 692 693 if (IS_MT(tp)) { 694 lifted = (input->mt.sync[MTS_TOUCH] & ~input->mt.touches); 695 FOREACHBIT(lifted, slot) { 696 s = &tp->tpad_touches[slot]; 697 if (tp->tap.state == TAP_DETECT && !tp->tap.centered) 698 wstpad_tap_filter(tp, s); 699 if (t == NULL || timespeccmp(&t->orig.time, 700 &s->orig.time, >)) 701 t = s; 702 } 703 } else { 704 if (tp->t->state == TOUCH_END) { 705 t = tp->t; 706 if (tp->tap.state == TAP_DETECT && !tp->tap.centered) 707 wstpad_tap_filter(tp, t); 708 } 709 } 710 711 return (t); 712 } 713 714 /* 715 * If each contact in a sequence of contacts that overlap in time 716 * is a tap, a button event may be generated when the number of 717 * contacts drops to zero, or to one if there is a masked touch. 718 */ 719 static inline int 720 tap_finished(struct wstpad *tp, int nmasked) 721 { 722 return (tp->contacts == nmasked 723 && (nmasked == 0 || !wstpad_is_tap(tp, tp->t))); 724 } 725 726 static inline u_int 727 tap_btn(struct wstpad *tp, int nmasked) 728 { 729 int n = tp->tap.contacts - nmasked; 730 731 return (n <= TAP_BTNMAP_SIZE ? tp->tap.btnmap[n - 1] : 0); 732 } 733 734 /* 735 * This handler supports one-, two-, and three-finger-taps, which 736 * are mapped to left-button, right-button and middle-button events, 737 * respectively; moreover, it supports tap-and-drag operations with 738 * "locked drags", which are finished by a timeout or a tap-to-end 739 * gesture. 740 */ 741 void 742 wstpad_tap(struct wsmouseinput *input, u_int *cmds) 743 { 744 struct wstpad *tp = input->tp; 745 struct tpad_touch *t; 746 int nmasked, err = 0; 747 748 if (tp->btns) { 749 /* 750 * Don't process tapping while hardware buttons are being 751 * pressed. If the handler is not in its initial state, 752 * release the "tap button". 753 */ 754 if (tp->tap.state > TAP_IGNORE) { 755 timeout_del(&tp->tap.to); 756 *cmds |= 1 << TAPBUTTON_UP; 757 } 758 /* 759 * It might be possible to produce a click within the tap 760 * timeout; ignore the current touch. 761 */ 762 tp->tap.state = TAP_IGNORE; 763 tp->tap.contacts = 0; 764 tp->tap.centered = 0; 765 } 766 767 /* 768 * If a touch from the bottom area is masked, reduce the 769 * contact counts and ignore it. 770 */ 771 nmasked = (input->mt.ptr_mask ? 1 : 0); 772 773 /* 774 * Only touches in the TOUCH_END state are relevant here. 775 * t is NULL if no touch has been lifted. 776 */ 777 t = wstpad_tap_touch(input); 778 779 switch (tp->tap.state) { 780 case TAP_DETECT: 781 if (tp->contacts > tp->tap.contacts) 782 tp->tap.contacts = tp->contacts; 783 784 if (t) { 785 if (wstpad_is_tap(tp, t)) { 786 if (tap_finished(tp, nmasked)) { 787 if (tp->tap.centered) { 788 tp->tap.state = TAP_LIFTED; 789 tp->tap.button = 790 tap_btn(tp, nmasked); 791 } 792 tp->tap.contacts = 0; 793 tp->tap.centered = 0; 794 } 795 } else { 796 if (tp->contacts > nmasked) 797 tp->tap.state = TAP_IGNORE; 798 tp->tap.contacts = 0; 799 tp->tap.centered = 0; 800 } 801 if (tp->tap.state == TAP_LIFTED) { 802 if (tp->tap.button != 0) { 803 *cmds |= 1 << TAPBUTTON_DOWN; 804 err = !timeout_add_msec(&tp->tap.to, 805 tp->tap.clicktime); 806 } else { 807 tp->tap.state = TAP_DETECT; 808 } 809 } 810 } 811 break; 812 813 case TAP_IGNORE: 814 if (tp->contacts == nmasked) 815 tp->tap.state = TAP_DETECT; 816 break; 817 case TAP_LIFTED: 818 if (tp->contacts > nmasked) { 819 timeout_del(&tp->tap.to); 820 if (tp->tap.button == LEFTBTN) { 821 tp->tap.state = TAP_2ND_TOUCH; 822 } else { 823 *cmds |= 1 << TAPBUTTON_UP; 824 tp->tap.state = TAP_DETECT; 825 } 826 } 827 break; 828 case TAP_2ND_TOUCH: 829 if (t) { 830 if (wstpad_is_tap(tp, t)) { 831 *cmds |= 1 << TAPBUTTON_DOUBLECLK; 832 tp->tap.state = TAP_LIFTED; 833 err = !timeout_add_msec(&tp->tap.to, 834 CLICKDELAY_MS); 835 } else if (tp->contacts == nmasked) { 836 if (tp->tap.locktime == 0) { 837 *cmds |= 1 << TAPBUTTON_UP; 838 tp->tap.state = TAP_DETECT; 839 } else { 840 tp->tap.state = TAP_LOCKED; 841 err = !timeout_add_msec(&tp->tap.to, 842 tp->tap.locktime); 843 } 844 } 845 } else if (tp->contacts != nmasked + 1) { 846 *cmds |= 1 << TAPBUTTON_UP; 847 tp->tap.state = TAP_DETECT; 848 } 849 break; 850 case TAP_LOCKED: 851 if (tp->contacts > nmasked) { 852 timeout_del(&tp->tap.to); 853 tp->tap.state = TAP_NTH_TOUCH; 854 } 855 break; 856 case TAP_NTH_TOUCH: 857 if (t) { 858 if (wstpad_is_tap(tp, t)) { 859 /* "tap-to-end" */ 860 *cmds |= 1 << TAPBUTTON_UP; 861 tp->tap.state = TAP_DETECT; 862 } else if (tp->contacts == nmasked) { 863 tp->tap.state = TAP_LOCKED; 864 err = !timeout_add_msec(&tp->tap.to, 865 tp->tap.locktime); 866 } 867 } else if (tp->contacts != nmasked + 1) { 868 *cmds |= 1 << TAPBUTTON_UP; 869 tp->tap.state = TAP_DETECT; 870 } 871 break; 872 } 873 874 if (err) { /* Did timeout_add fail? */ 875 if (tp->tap.state == TAP_LIFTED) 876 *cmds &= ~(1 << TAPBUTTON_DOWN); 877 else 878 *cmds |= 1 << TAPBUTTON_UP; 879 880 tp->tap.state = TAP_DETECT; 881 } 882 } 883 884 void 885 wstpad_tap_timeout(void *p) 886 { 887 struct wsmouseinput *input = p; 888 struct wstpad *tp = input->tp; 889 struct evq_access evq; 890 u_int btn; 891 int s; 892 893 s = spltty(); 894 evq.evar = *input->evar; 895 if (evq.evar != NULL && tp != NULL && 896 (tp->tap.state == TAP_LIFTED || tp->tap.state == TAP_LOCKED)) { 897 tp->tap.state = TAP_DETECT; 898 input->sbtn.buttons &= ~tp->tap.button; 899 btn = ffs(tp->tap.button) - 1; 900 evq.put = evq.evar->put; 901 evq.result = EVQ_RESULT_NONE; 902 getnanotime(&evq.ts); 903 wsmouse_evq_put(&evq, BTN_UP_EV, btn); 904 wsmouse_evq_put(&evq, SYNC_EV, 0); 905 if (evq.result == EVQ_RESULT_SUCCESS) { 906 if (input->flags & LOG_EVENTS) { 907 wsmouse_log_events(input, &evq); 908 } 909 evq.evar->put = evq.put; 910 WSEVENT_WAKEUP(evq.evar); 911 } else { 912 input->sbtn.sync |= tp->tap.button; 913 } 914 } 915 splx(s); 916 } 917 918 /* 919 * Suppress accidental pointer movements after a click on a clickpad. 920 */ 921 void 922 wstpad_click(struct wsmouseinput *input) 923 { 924 struct wstpad *tp = input->tp; 925 926 if (tp->contacts == 1 && 927 (PRIMARYBTN_CLICKED(tp) || PRIMARYBTN_RELEASED(tp))) 928 set_freeze_ts(tp, 0, FREEZE_MS); 929 } 930 931 /* 932 * Translate the "command" bits into the sync-state of wsmouse, or into 933 * wscons events. 934 */ 935 void 936 wstpad_cmds(struct wsmouseinput *input, struct evq_access *evq, u_int cmds) 937 { 938 struct wstpad *tp = input->tp; 939 u_int btn, sbtns_dn = 0, sbtns_up = 0; 940 int n; 941 942 FOREACHBIT(cmds, n) { 943 switch (n) { 944 case CLEAR_MOTION_DELTAS: 945 input->motion.dx = input->motion.dy = 0; 946 if (input->motion.dz == 0 && input->motion.dw == 0) 947 input->motion.sync &= ~SYNC_DELTAS; 948 continue; 949 case SOFTBUTTON_DOWN: 950 input->btn.sync &= ~PRIMARYBTN; 951 sbtns_dn |= tp->softbutton; 952 continue; 953 case SOFTBUTTON_UP: 954 input->btn.sync &= ~PRIMARYBTN; 955 sbtns_up |= tp->softbutton; 956 tp->softbutton = 0; 957 continue; 958 case TAPBUTTON_DOWN: 959 sbtns_dn |= tp->tap.button; 960 continue; 961 case TAPBUTTON_UP: 962 sbtns_up |= tp->tap.button; 963 continue; 964 case TAPBUTTON_DOUBLECLK: 965 /* 966 * We cannot add the final BTN_UP event here, a 967 * delay is required. This is the reason why the 968 * tap handler returns from the 2ND_TOUCH state 969 * into the LIFTED state with a short timeout 970 * (CLICKDELAY_MS). 971 */ 972 btn = ffs(PRIMARYBTN) - 1; 973 wsmouse_evq_put(evq, BTN_UP_EV, btn); 974 wsmouse_evq_put(evq, SYNC_EV, 0); 975 wsmouse_evq_put(evq, BTN_DOWN_EV, btn); 976 continue; 977 case HSCROLL: 978 input->motion.dw = tp->scroll.dw; 979 input->motion.sync |= SYNC_DELTAS; 980 continue; 981 case VSCROLL: 982 input->motion.dz = tp->scroll.dz; 983 input->motion.sync |= SYNC_DELTAS; 984 continue; 985 default: 986 printf("[wstpad] invalid cmd %d\n", n); 987 break; 988 } 989 } 990 if (sbtns_dn || sbtns_up) { 991 input->sbtn.buttons |= sbtns_dn; 992 input->sbtn.buttons &= ~sbtns_up; 993 input->sbtn.sync |= (sbtns_dn | sbtns_up); 994 } 995 } 996 997 998 /* 999 * Set the state of touches that have ended. TOUCH_END is a transitional 1000 * state and will be changed to TOUCH_NONE before process_input() returns. 1001 */ 1002 static inline void 1003 clear_touchstates(struct wsmouseinput *input, enum touchstates state) 1004 { 1005 u_int touches; 1006 int slot; 1007 1008 touches = input->mt.sync[MTS_TOUCH] & ~input->mt.touches; 1009 FOREACHBIT(touches, slot) 1010 input->tp->tpad_touches[slot].state = state; 1011 } 1012 1013 void 1014 wstpad_mt_inputs(struct wsmouseinput *input) 1015 { 1016 struct wstpad *tp = input->tp; 1017 struct tpad_touch *t; 1018 int slot, dx, dy; 1019 u_int touches, inactive; 1020 1021 /* TOUCH_BEGIN */ 1022 touches = input->mt.touches & input->mt.sync[MTS_TOUCH]; 1023 FOREACHBIT(touches, slot) { 1024 t = &tp->tpad_touches[slot]; 1025 t->state = TOUCH_BEGIN; 1026 t->x = normalize_abs(&input->filter.h, t->pos->x); 1027 t->y = normalize_abs(&input->filter.v, t->pos->y); 1028 t->orig.x = t->x; 1029 t->orig.y = t->y; 1030 memcpy(&t->orig.time, &tp->time, sizeof(struct timespec)); 1031 t->flags = edge_flags(tp, t->x, t->y); 1032 wstpad_set_direction(tp, t, 0, 0); 1033 } 1034 1035 /* TOUCH_UPDATE */ 1036 touches = input->mt.touches & input->mt.frame; 1037 if (touches & tp->mtcycle) { 1038 /* 1039 * Slot data may be synchronized separately, in any order, 1040 * or not at all if there is no delta. Identify the touches 1041 * without deltas. 1042 */ 1043 inactive = input->mt.touches & ~tp->mtcycle; 1044 tp->mtcycle = touches; 1045 } else { 1046 inactive = 0; 1047 tp->mtcycle |= touches; 1048 } 1049 touches = input->mt.touches & ~input->mt.sync[MTS_TOUCH]; 1050 FOREACHBIT(touches, slot) { 1051 t = &tp->tpad_touches[slot]; 1052 t->state = TOUCH_UPDATE; 1053 if ((1 << slot) & input->mt.frame) { 1054 dx = normalize_abs(&input->filter.h, t->pos->x) - t->x; 1055 t->x += dx; 1056 dy = normalize_abs(&input->filter.v, t->pos->y) - t->y; 1057 t->y += dy; 1058 t->flags &= (~EDGES | edge_flags(tp, t->x, t->y)); 1059 if (wsmouse_hysteresis(input, t->pos)) 1060 dx = dy = 0; 1061 wstpad_set_direction(tp, t, dx, dy); 1062 } else if ((1 << slot) & inactive) { 1063 wstpad_set_direction(tp, t, 0, 0); 1064 } 1065 } 1066 1067 clear_touchstates(input, TOUCH_END); 1068 } 1069 1070 /* 1071 * Identify "thumb" contacts in the bottom area. The identification 1072 * has three stages: 1073 * 1. If exactly one of two or more touches is in the bottom area, it 1074 * is masked, which means it does not receive pointer control as long 1075 * as there are alternatives. Once set, the mask will only be cleared 1076 * when the touch is released. 1077 * Tap detection ignores a masked touch if it does not participate in 1078 * a tap gesture. 1079 * 2. If the pointer-controlling touch is moving stably while a masked 1080 * touch in the bottom area is resting, or only moving minimally, the 1081 * pointer mask is copied to tp->ignore. In this stage, the masked 1082 * touch does not block pointer movement, and it is ignored by 1083 * wstpad_f2scroll(). 1084 * Decisions are made more or less immediately, there may be errors 1085 * in edge cases. If a fast or long upward movement is detected, 1086 * tp->ignore is cleared. There is no other transition from stage 2 1087 * to scrolling, or vice versa, for a pair of touches. 1088 * 3. If tp->ignore is set and the touch is resting, it is marked as 1089 * thumb, and it will be ignored until it ends. 1090 */ 1091 void 1092 wstpad_mt_masks(struct wsmouseinput *input) 1093 { 1094 struct wstpad *tp = input->tp; 1095 struct tpad_touch *t; 1096 struct position *pos; 1097 u_int mask; 1098 int slot; 1099 1100 tp->ignore &= input->mt.touches; 1101 1102 if (tp->contacts < 2) 1103 return; 1104 1105 if (tp->ignore) { 1106 slot = ffs(tp->ignore) - 1; 1107 t = &tp->tpad_touches[slot]; 1108 if (t->flags & THUMB) 1109 return; 1110 if (t->dir < 0 && wstpad_is_stable(input, t)) { 1111 t->flags |= THUMB; 1112 return; 1113 } 1114 /* The edge.low area is a bit larger than the bottom area. */ 1115 if (t->y >= tp->edge.low || (NORTH(t->dir) && 1116 magnitude(input, t->pos->dx, t->pos->dy) >= MAG_MEDIUM)) 1117 tp->ignore = 0; 1118 return; 1119 } 1120 1121 if (input->mt.ptr_mask == 0) { 1122 mask = ~0; 1123 FOREACHBIT(input->mt.touches, slot) { 1124 t = &tp->tpad_touches[slot]; 1125 if (t->flags & B_EDGE) { 1126 mask &= (1 << slot); 1127 input->mt.ptr_mask = mask; 1128 } 1129 } 1130 } 1131 1132 if ((input->mt.ptr_mask & ~input->mt.ptr) 1133 && !(tp->scroll.dz || tp->scroll.dw) 1134 && tp->t->dir >= 0 1135 && wstpad_is_stable(input, tp->t)) { 1136 1137 slot = ffs(input->mt.ptr_mask) - 1; 1138 t = &tp->tpad_touches[slot]; 1139 1140 if (t->y >= tp->edge.low) 1141 return; 1142 1143 if (!wstpad_is_stable(input, t)) 1144 return; 1145 1146 /* Default hysteresis limits are low. Make a strict check. */ 1147 pos = tp->t->pos; 1148 if (abs(pos->acc_dx) < 3 * input->filter.h.hysteresis 1149 && abs(pos->acc_dy) < 3 * input->filter.v.hysteresis) 1150 return; 1151 1152 if (t->dir >= 0) { 1153 /* Treat t as thumb if it is slow while tp->t is fast. */ 1154 if (magnitude(input, t->pos->dx, t->pos->dy) > MAG_LOW 1155 || magnitude(input, pos->dx, pos->dy) < MAG_MEDIUM) 1156 return; 1157 } 1158 1159 tp->ignore = input->mt.ptr_mask; 1160 } 1161 } 1162 1163 void 1164 wstpad_touch_inputs(struct wsmouseinput *input) 1165 { 1166 struct wstpad *tp = input->tp; 1167 struct tpad_touch *t; 1168 int slot, x, y, dx, dy; 1169 1170 tp->btns = input->btn.buttons; 1171 tp->btns_sync = input->btn.sync; 1172 1173 tp->prev_contacts = tp->contacts; 1174 tp->contacts = input->touch.contacts; 1175 1176 if (tp->contacts == 1 && 1177 ((tp->params.f2width && 1178 input->touch.width >= tp->params.f2width) 1179 || (tp->params.f2pressure && 1180 input->touch.pressure >= tp->params.f2pressure))) 1181 tp->contacts = 2; 1182 1183 if (IS_MT(tp)) { 1184 wstpad_mt_inputs(input); 1185 if (input->mt.ptr) { 1186 slot = ffs(input->mt.ptr) - 1; 1187 tp->t = &tp->tpad_touches[slot]; 1188 } 1189 wstpad_mt_masks(input); 1190 } else { 1191 t = tp->t; 1192 if (tp->contacts) 1193 t->state = (tp->prev_contacts ? 1194 TOUCH_UPDATE : TOUCH_BEGIN); 1195 else 1196 t->state = (tp->prev_contacts ? 1197 TOUCH_END : TOUCH_NONE); 1198 1199 dx = dy = 0; 1200 x = normalize_abs(&input->filter.h, t->pos->x); 1201 y = normalize_abs(&input->filter.v, t->pos->y); 1202 if (t->state == TOUCH_BEGIN) { 1203 t->x = t->orig.x = x; 1204 t->y = t->orig.y = y; 1205 memcpy(&t->orig.time, &tp->time, 1206 sizeof(struct timespec)); 1207 t->flags = edge_flags(tp, x, y); 1208 } else if (input->motion.sync & SYNC_POSITION) { 1209 if (!wsmouse_hysteresis(input, t->pos)) { 1210 dx = x - t->x; 1211 dy = y - t->y; 1212 } 1213 t->x = x; 1214 t->y = y; 1215 t->flags &= (~EDGES | edge_flags(tp, x, y)); 1216 } 1217 wstpad_set_direction(tp, t, dx, dy); 1218 } 1219 } 1220 1221 static inline int 1222 t2_ignore(struct wsmouseinput *input) 1223 { 1224 /* 1225 * If there are two touches, do not block pointer movement if they 1226 * perform a click-and-drag action, or if the second touch is 1227 * resting in the bottom area. 1228 */ 1229 return (input->tp->contacts == 2 && ((input->tp->btns & PRIMARYBTN) 1230 || (input->tp->ignore & ~input->mt.ptr))); 1231 } 1232 1233 void 1234 wstpad_process_input(struct wsmouseinput *input, struct evq_access *evq) 1235 { 1236 struct wstpad *tp = input->tp; 1237 u_int handlers, hdlr, cmds; 1238 1239 memcpy(&tp->time, &evq->ts, sizeof(struct timespec)); 1240 wstpad_touch_inputs(input); 1241 1242 cmds = 0; 1243 handlers = tp->handlers; 1244 if (DISABLE(tp)) 1245 handlers &= ((1 << TOPBUTTON_HDLR) | (1 << SOFTBUTTON_HDLR)); 1246 1247 FOREACHBIT(handlers, hdlr) { 1248 switch (hdlr) { 1249 case SOFTBUTTON_HDLR: 1250 case TOPBUTTON_HDLR: 1251 wstpad_softbuttons(input, &cmds, hdlr); 1252 continue; 1253 case TAP_HDLR: 1254 wstpad_tap(input, &cmds); 1255 continue; 1256 case F2SCROLL_HDLR: 1257 wstpad_f2scroll(input, &cmds); 1258 continue; 1259 case EDGESCROLL_HDLR: 1260 wstpad_edgescroll(input, &cmds); 1261 continue; 1262 case CLICK_HDLR: 1263 wstpad_click(input); 1264 continue; 1265 } 1266 } 1267 1268 /* Check whether pointer movement should be blocked. */ 1269 if (input->motion.dx || input->motion.dy) { 1270 if (DISABLE(tp) 1271 || (tp->t->flags & tp->freeze) 1272 || timespeccmp(&tp->time, &tp->freeze_ts, <) 1273 || (tp->contacts > 1 && !t2_ignore(input))) { 1274 1275 cmds |= 1 << CLEAR_MOTION_DELTAS; 1276 } 1277 } 1278 1279 wstpad_cmds(input, evq, cmds); 1280 1281 if (IS_MT(tp)) 1282 clear_touchstates(input, TOUCH_NONE); 1283 } 1284 1285 /* 1286 * Try to determine the average interval between two updates. Various 1287 * conditions are checked in order to ensure that only valid samples enter 1288 * into the calculation. Above all, it is restricted to motion events 1289 * occurring when there is only one contact. MT devices may need more than 1290 * one packet to transmit their state if there are multiple touches, and 1291 * the update frequency may be higher in this case. 1292 */ 1293 void 1294 wstpad_track_interval(struct wsmouseinput *input, struct timespec *time) 1295 { 1296 static const struct timespec limit = { 0, 30 * 1000000L }; 1297 struct timespec ts; 1298 int samples; 1299 1300 if (input->motion.sync == 0 1301 || (input->touch.sync & SYNC_CONTACTS) 1302 || (input->touch.contacts > 1)) { 1303 input->intv.track = 0; 1304 return; 1305 } 1306 if (input->intv.track) { 1307 timespecsub(time, &input->intv.ts, &ts); 1308 if (timespeccmp(&ts, &limit, <)) { 1309 /* The unit of the sum is 4096 nanoseconds. */ 1310 input->intv.sum += ts.tv_nsec >> 12; 1311 samples = ++input->intv.samples; 1312 /* 1313 * Make the first calculation quickly and later 1314 * a more reliable one: 1315 */ 1316 if (samples == 8) { 1317 input->intv.avg = input->intv.sum << 9; 1318 wstpad_init_deceleration(input); 1319 } else if (samples == 128) { 1320 input->intv.avg = input->intv.sum << 5; 1321 wstpad_init_deceleration(input); 1322 input->intv.samples = 0; 1323 input->intv.sum = 0; 1324 input->flags &= ~TRACK_INTERVAL; 1325 } 1326 } 1327 } 1328 memcpy(&input->intv.ts, time, sizeof(struct timespec)); 1329 input->intv.track = 1; 1330 } 1331 1332 1333 1334 /* 1335 * The default acceleration options of X don't work convincingly with 1336 * touchpads (the synaptics driver installs its own "acceleration 1337 * profile" and callback function). As a preliminary workaround, this 1338 * filter applies a simple deceleration scheme to small deltas, based 1339 * on the "magnitude" of the delta pair. A magnitude of 8 corresponds, 1340 * roughly, to a speed of (filter.dclr / 12.5) device units per milli- 1341 * second. If its magnitude is smaller than 7 a delta will be downscaled 1342 * by the factor 2/8, deltas with magnitudes from 7 to 11 by factors 1343 * ranging from 3/8 to 7/8. 1344 */ 1345 int 1346 wstpad_decelerate(struct wsmouseinput *input, int *dx, int *dy) 1347 { 1348 int mag, n, h, v; 1349 1350 mag = magnitude(input, *dx, *dy); 1351 1352 /* Don't change deceleration levels abruptly. */ 1353 mag = (mag + 7 * input->filter.mag) / 8; 1354 /* Don't use arbitrarily high values. */ 1355 input->filter.mag = imin(mag, 24 << 12); 1356 1357 n = imax((mag >> 12) - 4, 2); 1358 if (n < 8) { 1359 /* Scale by (n / 8). */ 1360 h = *dx * n + input->filter.h.dclr_rmdr; 1361 v = *dy * n + input->filter.v.dclr_rmdr; 1362 input->filter.h.dclr_rmdr = (h >= 0 ? h & 7 : -(-h & 7)); 1363 input->filter.v.dclr_rmdr = (v >= 0 ? v & 7 : -(-v & 7)); 1364 *dx = h / 8; 1365 *dy = v / 8; 1366 return (1); 1367 } 1368 return (0); 1369 } 1370 1371 void 1372 wstpad_filter(struct wsmouseinput *input) 1373 { 1374 struct axis_filter *h = &input->filter.h; 1375 struct axis_filter *v = &input->filter.v; 1376 struct position *pos = &input->motion.pos; 1377 int strength = input->filter.mode & 7; 1378 int dx, dy; 1379 1380 if (!(input->motion.sync & SYNC_POSITION) 1381 || (h->dmax && (abs(pos->dx) > h->dmax)) 1382 || (v->dmax && (abs(pos->dy) > v->dmax))) { 1383 dx = dy = 0; 1384 } else { 1385 dx = pos->dx; 1386 dy = pos->dy; 1387 } 1388 1389 if (wsmouse_hysteresis(input, pos)) 1390 dx = dy = 0; 1391 1392 if (input->filter.dclr && wstpad_decelerate(input, &dx, &dy)) 1393 /* Strong smoothing may hamper the precision at low speeds. */ 1394 strength = imin(strength, 2); 1395 1396 if (strength) { 1397 if ((input->touch.sync & SYNC_CONTACTS) 1398 || input->mt.ptr != input->mt.prev_ptr) { 1399 h->avg = v->avg = 0; 1400 } 1401 /* Use a weighted decaying average for smoothing. */ 1402 dx = dx * (8 - strength) + h->avg * strength + h->avg_rmdr; 1403 dy = dy * (8 - strength) + v->avg * strength + v->avg_rmdr; 1404 h->avg_rmdr = (dx >= 0 ? dx & 7 : -(-dx & 7)); 1405 v->avg_rmdr = (dy >= 0 ? dy & 7 : -(-dy & 7)); 1406 dx = h->avg = dx / 8; 1407 dy = v->avg = dy / 8; 1408 } 1409 1410 input->motion.dx = dx; 1411 input->motion.dy = dy; 1412 } 1413 1414 1415 /* 1416 * Compatibility-mode conversions. wstpad_filter transforms and filters 1417 * the coordinate inputs, extended functionality is provided by 1418 * wstpad_process_input. 1419 */ 1420 void 1421 wstpad_compat_convert(struct wsmouseinput *input, struct evq_access *evq) 1422 { 1423 if (input->flags & TRACK_INTERVAL) 1424 wstpad_track_interval(input, &evq->ts); 1425 1426 wstpad_filter(input); 1427 1428 if ((input->motion.dx || input->motion.dy) 1429 && !(input->motion.sync & SYNC_DELTAS)) { 1430 input->motion.dz = input->motion.dw = 0; 1431 input->motion.sync |= SYNC_DELTAS; 1432 } 1433 1434 if (input->tp != NULL) 1435 wstpad_process_input(input, evq); 1436 1437 input->motion.sync &= ~SYNC_POSITION; 1438 input->touch.sync = 0; 1439 } 1440 1441 int 1442 wstpad_init(struct wsmouseinput *input) 1443 { 1444 struct wstpad *tp = input->tp; 1445 int i, slots; 1446 1447 if (tp != NULL) 1448 return (0); 1449 1450 input->tp = tp = malloc(sizeof(struct wstpad), 1451 M_DEVBUF, M_WAITOK | M_ZERO); 1452 if (tp == NULL) 1453 return (-1); 1454 1455 slots = imax(input->mt.num_slots, 1); 1456 tp->tpad_touches = malloc(slots * sizeof(struct tpad_touch), 1457 M_DEVBUF, M_WAITOK | M_ZERO); 1458 if (tp->tpad_touches == NULL) { 1459 free(tp, M_DEVBUF, sizeof(struct wstpad)); 1460 return (-1); 1461 } 1462 1463 tp->t = &tp->tpad_touches[0]; 1464 if (input->mt.num_slots) { 1465 tp->features |= WSTPAD_MT; 1466 for (i = 0; i < input->mt.num_slots; i++) 1467 tp->tpad_touches[i].pos = &input->mt.slots[i].pos; 1468 } else { 1469 tp->t->pos = &input->motion.pos; 1470 } 1471 1472 timeout_set(&tp->tap.to, wstpad_tap_timeout, input); 1473 1474 tp->ratio = input->filter.ratio; 1475 1476 return (0); 1477 } 1478 1479 /* 1480 * Integer square root (Halleck's method) 1481 * 1482 * An adaption of code from John B. Halleck (from 1483 * http://www.cc.utah.edu/~nahaj/factoring/code.html). This version is 1484 * used and published under the OpenBSD license terms with his permission. 1485 * 1486 * Cf. also Martin Guy's "Square root by abacus" method. 1487 */ 1488 static inline u_int 1489 isqrt(u_int n) 1490 { 1491 u_int root, sqbit; 1492 1493 root = 0; 1494 sqbit = 1 << (sizeof(u_int) * 8 - 2); 1495 while (sqbit) { 1496 if (n >= (sqbit | root)) { 1497 n -= (sqbit | root); 1498 root = (root >> 1) | sqbit; 1499 } else { 1500 root >>= 1; 1501 } 1502 sqbit >>= 2; 1503 } 1504 return (root); 1505 } 1506 1507 void 1508 wstpad_init_deceleration(struct wsmouseinput *input) 1509 { 1510 int n, dclr; 1511 1512 if ((dclr = input->filter.dclr) == 0) 1513 return; 1514 1515 dclr = imax(dclr, 4); 1516 1517 /* 1518 * For a standard update rate of about 80Hz, (dclr) units 1519 * will be mapped to a magnitude of 8. If the average rate 1520 * is significantly higher or lower, adjust the coefficient 1521 * accordingly: 1522 */ 1523 if (input->intv.avg == 0) { 1524 n = 8; 1525 } else { 1526 n = 8 * 13000000 / input->intv.avg; 1527 n = imax(imin(n, 32), 4); 1528 } 1529 input->filter.h.mag_scale = (n << 12) / dclr; 1530 input->filter.v.mag_scale = (input->filter.ratio ? 1531 n * input->filter.ratio : n << 12) / dclr; 1532 input->filter.h.dclr_rmdr = 0; 1533 input->filter.v.dclr_rmdr = 0; 1534 input->flags |= TRACK_INTERVAL; 1535 } 1536 1537 int 1538 wstpad_configure(struct wsmouseinput *input) 1539 { 1540 struct wstpad *tp; 1541 int width, height, diag, offset, h_res, v_res, h_unit, v_unit, i; 1542 1543 width = abs(input->hw.x_max - input->hw.x_min); 1544 height = abs(input->hw.y_max - input->hw.y_min); 1545 if (width == 0 || height == 0) 1546 return (-1); /* We can't do anything. */ 1547 1548 if (input->tp == NULL && wstpad_init(input)) 1549 return (-1); 1550 tp = input->tp; 1551 1552 if (!(input->flags & CONFIGURED)) { 1553 /* 1554 * The filter parameters are derived from the length of the 1555 * diagonal in device units, with some magic constants which 1556 * are partly adapted from libinput or synaptics code, or are 1557 * based on tests and guess work. The absolute resolution 1558 * values might not be reliable, but if they are present the 1559 * settings are adapted to the ratio. 1560 */ 1561 h_res = input->hw.h_res; 1562 v_res = input->hw.v_res; 1563 if (h_res == 0 || v_res == 0) 1564 h_res = v_res = 1; 1565 diag = isqrt(width * width + height * height); 1566 input->filter.h.scale = (imin(920, diag) << 12) / diag; 1567 input->filter.v.scale = input->filter.h.scale * h_res / v_res; 1568 h_unit = imax(diag / 280, 3); 1569 v_unit = imax((h_unit * v_res + h_res / 2) / h_res, 3); 1570 input->filter.h.hysteresis = h_unit; 1571 input->filter.v.hysteresis = v_unit; 1572 input->filter.mode = FILTER_MODE_DEFAULT; 1573 input->filter.dclr = h_unit - h_unit / 5; 1574 wstpad_init_deceleration(input); 1575 1576 tp->features &= (WSTPAD_MT | WSTPAD_DISABLE); 1577 1578 if (input->hw.contacts_max != 1) 1579 tp->features |= WSTPAD_TWOFINGERSCROLL; 1580 else 1581 tp->features |= WSTPAD_EDGESCROLL; 1582 1583 if (input->hw.hw_type == WSMOUSEHW_CLICKPAD) { 1584 if (input->hw.type == WSMOUSE_TYPE_SYNAP_SBTN) { 1585 tp->features |= WSTPAD_TOPBUTTONS; 1586 } else { 1587 tp->features |= WSTPAD_SOFTBUTTONS; 1588 tp->features |= WSTPAD_SOFTMBTN; 1589 } 1590 } 1591 1592 tp->params.left_edge = V_EDGE_RATIO_DEFAULT; 1593 tp->params.right_edge = V_EDGE_RATIO_DEFAULT; 1594 tp->params.bottom_edge = ((tp->features & WSTPAD_SOFTBUTTONS) 1595 ? B_EDGE_RATIO_DEFAULT : 0); 1596 tp->params.top_edge = ((tp->features & WSTPAD_TOPBUTTONS) 1597 ? T_EDGE_RATIO_DEFAULT : 0); 1598 tp->params.center_width = CENTER_RATIO_DEFAULT; 1599 1600 tp->tap.maxtime.tv_nsec = TAP_MAXTIME_DEFAULT * 1000000; 1601 tp->tap.clicktime = TAP_CLICKTIME_DEFAULT; 1602 tp->tap.locktime = TAP_LOCKTIME_DEFAULT; 1603 1604 tp->scroll.hdist = 4 * h_unit; 1605 tp->scroll.vdist = 4 * v_unit; 1606 tp->tap.maxdist = 4 * h_unit; 1607 } 1608 1609 /* A touch with a flag set in this mask does not move the pointer. */ 1610 tp->freeze = EDGES; 1611 1612 offset = width * tp->params.left_edge / 4096; 1613 tp->edge.left = (offset ? input->hw.x_min + offset : INT_MIN); 1614 offset = width * tp->params.right_edge / 4096; 1615 tp->edge.right = (offset ? input->hw.x_max - offset : INT_MAX); 1616 offset = height * tp->params.bottom_edge / 4096; 1617 tp->edge.bottom = (offset ? input->hw.y_min + offset : INT_MIN); 1618 tp->edge.low = tp->edge.bottom + offset / 2; 1619 offset = height * tp->params.top_edge / 4096; 1620 tp->edge.top = (offset ? input->hw.y_max - offset : INT_MAX); 1621 1622 offset = width * abs(tp->params.center_width) / 8192; 1623 tp->edge.center = input->hw.x_min + width / 2; 1624 tp->edge.center_left = tp->edge.center - offset; 1625 tp->edge.center_right = tp->edge.center + offset; 1626 1627 tp->handlers = 0; 1628 1629 if (tp->features & WSTPAD_SOFTBUTTONS) 1630 tp->handlers |= 1 << SOFTBUTTON_HDLR; 1631 if (tp->features & WSTPAD_TOPBUTTONS) 1632 tp->handlers |= 1 << TOPBUTTON_HDLR; 1633 1634 if (tp->features & WSTPAD_TWOFINGERSCROLL) 1635 tp->handlers |= 1 << F2SCROLL_HDLR; 1636 else if (tp->features & WSTPAD_EDGESCROLL) 1637 tp->handlers |= 1 << EDGESCROLL_HDLR; 1638 1639 for (i = 0; i < TAP_BTNMAP_SIZE; i++) { 1640 if (tp->tap.btnmap[i] == 0) 1641 continue; 1642 1643 tp->tap.clicktime = imin(imax(tp->tap.clicktime, 80), 350); 1644 if (tp->tap.locktime) 1645 tp->tap.locktime = 1646 imin(imax(tp->tap.locktime, 150), 5000); 1647 tp->handlers |= 1 << TAP_HDLR; 1648 break; 1649 } 1650 1651 if (input->hw.hw_type == WSMOUSEHW_CLICKPAD) 1652 tp->handlers |= 1 << CLICK_HDLR; 1653 1654 tp->sbtnswap = ((tp->features & WSTPAD_SWAPSIDES) 1655 ? (LEFTBTN | RIGHTBTN) : 0); 1656 1657 return (0); 1658 } 1659 1660 void 1661 wstpad_reset(struct wsmouseinput *input) 1662 { 1663 struct wstpad *tp = input->tp; 1664 1665 if (tp != NULL) { 1666 timeout_del(&tp->tap.to); 1667 tp->tap.state = TAP_DETECT; 1668 } 1669 1670 if (input->sbtn.buttons) { 1671 input->sbtn.sync = input->sbtn.buttons; 1672 input->sbtn.buttons = 0; 1673 } 1674 } 1675 1676 void 1677 wstpad_cleanup(struct wsmouseinput *input) 1678 { 1679 struct wstpad *tp = input->tp; 1680 int slots; 1681 1682 timeout_del(&tp->tap.to); 1683 slots = imax(input->mt.num_slots, 1); 1684 free(tp->tpad_touches, M_DEVBUF, slots * sizeof(struct tpad_touch)); 1685 free(tp, M_DEVBUF, sizeof(struct wstpad)); 1686 input->tp = NULL; 1687 } 1688 1689 int 1690 wstpad_set_param(struct wsmouseinput *input, int key, int val) 1691 { 1692 struct wstpad *tp = input->tp; 1693 u_int flag; 1694 1695 if (tp == NULL) 1696 return (EINVAL); 1697 1698 switch (key) { 1699 case WSMOUSECFG_SOFTBUTTONS ... WSMOUSECFG_DISABLE: 1700 switch (key) { 1701 case WSMOUSECFG_SOFTBUTTONS: 1702 flag = WSTPAD_SOFTBUTTONS; 1703 break; 1704 case WSMOUSECFG_SOFTMBTN: 1705 flag = WSTPAD_SOFTMBTN; 1706 break; 1707 case WSMOUSECFG_TOPBUTTONS: 1708 flag = WSTPAD_TOPBUTTONS; 1709 break; 1710 case WSMOUSECFG_TWOFINGERSCROLL: 1711 flag = WSTPAD_TWOFINGERSCROLL; 1712 break; 1713 case WSMOUSECFG_EDGESCROLL: 1714 flag = WSTPAD_EDGESCROLL; 1715 break; 1716 case WSMOUSECFG_HORIZSCROLL: 1717 flag = WSTPAD_HORIZSCROLL; 1718 break; 1719 case WSMOUSECFG_SWAPSIDES: 1720 flag = WSTPAD_SWAPSIDES; 1721 break; 1722 case WSMOUSECFG_DISABLE: 1723 flag = WSTPAD_DISABLE; 1724 break; 1725 } 1726 if (val) 1727 tp->features |= flag; 1728 else 1729 tp->features &= ~flag; 1730 break; 1731 case WSMOUSECFG_LEFT_EDGE: 1732 tp->params.left_edge = val; 1733 break; 1734 case WSMOUSECFG_RIGHT_EDGE: 1735 tp->params.right_edge = val; 1736 break; 1737 case WSMOUSECFG_TOP_EDGE: 1738 tp->params.top_edge = val; 1739 break; 1740 case WSMOUSECFG_BOTTOM_EDGE: 1741 tp->params.bottom_edge = val; 1742 break; 1743 case WSMOUSECFG_CENTERWIDTH: 1744 tp->params.center_width = val; 1745 break; 1746 case WSMOUSECFG_HORIZSCROLLDIST: 1747 tp->scroll.hdist = val; 1748 break; 1749 case WSMOUSECFG_VERTSCROLLDIST: 1750 tp->scroll.vdist = val; 1751 break; 1752 case WSMOUSECFG_F2WIDTH: 1753 tp->params.f2width = val; 1754 break; 1755 case WSMOUSECFG_F2PRESSURE: 1756 tp->params.f2pressure = val; 1757 break; 1758 case WSMOUSECFG_TAP_MAXTIME: 1759 tp->tap.maxtime.tv_nsec = imin(val, 999) * 1000000; 1760 break; 1761 case WSMOUSECFG_TAP_CLICKTIME: 1762 tp->tap.clicktime = val; 1763 break; 1764 case WSMOUSECFG_TAP_LOCKTIME: 1765 tp->tap.locktime = val; 1766 break; 1767 case WSMOUSECFG_TAP_ONE_BTNMAP: 1768 tp->tap.btnmap[0] = BTNMASK(val); 1769 break; 1770 case WSMOUSECFG_TAP_TWO_BTNMAP: 1771 tp->tap.btnmap[1] = BTNMASK(val); 1772 break; 1773 case WSMOUSECFG_TAP_THREE_BTNMAP: 1774 tp->tap.btnmap[2] = BTNMASK(val); 1775 break; 1776 default: 1777 return (ENOTSUP); 1778 } 1779 1780 return (0); 1781 } 1782 1783 int 1784 wstpad_get_param(struct wsmouseinput *input, int key, int *pval) 1785 { 1786 struct wstpad *tp = input->tp; 1787 u_int flag; 1788 1789 if (tp == NULL) 1790 return (EINVAL); 1791 1792 switch (key) { 1793 case WSMOUSECFG_SOFTBUTTONS ... WSMOUSECFG_DISABLE: 1794 switch (key) { 1795 case WSMOUSECFG_SOFTBUTTONS: 1796 flag = WSTPAD_SOFTBUTTONS; 1797 break; 1798 case WSMOUSECFG_SOFTMBTN: 1799 flag = WSTPAD_SOFTMBTN; 1800 break; 1801 case WSMOUSECFG_TOPBUTTONS: 1802 flag = WSTPAD_TOPBUTTONS; 1803 break; 1804 case WSMOUSECFG_TWOFINGERSCROLL: 1805 flag = WSTPAD_TWOFINGERSCROLL; 1806 break; 1807 case WSMOUSECFG_EDGESCROLL: 1808 flag = WSTPAD_EDGESCROLL; 1809 break; 1810 case WSMOUSECFG_HORIZSCROLL: 1811 flag = WSTPAD_HORIZSCROLL; 1812 break; 1813 case WSMOUSECFG_SWAPSIDES: 1814 flag = WSTPAD_SWAPSIDES; 1815 break; 1816 case WSMOUSECFG_DISABLE: 1817 flag = WSTPAD_DISABLE; 1818 break; 1819 } 1820 *pval = !!(tp->features & flag); 1821 break; 1822 case WSMOUSECFG_LEFT_EDGE: 1823 *pval = tp->params.left_edge; 1824 break; 1825 case WSMOUSECFG_RIGHT_EDGE: 1826 *pval = tp->params.right_edge; 1827 break; 1828 case WSMOUSECFG_TOP_EDGE: 1829 *pval = tp->params.top_edge; 1830 break; 1831 case WSMOUSECFG_BOTTOM_EDGE: 1832 *pval = tp->params.bottom_edge; 1833 break; 1834 case WSMOUSECFG_CENTERWIDTH: 1835 *pval = tp->params.center_width; 1836 break; 1837 case WSMOUSECFG_HORIZSCROLLDIST: 1838 *pval = tp->scroll.hdist; 1839 break; 1840 case WSMOUSECFG_VERTSCROLLDIST: 1841 *pval = tp->scroll.vdist; 1842 break; 1843 case WSMOUSECFG_F2WIDTH: 1844 *pval = tp->params.f2width; 1845 break; 1846 case WSMOUSECFG_F2PRESSURE: 1847 *pval = tp->params.f2pressure; 1848 break; 1849 case WSMOUSECFG_TAP_MAXTIME: 1850 *pval = tp->tap.maxtime.tv_nsec / 1000000; 1851 break; 1852 case WSMOUSECFG_TAP_CLICKTIME: 1853 *pval = tp->tap.clicktime; 1854 break; 1855 case WSMOUSECFG_TAP_LOCKTIME: 1856 *pval = tp->tap.locktime; 1857 break; 1858 case WSMOUSECFG_TAP_ONE_BTNMAP: 1859 *pval = ffs(tp->tap.btnmap[0]); 1860 break; 1861 case WSMOUSECFG_TAP_TWO_BTNMAP: 1862 *pval = ffs(tp->tap.btnmap[1]); 1863 break; 1864 case WSMOUSECFG_TAP_THREE_BTNMAP: 1865 *pval = ffs(tp->tap.btnmap[2]); 1866 break; 1867 default: 1868 return (ENOTSUP); 1869 } 1870 1871 return (0); 1872 } 1873