1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 1997-2000 Kazutaka YOKOTA <yokota@FreeBSD.org>
5 * Copyright (c) 2004-2008 Philip Paeps <philip@FreeBSD.org>
6 * Copyright (c) 2008 Jean-Sebastien Pedron <dumbbell@FreeBSD.org>
7 * Copyright (c) 2021,2024 Vladimir Kondratyev <wulf@FreeBSD.org>
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 /*
32 * MOUSED.C
33 *
34 * Mouse daemon : listens to a evdev device node for mouse data stream,
35 * interprets data and passes ioctls off to the console driver.
36 *
37 */
38
39 #include <sys/param.h>
40 #include <sys/consio.h>
41 #include <sys/event.h>
42 #include <sys/mouse.h>
43 #include <sys/socket.h>
44 #include <sys/time.h>
45 #include <sys/un.h>
46
47 #include <dev/evdev/input.h>
48
49 #include <bitstring.h>
50 #include <ctype.h>
51 #include <dirent.h>
52 #include <err.h>
53 #include <errno.h>
54 #include <fcntl.h>
55 #include <fnmatch.h>
56 #include <libutil.h>
57 #include <math.h>
58 #include <setjmp.h>
59 #include <signal.h>
60 #include <stdarg.h>
61 #include <stdbool.h>
62 #include <stddef.h>
63 #include <stdint.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <syslog.h>
68 #include <unistd.h>
69
70 #include "util.h"
71 #include "quirks.h"
72
73 /*
74 * bitstr_t implementation must be identical to one found in EVIOCG*
75 * libevdev ioctls. Our bitstring(3) API is compatible since r299090.
76 */
77 _Static_assert(sizeof(bitstr_t) == sizeof(unsigned long),
78 "bitstr_t size mismatch");
79
80 #define MAX_CLICKTHRESHOLD 2000 /* 2 seconds */
81 #define MAX_BUTTON2TIMEOUT 2000 /* 2 seconds */
82 #define DFLT_CLICKTHRESHOLD 500 /* 0.5 second */
83 #define DFLT_BUTTON2TIMEOUT 100 /* 0.1 second */
84 #define DFLT_SCROLLTHRESHOLD 3 /* 3 pixels */
85 #define DFLT_SCROLLSPEED 2 /* 2 pixels */
86 #define DFLT_MOUSE_RESOLUTION 8 /* dpmm, == 200dpi */
87 #define DFLT_TPAD_RESOLUTION 40 /* dpmm, typical X res for Synaptics */
88 #define DFLT_LINEHEIGHT 10 /* pixels per line */
89
90 /* Abort 3-button emulation delay after this many movement events. */
91 #define BUTTON2_MAXMOVE 3
92
93 #define MOUSE_XAXIS (-1)
94 #define MOUSE_YAXIS (-2)
95
96 #define ZMAP_MAXBUTTON 4 /* Number of zmap items */
97 #define MAX_FINGERS 10
98
99 #define ID_NONE 0
100 #define ID_PORT 1
101 #define ID_IF 2
102 #define ID_TYPE 4
103 #define ID_MODEL 8
104 #define ID_ALL (ID_PORT | ID_IF | ID_TYPE | ID_MODEL)
105
106 /* Operations on timespecs */
107 #define tsclr(tvp) timespecclear(tvp)
108 #define tscmp(tvp, uvp, cmp) timespeccmp(tvp, uvp, cmp)
109 #define tssub(tvp, uvp, vvp) timespecsub(tvp, uvp, vvp)
110 #define msec2ts(msec) (struct timespec) { \
111 .tv_sec = (msec) / 1000, \
112 .tv_nsec = (msec) % 1000 * 1000000, \
113 }
114 static inline struct timespec
tsaddms(struct timespec * tsp,u_int ms)115 tsaddms(struct timespec* tsp, u_int ms)
116 {
117 struct timespec ret;
118
119 ret = msec2ts(ms);
120 timespecadd(tsp, &ret, &ret);
121
122 return (ret);
123 };
124
125 static inline struct timespec
tssubms(struct timespec * tsp,u_int ms)126 tssubms(struct timespec* tsp, u_int ms)
127 {
128 struct timespec ret;
129
130 ret = msec2ts(ms);
131 timespecsub(tsp, &ret, &ret);
132
133 return (ret);
134 };
135
136 #define debug(...) do { \
137 if (debug && nodaemon) \
138 warnx(__VA_ARGS__); \
139 } while (0)
140
141 #define logerr(e, ...) do { \
142 log_or_warn(LOG_DAEMON | LOG_ERR, errno, __VA_ARGS__); \
143 exit(e); \
144 } while (0)
145
146 #define logerrx(e, ...) do { \
147 log_or_warn(LOG_DAEMON | LOG_ERR, 0, __VA_ARGS__); \
148 exit(e); \
149 } while (0)
150
151 #define logwarn(...) \
152 log_or_warn(LOG_DAEMON | LOG_WARNING, errno, __VA_ARGS__)
153
154 #define logwarnx(...) \
155 log_or_warn(LOG_DAEMON | LOG_WARNING, 0, __VA_ARGS__)
156
157 /* structures */
158
159 enum gesture {
160 GEST_IGNORE,
161 GEST_ACCUMULATE,
162 GEST_MOVE,
163 GEST_VSCROLL,
164 GEST_HSCROLL,
165 };
166
167 /* interfaces (the table must be ordered by DEVICE_IF_XXX in util.h) */
168 static const struct {
169 const char *name;
170 size_t p_size;
171 } rifs[] = {
172 [DEVICE_IF_EVDEV] = { "evdev", sizeof(struct input_event) },
173 [DEVICE_IF_SYSMOUSE] = { "sysmouse", MOUSE_SYS_PACKETSIZE },
174 };
175
176 /* types (the table must be ordered by DEVICE_TYPE_XXX in util.h) */
177 static const char *rnames[] = {
178 [DEVICE_TYPE_MOUSE] = "mouse",
179 [DEVICE_TYPE_POINTINGSTICK] = "pointing stick",
180 [DEVICE_TYPE_TOUCHPAD] = "touchpad",
181 [DEVICE_TYPE_TOUCHSCREEN] = "touchscreen",
182 [DEVICE_TYPE_TABLET] = "tablet",
183 [DEVICE_TYPE_TABLET_PAD] = "tablet pad",
184 [DEVICE_TYPE_KEYBOARD] = "keyboard",
185 [DEVICE_TYPE_JOYSTICK] = "joystick",
186 };
187
188 /* Default phisical to logical button mapping */
189 static const u_int default_p2l[MOUSE_MAXBUTTON] = {
190 MOUSE_BUTTON1DOWN, MOUSE_BUTTON2DOWN, MOUSE_BUTTON3DOWN, MOUSE_BUTTON4DOWN,
191 MOUSE_BUTTON5DOWN, MOUSE_BUTTON6DOWN, MOUSE_BUTTON7DOWN, MOUSE_BUTTON8DOWN,
192 0x00000100, 0x00000200, 0x00000400, 0x00000800,
193 0x00001000, 0x00002000, 0x00004000, 0x00008000,
194 0x00010000, 0x00020000, 0x00040000, 0x00080000,
195 0x00100000, 0x00200000, 0x00400000, 0x00800000,
196 0x01000000, 0x02000000, 0x04000000, 0x08000000,
197 0x10000000, 0x20000000, 0x40000000,
198 };
199
200 struct tpcaps {
201 bool is_clickpad;
202 bool is_topbuttonpad;
203 bool is_mt;
204 bool cap_touch;
205 bool cap_pressure;
206 bool cap_width;
207 int min_x;
208 int max_x;
209 int min_y;
210 int max_y;
211 int res_x; /* dots per mm */
212 int res_y; /* dots per mm */
213 int min_p;
214 int max_p;
215 };
216
217 struct tpinfo {
218 bool two_finger_scroll; /* Enable two finger scrolling */
219 bool natural_scroll; /* Enable natural scrolling */
220 bool three_finger_drag; /* Enable dragging with three fingers */
221 u_int min_pressure_hi; /* Min pressure to start an action */
222 u_int min_pressure_lo; /* Min pressure to continue an action */
223 u_int max_pressure; /* Maximum pressure to detect palm */
224 u_int max_width; /* Max finger width to detect palm */
225 int margin_top; /* Top margin */
226 int margin_right; /* Right margin */
227 int margin_bottom; /* Bottom margin */
228 int margin_left; /* Left margin */
229 u_int tap_timeout; /* */
230 u_int tap_threshold; /* Minimum pressure to detect a tap */
231 double tap_max_delta; /* Length of segments above which a tap is ignored */
232 u_int taphold_timeout; /* Maximum elapsed time between two taps to consider a tap-hold action */
233 double vscroll_ver_area; /* Area reserved for vertical virtual scrolling */
234 double vscroll_hor_area; /* Area reserved for horizontal virtual scrolling */
235 double vscroll_min_delta; /* Minimum movement to consider virtual scrolling */
236 int softbuttons_y; /* Vertical size of softbuttons area */
237 int softbutton2_x; /* Horizontal offset of 2-nd softbutton left edge */
238 int softbutton3_x; /* Horizontal offset of 3-rd softbutton left edge */
239 };
240
241 struct tpstate {
242 int start_x;
243 int start_y;
244 int prev_x;
245 int prev_y;
246 int prev_nfingers;
247 int fingers_nb;
248 int tap_button;
249 bool fingerdown;
250 bool in_taphold;
251 int in_vscroll;
252 u_int zmax; /* maximum pressure value */
253 struct timespec taptimeout; /* tap timeout for touchpads */
254 int idletimeout;
255 bool timer_armed;
256 };
257
258 struct tpad {
259 struct tpcaps hw; /* touchpad capabilities */
260 struct tpinfo info; /* touchpad gesture parameters */
261 struct tpstate gest; /* touchpad gesture state */
262 };
263
264 struct finger {
265 int x;
266 int y;
267 int p;
268 int w;
269 int id; /* id=0 - no touch, id>1 - touch id */
270 };
271
272 struct evstate {
273 int buttons;
274 /* Relative */
275 int dx;
276 int dy;
277 int dz;
278 int dw;
279 int acc_dx;
280 int acc_dy;
281 /* Absolute single-touch */
282 int nfingers;
283 struct finger st;
284 /* Absolute multi-touch */
285 int slot;
286 struct finger mt[MAX_FINGERS];
287 bitstr_t bit_decl(key_ignore, KEY_CNT);
288 bitstr_t bit_decl(rel_ignore, REL_CNT);
289 bitstr_t bit_decl(abs_ignore, ABS_CNT);
290 bitstr_t bit_decl(prop_ignore, INPUT_PROP_CNT);
291 };
292
293 /* button status */
294 struct button_state {
295 int count; /* 0: up, 1: single click, 2: double click,... */
296 struct timespec ts; /* timestamp on the last button event */
297 };
298
299 struct btstate {
300 u_int wmode; /* wheel mode button number */
301 u_int clickthreshold; /* double click speed in msec */
302 struct button_state bstate[MOUSE_MAXBUTTON]; /* button state */
303 struct button_state *mstate[MOUSE_MAXBUTTON];/* mapped button st.*/
304 u_int p2l[MOUSE_MAXBUTTON];/* phisical to logical button mapping */
305 int zmap[ZMAP_MAXBUTTON];/* MOUSE_{X|Y}AXIS or a button number */
306 struct button_state zstate[ZMAP_MAXBUTTON]; /* Z/W axis state */
307 };
308
309 /* state machine for 3 button emulation */
310
311 enum bt3_emul_state {
312 S0, /* start */
313 S1, /* button 1 delayed down */
314 S2, /* button 3 delayed down */
315 S3, /* both buttons down -> button 2 down */
316 S4, /* button 1 delayed up */
317 S5, /* button 1 down */
318 S6, /* button 3 down */
319 S7, /* both buttons down */
320 S8, /* button 3 delayed up */
321 S9, /* button 1 or 3 up after S3 */
322 };
323
324 #define A(b1, b3) (((b1) ? 2 : 0) | ((b3) ? 1 : 0))
325 #define A_TIMEOUT 4
326 #define S_DELAYED(st) (states[st].s[A_TIMEOUT] != (st))
327
328 static const struct {
329 enum bt3_emul_state s[A_TIMEOUT + 1];
330 int buttons;
331 int mask;
332 bool timeout;
333 } states[10] = {
334 /* S0 */
335 { { S0, S2, S1, S3, S0 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), false },
336 /* S1 */
337 { { S4, S2, S1, S3, S5 }, 0, ~MOUSE_BUTTON1DOWN, false },
338 /* S2 */
339 { { S8, S2, S1, S3, S6 }, 0, ~MOUSE_BUTTON3DOWN, false },
340 /* S3 */
341 { { S0, S9, S9, S3, S3 }, MOUSE_BUTTON2DOWN, ~0, false },
342 /* S4 */
343 { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON1DOWN, ~0, true },
344 /* S5 */
345 { { S0, S2, S5, S7, S5 }, MOUSE_BUTTON1DOWN, ~0, false },
346 /* S6 */
347 { { S0, S6, S1, S7, S6 }, MOUSE_BUTTON3DOWN, ~0, false },
348 /* S7 */
349 { { S0, S6, S5, S7, S7 }, MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, ~0, false },
350 /* S8 */
351 { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON3DOWN, ~0, true },
352 /* S9 */
353 { { S0, S9, S9, S3, S9 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), false },
354 };
355
356 struct e3bstate {
357 bool enabled;
358 u_int button2timeout; /* 3 button emulation timeout */
359 enum bt3_emul_state mouse_button_state;
360 struct timespec mouse_button_state_ts;
361 int mouse_move_delayed;
362 bool timer_armed;
363 };
364
365 enum scroll_state {
366 SCROLL_NOTSCROLLING,
367 SCROLL_PREPARE,
368 SCROLL_SCROLLING,
369 };
370
371 struct scroll {
372 bool enable_vert;
373 bool enable_hor;
374 u_int threshold; /* Movement distance before virtual scrolling */
375 u_int speed; /* Movement distance to rate of scrolling */
376 enum scroll_state state;
377 int movement;
378 int hmovement;
379 };
380
381 struct drift_xy {
382 int x;
383 int y;
384 };
385 struct drift {
386 u_int distance; /* max steps X+Y */
387 u_int time; /* ms */
388 struct timespec time_ts;
389 struct timespec twotime_ts; /* 2*drift_time */
390 u_int after; /* ms */
391 struct timespec after_ts;
392 bool terminate;
393 struct timespec current_ts;
394 struct timespec last_activity;
395 struct timespec since;
396 struct drift_xy last; /* steps in last drift_time */
397 struct drift_xy previous; /* steps in prev. drift_time */
398 };
399
400 struct accel {
401 bool is_exponential; /* Exponential acceleration is enabled */
402 double accelx; /* Acceleration in the X axis */
403 double accely; /* Acceleration in the Y axis */
404 double accelz; /* Acceleration in the wheel axis */
405 double expoaccel; /* Exponential acceleration */
406 double expoffset; /* Movement offset for exponential accel. */
407 double remainx; /* Remainder on X, Y and wheel axis, ... */
408 double remainy; /* ... respectively to compensate */
409 double remainz; /* ... for rounding errors. */
410 double lastlength[3];
411 };
412
413 struct rodent {
414 struct device dev; /* Device */
415 int mfd; /* mouse file descriptor */
416 struct btstate btstate; /* button status */
417 struct e3bstate e3b; /* 3 button emulation state */
418 struct drift drift;
419 struct accel accel; /* cursor acceleration state */
420 struct scroll scroll; /* virtual scroll state */
421 struct tpad tp; /* touchpad info and gesture state */
422 struct evstate ev; /* event device state */
423 SLIST_ENTRY(rodent) next;
424 };
425
426 /* global variables */
427
428 static SLIST_HEAD(rodent_list, rodent) rodents = SLIST_HEAD_INITIALIZER();
429
430 static int debug = 0;
431 static bool nodaemon = false;
432 static bool background = false;
433 static bool paused = false;
434 static bool opt_grab = false;
435 static int identify = ID_NONE;
436 static int cfd = -1; /* /dev/consolectl file descriptor */
437 static int kfd = -1; /* kqueue file descriptor */
438 static int dfd = -1; /* devd socket descriptor */
439 static const char *portname = NULL;
440 static const char *pidfile = "/var/run/moused.pid";
441 static struct pidfh *pfh;
442 #ifndef CONFDIR
443 #define CONFDIR "/etc"
444 #endif
445 static const char *config_file = CONFDIR "/moused.conf";
446 #ifndef QUIRKSDIR
447 #define QUIRKSDIR "/usr/share/moused"
448 #endif
449 static const char *quirks_path = QUIRKSDIR;
450 static struct quirks_context *quirks;
451
452 static int opt_rate = 0;
453 static int opt_resolution = MOUSE_RES_UNKNOWN;
454
455 static u_int opt_wmode = 0;
456 static int opt_clickthreshold = -1;
457 static bool opt_e3b_enabled = false;
458 static int opt_e3b_button2timeout = -1;
459 static struct btstate opt_btstate;
460
461 static bool opt_drift_terminate = false;
462 static u_int opt_drift_distance = 4; /* max steps X+Y */
463 static u_int opt_drift_time = 500; /* ms */
464 static u_int opt_drift_after = 4000; /* ms */
465
466 static double opt_accelx = 1.0;
467 static double opt_accely = 1.0;
468 static bool opt_exp_accel = false;
469 static double opt_expoaccel = 1.0;
470 static double opt_expoffset = 1.0;
471
472 static bool opt_virtual_scroll = false;
473 static bool opt_hvirtual_scroll = false;
474 static int opt_scroll_speed = -1;
475 static int opt_scroll_threshold = -1;
476
477 static jmp_buf env;
478
479 /* function prototypes */
480
481 static moused_log_handler log_or_warn_va;
482
483 static void linacc(struct accel *, int, int, int, int*, int*, int*);
484 static void expoacc(struct accel *, int, int, int, int*, int*, int*);
485 static void moused(void);
486 static void reset(int sig);
487 static void pause_mouse(int sig);
488 static int connect_devd(void);
489 static void fetch_and_parse_devd(void);
490 static void usage(void);
491 static void log_or_warn(int log_pri, int errnum, const char *fmt, ...)
492 __printflike(3, 4);
493
494 static int r_daemon(void);
495 static enum device_if r_identify_if(int fd);
496 static enum device_type r_identify_evdev(int fd);
497 static enum device_type r_identify_sysmouse(int fd);
498 static const char *r_if(enum device_if type);
499 static const char *r_name(enum device_type type);
500 static struct rodent *r_init(const char *path);
501 static void r_init_all(void);
502 static void r_deinit(struct rodent *r);
503 static void r_deinit_all(void);
504 static int r_protocol_evdev(enum device_type type, struct tpad *tp,
505 struct evstate *ev, struct input_event *ie,
506 mousestatus_t *act);
507 static int r_protocol_sysmouse(uint8_t *pBuf, mousestatus_t *act);
508 static void r_vscroll_detect(struct rodent *r, struct scroll *sc,
509 mousestatus_t *act);
510 static void r_vscroll(struct scroll *sc, mousestatus_t *act);
511 static int r_statetrans(struct rodent *r, mousestatus_t *a1,
512 mousestatus_t *a2, int trans);
513 static bool r_installmap(char *arg, struct btstate *bt);
514 static char * r_installzmap(char **argv, int argc, int* idx, struct btstate *bt);
515 static void r_map(mousestatus_t *act1, mousestatus_t *act2,
516 struct btstate *bt);
517 static void r_timestamp(mousestatus_t *act, struct btstate *bt,
518 struct e3bstate *e3b, struct drift *drift);
519 static bool r_timeout(struct e3bstate *e3b);
520 static void r_move(mousestatus_t *act, struct accel *acc);
521 static void r_click(mousestatus_t *act, struct btstate *bt);
522 static bool r_drift(struct drift *, mousestatus_t *);
523 static enum gesture r_gestures(struct tpad *tp, int x0, int y0, u_int z, int w,
524 int nfingers, struct timespec *time, mousestatus_t *ms);
525
526 int
main(int argc,char * argv[])527 main(int argc, char *argv[])
528 {
529 struct rodent *r;
530 pid_t mpid;
531 int c;
532 int i;
533 u_long ul;
534 char *errstr;
535
536 while ((c = getopt(argc, argv, "3A:C:E:F:HI:L:T:VU:a:dfghi:l:m:p:r:t:q:w:z:")) != -1) {
537 switch(c) {
538
539 case '3':
540 opt_e3b_enabled = true;
541 break;
542
543 case 'E':
544 errno = 0;
545 ul = strtoul(optarg, NULL, 10);
546 if ((ul == 0 && errno != 0) ||
547 ul > MAX_BUTTON2TIMEOUT) {
548 warnx("invalid argument `%s'", optarg);
549 usage();
550 }
551 opt_e3b_button2timeout = ul;
552 break;
553
554 case 'a':
555 i = sscanf(optarg, "%lf,%lf", &opt_accelx, &opt_accely);
556 if (i == 0) {
557 warnx("invalid linear acceleration argument "
558 "'%s'", optarg);
559 usage();
560 }
561 if (i == 1)
562 opt_accely = opt_accelx;
563 break;
564
565 case 'A':
566 opt_exp_accel = true;
567 i = sscanf(optarg, "%lf,%lf", &opt_expoaccel,
568 &opt_expoffset);
569 if (i == 0) {
570 warnx("invalid exponential acceleration "
571 "argument '%s'", optarg);
572 usage();
573 }
574 if (i == 1)
575 opt_expoffset = 1.0;
576 break;
577
578 case 'd':
579 ++debug;
580 break;
581
582 case 'f':
583 nodaemon = true;
584 break;
585
586 case 'g':
587 opt_grab = true;
588 break;
589
590 case 'i':
591 if (strcmp(optarg, "all") == 0)
592 identify = ID_ALL;
593 else if (strcmp(optarg, "port") == 0)
594 identify = ID_PORT;
595 else if (strcmp(optarg, "if") == 0)
596 identify = ID_IF;
597 else if (strcmp(optarg, "type") == 0)
598 identify = ID_TYPE;
599 else if (strcmp(optarg, "model") == 0)
600 identify = ID_MODEL;
601 else {
602 warnx("invalid argument `%s'", optarg);
603 usage();
604 }
605 nodaemon = true;
606 break;
607
608 case 'l':
609 ul = strtoul(optarg, NULL, 10);
610 if (ul != 1)
611 warnx("ignore mouse level `%s'", optarg);
612 break;
613
614 case 'm':
615 if (!r_installmap(optarg, &opt_btstate)) {
616 warnx("invalid argument `%s'", optarg);
617 usage();
618 }
619 break;
620
621 case 'p':
622 /* "auto" is an alias to no portname */
623 if (strcmp(optarg, "auto") != 0)
624 portname = optarg;
625 break;
626
627 case 'r':
628 if (strcmp(optarg, "high") == 0)
629 opt_resolution = MOUSE_RES_HIGH;
630 else if (strcmp(optarg, "medium-high") == 0)
631 opt_resolution = MOUSE_RES_HIGH;
632 else if (strcmp(optarg, "medium-low") == 0)
633 opt_resolution = MOUSE_RES_MEDIUMLOW;
634 else if (strcmp(optarg, "low") == 0)
635 opt_resolution = MOUSE_RES_LOW;
636 else if (strcmp(optarg, "default") == 0)
637 opt_resolution = MOUSE_RES_DEFAULT;
638 else {
639 ul= strtoul(optarg, NULL, 10);
640 if (ul == 0) {
641 warnx("invalid argument `%s'", optarg);
642 usage();
643 }
644 opt_resolution = ul;
645 }
646 break;
647
648 case 't':
649 if (strcmp(optarg, "auto") != 0)
650 warnx("ignore mouse type `%s'", optarg);
651 break;
652
653 case 'w':
654 ul = strtoul(optarg, NULL, 10);
655 if (ul == 0 || ul > MOUSE_MAXBUTTON) {
656 warnx("invalid argument `%s'", optarg);
657 usage();
658 }
659 opt_wmode = ul;
660 break;
661
662 case 'z':
663 --optind;
664 errstr = r_installzmap(argv, argc, &optind, &opt_btstate);
665 if (errstr != NULL) {
666 warnx("%s", errstr);
667 free(errstr);
668 usage();
669 }
670 break;
671
672 case 'C':
673 ul = strtoul(optarg, NULL, 10);
674 if (ul > MAX_CLICKTHRESHOLD) {
675 warnx("invalid argument `%s'", optarg);
676 usage();
677 }
678 opt_clickthreshold = ul;
679 break;
680
681 case 'F':
682 ul = strtoul(optarg, NULL, 10);
683 if (ul == 0) {
684 warnx("invalid argument `%s'", optarg);
685 usage();
686 }
687 opt_rate = ul;
688 break;
689
690 case 'H':
691 opt_hvirtual_scroll = true;
692 break;
693
694 case 'I':
695 pidfile = optarg;
696 break;
697
698 case 'L':
699 errno = 0;
700 ul = strtoul(optarg, NULL, 10);
701 if ((ul == 0 && errno != 0) || ul > INT_MAX) {
702 warnx("invalid argument `%s'", optarg);
703 usage();
704 }
705 opt_scroll_speed = ul;
706 break;
707
708 case 'q':
709 config_file = optarg;
710 break;
711
712 case 'Q':
713 quirks_path = optarg;
714 break;
715
716 case 'T':
717 opt_drift_terminate = true;
718 sscanf(optarg, "%u,%u,%u", &opt_drift_distance,
719 &opt_drift_time, &opt_drift_after);
720 if (opt_drift_distance == 0 ||
721 opt_drift_time == 0 ||
722 opt_drift_after == 0) {
723 warnx("invalid argument `%s'", optarg);
724 usage();
725 }
726 break;
727
728 case 'V':
729 opt_virtual_scroll = true;
730 break;
731
732 case 'U':
733 errno = 0;
734 ul = strtoul(optarg, NULL, 10);
735 if ((ul == 0 && errno != 0) || ul > INT_MAX) {
736 warnx("invalid argument `%s'", optarg);
737 usage();
738 }
739 opt_scroll_threshold = ul;
740 break;
741
742 case 'h':
743 case '?':
744 default:
745 usage();
746 }
747 }
748
749 if ((cfd = open("/dev/consolectl", O_RDWR, 0)) == -1)
750 logerr(1, "cannot open /dev/consolectl");
751 if ((kfd = kqueue()) == -1)
752 logerr(1, "cannot create kqueue");
753 if (portname == NULL && (dfd = connect_devd()) == -1)
754 logwarnx("cannot open devd socket");
755
756 switch (setjmp(env)) {
757 case SIGHUP:
758 quirks_context_unref(quirks);
759 r_deinit_all();
760 /* FALLTHROUGH */
761 case 0:
762 break;
763 case SIGINT:
764 case SIGQUIT:
765 case SIGTERM:
766 exit(0);
767 /* NOT REACHED */
768 default:
769 goto out;
770 }
771
772 signal(SIGHUP , reset);
773 signal(SIGINT , reset);
774 signal(SIGQUIT, reset);
775 signal(SIGTERM, reset);
776 signal(SIGUSR1, pause_mouse);
777
778 quirks = quirks_init_subsystem(quirks_path, config_file,
779 log_or_warn_va,
780 background ? QLOG_MOUSED_LOGGING : QLOG_CUSTOM_LOG_PRIORITIES);
781 if (quirks == NULL)
782 logwarnx("cannot open configuration file %s", config_file);
783
784 if (portname == NULL) {
785 r_init_all();
786 } else {
787 if ((r = r_init(portname)) == NULL)
788 logerrx(1, "Can not initialize device");
789 }
790
791 /* print some information */
792 if (identify != ID_NONE) {
793 SLIST_FOREACH(r, &rodents, next) {
794 if (identify == ID_ALL)
795 printf("%s %s %s %s\n",
796 r->dev.path, r_if(r->dev.iftype),
797 r_name(r->dev.type), r->dev.name);
798 else if (identify & ID_PORT)
799 printf("%s\n", r->dev.path);
800 else if (identify & ID_IF)
801 printf("%s\n", r_if(r->dev.iftype));
802 else if (identify & ID_TYPE)
803 printf("%s\n", r_name(r->dev.type));
804 else if (identify & ID_MODEL)
805 printf("%s\n", r->dev.name);
806 }
807 exit(0);
808 }
809
810 if (!nodaemon && !background) {
811 pfh = pidfile_open(pidfile, 0600, &mpid);
812 if (pfh == NULL) {
813 if (errno == EEXIST)
814 logerrx(1, "moused already running, pid: %d", mpid);
815 logwarn("cannot open pid file");
816 }
817 if (r_daemon()) {
818 int saved_errno = errno;
819 pidfile_remove(pfh);
820 errno = saved_errno;
821 logerr(1, "failed to become a daemon");
822 } else {
823 background = true;
824 pidfile_write(pfh);
825 }
826 }
827
828 moused();
829
830 out:
831 quirks_context_unref(quirks);
832
833 r_deinit_all();
834 if (dfd != -1)
835 close(dfd);
836 if (kfd != -1)
837 close(kfd);
838 if (cfd != -1)
839 close(cfd);
840
841 exit(0);
842 }
843
844 /*
845 * Function to calculate linear acceleration.
846 *
847 * If there are any rounding errors, the remainder
848 * is stored in the remainx and remainy variables
849 * and taken into account upon the next movement.
850 */
851
852 static void
linacc(struct accel * acc,int dx,int dy,int dz,int * movex,int * movey,int * movez)853 linacc(struct accel *acc, int dx, int dy, int dz,
854 int *movex, int *movey, int *movez)
855 {
856 double fdx, fdy, fdz;
857
858 if (dx == 0 && dy == 0 && dz == 0) {
859 *movex = *movey = *movez = 0;
860 return;
861 }
862 fdx = dx * acc->accelx + acc->remainx;
863 fdy = dy * acc->accely + acc->remainy;
864 fdz = dz * acc->accelz + acc->remainz;
865 *movex = lround(fdx);
866 *movey = lround(fdy);
867 *movez = lround(fdz);
868 acc->remainx = fdx - *movex;
869 acc->remainy = fdy - *movey;
870 acc->remainz = fdz - *movez;
871 }
872
873 /*
874 * Function to calculate exponential acceleration.
875 * (Also includes linear acceleration if enabled.)
876 *
877 * In order to give a smoother behaviour, we record the four
878 * most recent non-zero movements and use their average value
879 * to calculate the acceleration.
880 */
881
882 static void
expoacc(struct accel * acc,int dx,int dy,int dz,int * movex,int * movey,int * movez)883 expoacc(struct accel *acc, int dx, int dy, int dz,
884 int *movex, int *movey, int *movez)
885 {
886 double fdx, fdy, fdz, length, lbase, accel;
887
888 if (dx == 0 && dy == 0 && dz == 0) {
889 *movex = *movey = *movez = 0;
890 return;
891 }
892 fdx = dx * acc->accelx;
893 fdy = dy * acc->accely;
894 fdz = dz * acc->accelz;
895 length = sqrt((fdx * fdx) + (fdy * fdy)); /* Pythagoras */
896 length = (length + acc->lastlength[0] + acc->lastlength[1] +
897 acc->lastlength[2]) / 4;
898 lbase = length / acc->expoffset;
899 accel = pow(lbase, acc->expoaccel) / lbase;
900 fdx = fdx * accel + acc->remainx;
901 fdy = fdy * accel + acc->remainy;
902 *movex = lround(fdx);
903 *movey = lround(fdy);
904 *movez = lround(fdz);
905 acc->remainx = fdx - *movex;
906 acc->remainy = fdy - *movey;
907 acc->remainz = fdz - *movez;
908 acc->lastlength[2] = acc->lastlength[1];
909 acc->lastlength[1] = acc->lastlength[0];
910 /* Insert new average, not original length! */
911 acc->lastlength[0] = length;
912 }
913
914 static void
moused(void)915 moused(void)
916 {
917 struct rodent *r = NULL;
918 mousestatus_t action0; /* original mouse action */
919 mousestatus_t action; /* interim buffer */
920 mousestatus_t action2; /* mapped action */
921 struct kevent ke[3];
922 int nchanges;
923 union {
924 struct input_event ie;
925 uint8_t se[MOUSE_SYS_PACKETSIZE];
926 } b;
927 size_t b_size;
928 ssize_t r_size;
929 int flags;
930 int c;
931
932 /* clear mouse data */
933 bzero(&action0, sizeof(action0));
934 bzero(&action, sizeof(action));
935 bzero(&action2, sizeof(action2));
936 /* process mouse data */
937 for (;;) {
938
939 if (dfd == -1 && portname == NULL)
940 dfd = connect_devd();
941 nchanges = 0;
942 if (r != NULL && r->e3b.enabled &&
943 S_DELAYED(r->e3b.mouse_button_state)) {
944 EV_SET(ke + nchanges, r->mfd << 1, EVFILT_TIMER,
945 EV_ADD | EV_ENABLE | EV_DISPATCH, 0, 20, r);
946 nchanges++;
947 r->e3b.timer_armed = true;
948 }
949 if (r != NULL && r->tp.gest.idletimeout > 0) {
950 EV_SET(ke + nchanges, r->mfd << 1 | 1, EVFILT_TIMER,
951 EV_ADD | EV_ENABLE | EV_DISPATCH,
952 0, r->tp.gest.idletimeout, r);
953 nchanges++;
954 r->tp.gest.timer_armed = true;
955 }
956 if (dfd == -1 && nchanges == 0 && portname == NULL) {
957 EV_SET(ke + nchanges, UINTPTR_MAX, EVFILT_TIMER,
958 EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 1000, NULL);
959 nchanges++;
960 }
961
962 if (!(r != NULL && r->tp.gest.idletimeout == 0)) {
963 c = kevent(kfd, ke, nchanges, ke, 1, NULL);
964 if (c <= 0) { /* error */
965 logwarn("failed to read from mouse");
966 continue;
967 }
968 } else
969 c = 0;
970 /* Devd event */
971 if (c > 0 && ke[0].udata == NULL) {
972 if (ke[0].filter == EVFILT_READ) {
973 if ((ke[0].flags & EV_EOF) != 0) {
974 logwarn("devd connection is closed");
975 close(dfd);
976 dfd = -1;
977 } else
978 fetch_and_parse_devd();
979 } else if (ke[0].filter == EVFILT_TIMER) {
980 /* DO NOTHING */
981 }
982 continue;
983 }
984 if (c > 0)
985 r = ke[0].udata;
986 /* E3B timeout */
987 if (c > 0 && ke[0].filter == EVFILT_TIMER &&
988 (ke[0].ident & 1) == 0) {
989 /* assert(rodent.flags & Emulate3Button) */
990 action0.button = action0.obutton;
991 action0.dx = action0.dy = action0.dz = 0;
992 action0.flags = flags = 0;
993 r->e3b.timer_armed = false;
994 if (r_timeout(&r->e3b) &&
995 r_statetrans(r, &action0, &action, A_TIMEOUT)) {
996 if (debug > 2)
997 debug("flags:%08x buttons:%08x obuttons:%08x",
998 action.flags, action.button, action.obutton);
999 } else {
1000 action0.obutton = action0.button;
1001 continue;
1002 }
1003 } else {
1004 /* mouse movement */
1005 if (c > 0 && ke[0].filter == EVFILT_READ) {
1006 b_size = rifs[r->dev.iftype].p_size;
1007 r_size = read(r->mfd, &b, b_size);
1008 if (r_size == -1) {
1009 if (errno == EWOULDBLOCK)
1010 continue;
1011 else if (portname == NULL) {
1012 r_deinit(r);
1013 r = NULL;
1014 continue;
1015 } else
1016 return;
1017 }
1018 if (r_size != (ssize_t)b_size) {
1019 logwarn("Short read from mouse: "
1020 "%zd bytes", r_size);
1021 continue;
1022 }
1023 /* Disarm nonexpired timers */
1024 nchanges = 0;
1025 if (r->e3b.timer_armed) {
1026 EV_SET(ke + nchanges, r->mfd << 1,
1027 EVFILT_TIMER, EV_DISABLE, 0, 0, r);
1028 nchanges++;
1029 r->e3b.timer_armed = false;
1030 }
1031 if (r->tp.gest.timer_armed) {
1032 EV_SET(ke + nchanges, r->mfd << 1 | 1,
1033 EVFILT_TIMER, EV_DISABLE, 0, 0, r);
1034 nchanges++;
1035 r->tp.gest.timer_armed = false;
1036 }
1037 if (nchanges != 0)
1038 kevent(kfd, ke, nchanges, NULL, 0, NULL);
1039 } else {
1040 /*
1041 * Gesture timeout expired.
1042 * Notify r_gestures by empty packet.
1043 */
1044 #ifdef DONE_RIGHT
1045 struct timespec ts;
1046 clock_gettime(CLOCK_REALTIME, &ts);
1047 b.ie.time.tv_sec = ts.tv_sec;
1048 b.ie.time.tv_usec = ts.tv_nsec / 1000;
1049 #else
1050 /* Hacky but cheap */
1051 b.ie.time.tv_sec =
1052 r->tp.gest.idletimeout == 0 ? 0 : LONG_MAX;
1053 b.ie.time.tv_usec = 0;
1054 #endif
1055 b.ie.type = EV_SYN;
1056 b.ie.code = SYN_REPORT;
1057 b.ie.value = 1;
1058 if (c > 0)
1059 r->tp.gest.timer_armed = false;
1060 }
1061 r->tp.gest.idletimeout = -1;
1062 flags = r->dev.iftype == DEVICE_IF_EVDEV ?
1063 r_protocol_evdev(r->dev.type,
1064 &r->tp, &r->ev, &b.ie, &action0) :
1065 r_protocol_sysmouse(b.se, &action0);
1066 if (flags == 0)
1067 continue;
1068
1069 if (r->scroll.enable_vert || r->scroll.enable_hor) {
1070 if (action0.button == MOUSE_BUTTON2DOWN) {
1071 debug("[BUTTON2] flags:%08x buttons:%08x obuttons:%08x",
1072 action.flags, action.button, action.obutton);
1073 } else {
1074 debug("[NOTBUTTON2] flags:%08x buttons:%08x obuttons:%08x",
1075 action.flags, action.button, action.obutton);
1076 }
1077 r_vscroll_detect(r, &r->scroll, &action0);
1078 }
1079
1080 r_timestamp(&action0, &r->btstate, &r->e3b, &r->drift);
1081 r_statetrans(r, &action0, &action,
1082 A(action0.button & MOUSE_BUTTON1DOWN,
1083 action0.button & MOUSE_BUTTON3DOWN));
1084 debug("flags:%08x buttons:%08x obuttons:%08x", action.flags,
1085 action.button, action.obutton);
1086 }
1087 action0.obutton = action0.button;
1088 flags &= MOUSE_POSCHANGED;
1089 flags |= action.obutton ^ action.button;
1090 action.flags = flags;
1091
1092 if (flags == 0)
1093 continue;
1094
1095 /* handler detected action */
1096 r_map(&action, &action2, &r->btstate);
1097 debug("activity : buttons 0x%08x dx %d dy %d dz %d",
1098 action2.button, action2.dx, action2.dy, action2.dz);
1099
1100 if (r->scroll.enable_vert || r->scroll.enable_hor) {
1101 /*
1102 * If *only* the middle button is pressed AND we are moving
1103 * the stick/trackpoint/nipple, scroll!
1104 */
1105 r_vscroll(&r->scroll, &action2);
1106 }
1107
1108 if (r->drift.terminate) {
1109 if ((flags & MOUSE_POSCHANGED) == 0 ||
1110 action.dz || action2.dz)
1111 r->drift.last_activity = r->drift.current_ts;
1112 else {
1113 if (r_drift (&r->drift, &action2))
1114 continue;
1115 }
1116 }
1117
1118 /* Defer clicks until we aren't VirtualScroll'ing. */
1119 if (r->scroll.state == SCROLL_NOTSCROLLING)
1120 r_click(&action2, &r->btstate);
1121
1122 if (action2.flags & MOUSE_POSCHANGED)
1123 r_move(&action2, &r->accel);
1124
1125 /*
1126 * If the Z axis movement is mapped to an imaginary physical
1127 * button, we need to cook up a corresponding button `up' event
1128 * after sending a button `down' event.
1129 */
1130 if ((r->btstate.zmap[0] > 0) && (action.dz != 0)) {
1131 action.obutton = action.button;
1132 action.dx = action.dy = action.dz = 0;
1133 r_map(&action, &action2, &r->btstate);
1134 debug("activity : buttons 0x%08x dx %d dy %d dz %d",
1135 action2.button, action2.dx, action2.dy, action2.dz);
1136
1137 r_click(&action2, &r->btstate);
1138 }
1139 }
1140 /* NOT REACHED */
1141 }
1142
1143 static void
reset(int sig)1144 reset(int sig)
1145 {
1146 longjmp(env, sig);
1147 }
1148
1149 static void
pause_mouse(__unused int sig)1150 pause_mouse(__unused int sig)
1151 {
1152 paused = !paused;
1153 }
1154
1155 static int
connect_devd(void)1156 connect_devd(void)
1157 {
1158 const static struct sockaddr_un sa = {
1159 .sun_family = AF_UNIX,
1160 .sun_path = "/var/run/devd.seqpacket.pipe",
1161 };
1162 struct kevent kev;
1163 int fd;
1164
1165 fd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
1166 if (fd < 0)
1167 return (-1);
1168 if (connect(fd, (const struct sockaddr *) &sa, sizeof(sa)) < 0) {
1169 close(fd);
1170 return (-1);
1171 }
1172 EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
1173 if (kevent(kfd, &kev, 1, NULL, 0, NULL) < 0) {
1174 close(fd);
1175 return (-1);
1176 }
1177
1178 return (fd);
1179 }
1180
1181 static void
fetch_and_parse_devd(void)1182 fetch_and_parse_devd(void)
1183 {
1184 char ev[1024];
1185 char path[22] = "/dev/";
1186 char *cdev, *cr;
1187 ssize_t len;
1188
1189 if ((len = recv(dfd, ev, sizeof(ev), MSG_WAITALL)) <= 0) {
1190 close(dfd);
1191 dfd = -1;
1192 return;
1193 }
1194
1195 if (ev[0] != '!')
1196 return;
1197 if (strnstr(ev, "system=DEVFS", len) == NULL)
1198 return;
1199 if (strnstr(ev, "subsystem=CDEV", len) == NULL)
1200 return;
1201 if (strnstr(ev, "type=CREATE", len) == NULL)
1202 return;
1203 if ((cdev = strnstr(ev, "cdev=input/event", len)) == NULL)
1204 return;
1205 cr = strchr(cdev, '\n');
1206 if (cr != NULL)
1207 *cr = '\0';
1208 cr = strchr(cdev, ' ');
1209 if (cr != NULL)
1210 *cr = '\0';
1211 strncpy(path + 5, cdev + 5, 17);
1212 (void)r_init(path);
1213 return;
1214 }
1215
1216 /*
1217 * usage
1218 *
1219 * Complain, and free the CPU for more worthy tasks
1220 */
1221 static void
usage(void)1222 usage(void)
1223 {
1224 fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
1225 "usage: moused [-dfg] [-I file] [-F rate] [-r resolution]",
1226 " [-VH [-U threshold]] [-a X[,Y]] [-C threshold] [-m N=M] [-w N]",
1227 " [-z N] [-t <mousetype>] [-l level] [-3 [-E timeout]]",
1228 " [-T distance[,time[,after]]] -p <port> [-q config] [-Q quirks]",
1229 " moused [-d] -i <port|if|type|model|all> -p <port>");
1230 exit(1);
1231 }
1232
1233 /*
1234 * Output an error message to syslog or stderr as appropriate. If
1235 * `errnum' is non-zero, append its string form to the message.
1236 */
1237 static void
log_or_warn_va(int log_pri,int errnum,const char * fmt,va_list ap)1238 log_or_warn_va(int log_pri, int errnum, const char *fmt, va_list ap)
1239 {
1240 char buf[256];
1241 size_t len;
1242
1243 if (debug == 0 && log_pri > LOG_ERR)
1244 return;
1245
1246 vsnprintf(buf, sizeof(buf), fmt, ap);
1247
1248 /* Strip trailing line-feed appended by quirk subsystem */
1249 len = strlen(buf);
1250 if (len != 0 && buf[len - 1] == '\n')
1251 buf[len - 1] = '\0';
1252
1253 if (errnum) {
1254 strlcat(buf, ": ", sizeof(buf));
1255 strlcat(buf, strerror(errnum), sizeof(buf));
1256 }
1257
1258 if (background)
1259 syslog(log_pri, "%s", buf);
1260 else
1261 warnx("%s", buf);
1262 }
1263
1264 static void
log_or_warn(int log_pri,int errnum,const char * fmt,...)1265 log_or_warn(int log_pri, int errnum, const char *fmt, ...)
1266 {
1267 va_list ap;
1268
1269 va_start(ap, fmt);
1270 log_or_warn_va(log_pri, errnum, fmt, ap);
1271 va_end(ap);
1272 }
1273
1274 static int
r_daemon(void)1275 r_daemon(void)
1276 {
1277 struct sigaction osa, sa;
1278 pid_t newgrp;
1279 int oerrno;
1280 int osa_ok;
1281 int nullfd;
1282
1283 /* A SIGHUP may be thrown when the parent exits below. */
1284 sigemptyset(&sa.sa_mask);
1285 sa.sa_handler = SIG_IGN;
1286 sa.sa_flags = 0;
1287 osa_ok = sigaction(SIGHUP, &sa, &osa);
1288
1289 /* Keep kqueue fd alive */
1290 switch (rfork(RFPROC)) {
1291 case -1:
1292 return (-1);
1293 case 0:
1294 break;
1295 default:
1296 /*
1297 * A fine point: _exit(0), not exit(0), to avoid triggering
1298 * atexit(3) processing
1299 */
1300 _exit(0);
1301 }
1302
1303 newgrp = setsid();
1304 oerrno = errno;
1305 if (osa_ok != -1)
1306 sigaction(SIGHUP, &osa, NULL);
1307
1308 if (newgrp == -1) {
1309 errno = oerrno;
1310 return (-1);
1311 }
1312
1313 (void)chdir("/");
1314
1315 nullfd = open("/dev/null", O_RDWR, 0);
1316 if (nullfd != -1) {
1317 (void)dup2(nullfd, STDIN_FILENO);
1318 (void)dup2(nullfd, STDOUT_FILENO);
1319 (void)dup2(nullfd, STDERR_FILENO);
1320 }
1321 if (nullfd > 2)
1322 close(nullfd);
1323
1324 return (0);
1325 }
1326
1327 static inline int
bit_find(bitstr_t * array,int start,int stop)1328 bit_find(bitstr_t *array, int start, int stop)
1329 {
1330 int res;
1331
1332 bit_ffs_at(array, start, stop + 1, &res);
1333 return (res != -1);
1334 }
1335
1336 static enum device_if
r_identify_if(int fd)1337 r_identify_if(int fd)
1338 {
1339 int dummy;
1340
1341 if (ioctl(fd, EVIOCGVERSION, &dummy) >= 0)
1342 return (DEVICE_IF_EVDEV);
1343 if (ioctl(fd, MOUSE_GETLEVEL, &dummy) >= 0)
1344 return (DEVICE_IF_SYSMOUSE);
1345 return (DEVICE_IF_UNKNOWN);
1346 }
1347
1348 /* Derived from EvdevProbe() function of xf86-input-evdev driver */
1349 static enum device_type
r_identify_evdev(int fd)1350 r_identify_evdev(int fd)
1351 {
1352 enum device_type type;
1353 bitstr_t bit_decl(key_bits, KEY_CNT); /* */
1354 bitstr_t bit_decl(rel_bits, REL_CNT); /* Evdev capabilities */
1355 bitstr_t bit_decl(abs_bits, ABS_CNT); /* */
1356 bitstr_t bit_decl(prop_bits, INPUT_PROP_CNT);
1357 bool has_keys, has_buttons, has_lmr, has_rel_axes, has_abs_axes;
1358 bool has_mt;
1359
1360 /* maybe this is a evdev mouse... */
1361 if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), rel_bits) < 0 ||
1362 ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits) < 0 ||
1363 ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits) < 0 ||
1364 ioctl(fd, EVIOCGPROP(sizeof(prop_bits)), prop_bits) < 0) {
1365 return (DEVICE_TYPE_UNKNOWN);
1366 }
1367
1368 has_keys = bit_find(key_bits, 0, BTN_MISC - 1);
1369 has_buttons = bit_find(key_bits, BTN_MISC, BTN_JOYSTICK - 1);
1370 has_lmr = bit_find(key_bits, BTN_LEFT, BTN_MIDDLE);
1371 has_rel_axes = bit_find(rel_bits, 0, REL_MAX);
1372 has_abs_axes = bit_find(abs_bits, 0, ABS_MAX);
1373 has_mt = bit_find(abs_bits, ABS_MT_SLOT, ABS_MAX);
1374 type = DEVICE_TYPE_UNKNOWN;
1375
1376 if (has_abs_axes) {
1377 if (has_mt && !has_buttons) {
1378 /* TBD:Improve joystick detection */
1379 if (bit_test(key_bits, BTN_JOYSTICK)) {
1380 return (DEVICE_TYPE_JOYSTICK);
1381 } else {
1382 has_buttons = true;
1383 }
1384 }
1385
1386 if (bit_test(abs_bits, ABS_X) &&
1387 bit_test(abs_bits, ABS_Y)) {
1388 if (bit_test(key_bits, BTN_TOOL_PEN) ||
1389 bit_test(key_bits, BTN_STYLUS) ||
1390 bit_test(key_bits, BTN_STYLUS2)) {
1391 type = DEVICE_TYPE_TABLET;
1392 } else if (bit_test(abs_bits, ABS_PRESSURE) ||
1393 bit_test(key_bits, BTN_TOUCH)) {
1394 if (has_lmr ||
1395 bit_test(key_bits, BTN_TOOL_FINGER)) {
1396 type = DEVICE_TYPE_TOUCHPAD;
1397 } else {
1398 type = DEVICE_TYPE_TOUCHSCREEN;
1399 }
1400 /* some touchscreens use BTN_LEFT rather than BTN_TOUCH */
1401 } else if (!(bit_test(rel_bits, REL_X) &&
1402 bit_test(rel_bits, REL_Y)) &&
1403 has_lmr) {
1404 type = DEVICE_TYPE_TOUCHSCREEN;
1405 }
1406 }
1407 }
1408
1409 if (type == DEVICE_TYPE_UNKNOWN) {
1410 if (has_keys)
1411 type = DEVICE_TYPE_KEYBOARD;
1412 else if (has_rel_axes || has_buttons)
1413 type = DEVICE_TYPE_MOUSE;
1414 }
1415
1416 return (type);
1417 }
1418
1419 static enum device_type
r_identify_sysmouse(int fd __unused)1420 r_identify_sysmouse(int fd __unused)
1421 {
1422 /* All sysmouse devices act like mices */
1423 return (DEVICE_TYPE_MOUSE);
1424 }
1425
1426 static const char *
r_if(enum device_if type)1427 r_if(enum device_if type)
1428 {
1429 const char *unknown = "unknown";
1430
1431 return (type == DEVICE_IF_UNKNOWN || type >= (int)nitems(rifs) ?
1432 unknown : rifs[type].name);
1433 }
1434
1435 static const char *
r_name(enum device_type type)1436 r_name(enum device_type type)
1437 {
1438 const char *unknown = "unknown";
1439
1440 return (type == DEVICE_TYPE_UNKNOWN || type >= (int)nitems(rnames) ?
1441 unknown : rnames[type]);
1442 }
1443
1444 static int
r_init_dev_evdev(int fd,struct device * dev)1445 r_init_dev_evdev(int fd, struct device *dev)
1446 {
1447 if (ioctl(fd, EVIOCGNAME(sizeof(dev->name) - 1), dev->name) < 0) {
1448 logwarnx("unable to get device %s name", dev->path);
1449 return (errno);
1450 }
1451 /* Do not loop events */
1452 if (strncmp(dev->name, "System mouse", sizeof(dev->name)) == 0) {
1453 return (ENOTSUP);
1454 }
1455 if (ioctl(fd, EVIOCGID, &dev->id) < 0) {
1456 logwarnx("unable to get device %s ID", dev->path);
1457 return (errno);
1458 }
1459 (void)ioctl(fd, EVIOCGUNIQ(sizeof(dev->uniq) - 1), dev->uniq);
1460
1461 return (0);
1462 }
1463
1464 static int
r_init_dev_sysmouse(int fd,struct device * dev)1465 r_init_dev_sysmouse(int fd, struct device *dev)
1466 {
1467 mousemode_t *mode = &dev->mode;
1468 int level;
1469
1470 level = 1;
1471 if (ioctl(fd, MOUSE_SETLEVEL, &level) < 0) {
1472 logwarnx("unable to MOUSE_SETLEVEL for device %s", dev->path);
1473 return (errno);
1474 }
1475 if (ioctl(fd, MOUSE_GETLEVEL, &level) < 0) {
1476 logwarnx("unable to MOUSE_GETLEVEL for device %s", dev->path);
1477 return (errno);
1478 }
1479 if (level != 1) {
1480 logwarnx("unable to set level to 1 for device %s", dev->path);
1481 return (ENOTSUP);
1482 }
1483 memset(mode, 0, sizeof(*mode));
1484 if (ioctl(fd, MOUSE_GETMODE, mode) < 0) {
1485 logwarnx("unable to MOUSE_GETMODE for device %s", dev->path);
1486 return (errno);
1487 }
1488 if (mode->protocol != MOUSE_PROTO_SYSMOUSE) {
1489 logwarnx("unable to set sysmouse protocol for device %s",
1490 dev->path);
1491 return (ENOTSUP);
1492 }
1493 if (mode->packetsize != MOUSE_SYS_PACKETSIZE) {
1494 logwarnx("unable to set sysmouse packet size for device %s",
1495 dev->path);
1496 return (ENOTSUP);
1497 }
1498
1499 /* TODO: Fill name, id and uniq from dev.* sysctls */
1500 strlcpy(dev->name, dev->path, sizeof(dev->name));
1501
1502 return (0);
1503 }
1504
1505 static void
r_init_evstate(struct quirks * q,struct evstate * ev)1506 r_init_evstate(struct quirks *q, struct evstate *ev)
1507 {
1508 const struct quirk_tuples *t;
1509 bitstr_t *bitstr;
1510 int maxbit;
1511
1512 if (quirks_get_tuples(q, QUIRK_ATTR_EVENT_CODE, &t)) {
1513 for (size_t i = 0; i < t->ntuples; i++) {
1514 int type = t->tuples[i].first;
1515 int code = t->tuples[i].second;
1516 bool enable = t->tuples[i].third;
1517
1518 switch (type) {
1519 case EV_KEY:
1520 bitstr = (bitstr_t *)&ev->key_ignore;
1521 maxbit = KEY_MAX;
1522 break;
1523 case EV_REL:
1524 bitstr = (bitstr_t *)&ev->rel_ignore;
1525 maxbit = REL_MAX;
1526 break;
1527 case EV_ABS:
1528 bitstr = (bitstr_t *)&ev->abs_ignore;
1529 maxbit = ABS_MAX;
1530 break;
1531 default:
1532 continue;
1533 }
1534
1535 if (code == EVENT_CODE_UNDEFINED) {
1536 if (enable)
1537 bit_nclear(bitstr, 0, maxbit);
1538 else
1539 bit_nset(bitstr, 0, maxbit);
1540 } else {
1541 if (code > maxbit)
1542 continue;
1543 if (enable)
1544 bit_clear(bitstr, code);
1545 else
1546 bit_set(bitstr, code);
1547 }
1548 }
1549 }
1550
1551 if (quirks_get_tuples(q, QUIRK_ATTR_INPUT_PROP, &t)) {
1552 for (size_t idx = 0; idx < t->ntuples; idx++) {
1553 unsigned int p = t->tuples[idx].first;
1554 bool enable = t->tuples[idx].second;
1555
1556 if (p > INPUT_PROP_MAX)
1557 continue;
1558 if (enable)
1559 bit_clear(ev->prop_ignore, p);
1560 else
1561 bit_set(ev->prop_ignore, p);
1562 }
1563 }
1564 }
1565
1566 static void
r_init_buttons(struct quirks * q,struct btstate * bt,struct e3bstate * e3b)1567 r_init_buttons(struct quirks *q, struct btstate *bt, struct e3bstate *e3b)
1568 {
1569 struct timespec ts;
1570 int i, j;
1571
1572 *bt = (struct btstate) {
1573 .clickthreshold = DFLT_CLICKTHRESHOLD,
1574 .zmap = { 0, 0, 0, 0 },
1575 };
1576
1577 memcpy(bt->p2l, default_p2l, sizeof(bt->p2l));
1578 for (i = 0; i < MOUSE_MAXBUTTON; ++i) {
1579 j = i;
1580 if (opt_btstate.p2l[i] != 0)
1581 bt->p2l[i] = opt_btstate.p2l[i];
1582 if (opt_btstate.mstate[i] != NULL)
1583 j = opt_btstate.mstate[i] - opt_btstate.bstate;
1584 bt->mstate[i] = bt->bstate + j;
1585 }
1586
1587 if (opt_btstate.zmap[0] != 0)
1588 memcpy(bt->zmap, opt_btstate.zmap, sizeof(bt->zmap));
1589 if (opt_clickthreshold >= 0)
1590 bt->clickthreshold = opt_clickthreshold;
1591 else
1592 quirks_get_uint32(q, MOUSED_CLICK_THRESHOLD, &bt->clickthreshold);
1593 if (opt_wmode != 0)
1594 bt->wmode = opt_wmode;
1595 else
1596 quirks_get_uint32(q, MOUSED_WMODE, &bt->wmode);
1597 if (bt->wmode != 0)
1598 bt->wmode = 1 << (bt->wmode - 1);
1599
1600 /* fix Z axis mapping */
1601 for (i = 0; i < ZMAP_MAXBUTTON; ++i) {
1602 if (bt->zmap[i] <= 0)
1603 continue;
1604 for (j = 0; j < MOUSE_MAXBUTTON; ++j) {
1605 if (bt->mstate[j] == &bt->bstate[bt->zmap[i] - 1])
1606 bt->mstate[j] = &bt->zstate[i];
1607 }
1608 bt->zmap[i] = 1 << (bt->zmap[i] - 1);
1609 }
1610
1611 clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
1612
1613 *e3b = (struct e3bstate) {
1614 .enabled = false,
1615 .button2timeout = DFLT_BUTTON2TIMEOUT,
1616 };
1617 e3b->enabled = opt_e3b_enabled;
1618 if (!e3b->enabled)
1619 quirks_get_bool(q, MOUSED_EMULATE_THIRD_BUTTON, &e3b->enabled);
1620 if (opt_e3b_button2timeout >= 0)
1621 e3b->button2timeout = opt_e3b_button2timeout;
1622 else
1623 quirks_get_uint32(q, MOUSED_EMULATE_THIRD_BUTTON_TIMEOUT,
1624 &e3b->button2timeout);
1625 e3b->mouse_button_state = S0;
1626 e3b->mouse_button_state_ts = ts;
1627 e3b->mouse_move_delayed = 0;
1628
1629 for (i = 0; i < MOUSE_MAXBUTTON; ++i) {
1630 bt->bstate[i].count = 0;
1631 bt->bstate[i].ts = ts;
1632 }
1633 for (i = 0; i < ZMAP_MAXBUTTON; ++i) {
1634 bt->zstate[i].count = 0;
1635 bt->zstate[i].ts = ts;
1636 }
1637 }
1638
1639 static void
r_init_touchpad_hw(int fd,struct quirks * q,struct tpcaps * tphw,struct evstate * ev)1640 r_init_touchpad_hw(int fd, struct quirks *q, struct tpcaps *tphw,
1641 struct evstate *ev)
1642 {
1643 struct input_absinfo ai;
1644 bitstr_t bit_decl(key_bits, KEY_CNT);
1645 bitstr_t bit_decl(abs_bits, ABS_CNT);
1646 bitstr_t bit_decl(prop_bits, INPUT_PROP_CNT);
1647 struct quirk_range r;
1648 struct quirk_dimensions dim;
1649 u_int u;
1650
1651 ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
1652 ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits);
1653
1654 if (!bit_test(ev->abs_ignore, ABS_X) &&
1655 ioctl(fd, EVIOCGABS(ABS_X), &ai) >= 0) {
1656 tphw->min_x = (ai.maximum > ai.minimum) ? ai.minimum : INT_MIN;
1657 tphw->max_x = (ai.maximum > ai.minimum) ? ai.maximum : INT_MAX;
1658 tphw->res_x = ai.resolution == 0 ?
1659 DFLT_TPAD_RESOLUTION : ai.resolution;
1660 }
1661 if (!bit_test(ev->abs_ignore, ABS_Y) &&
1662 ioctl(fd, EVIOCGABS(ABS_Y), &ai) >= 0) {
1663 tphw->min_y = (ai.maximum > ai.minimum) ? ai.minimum : INT_MIN;
1664 tphw->max_y = (ai.maximum > ai.minimum) ? ai.maximum : INT_MAX;
1665 tphw->res_y = ai.resolution == 0 ?
1666 DFLT_TPAD_RESOLUTION : ai.resolution;
1667 }
1668 if (quirks_get_dimensions(q, QUIRK_ATTR_RESOLUTION_HINT, &dim)) {
1669 tphw->res_x = dim.x;
1670 tphw->res_y = dim.y;
1671 } else if (tphw->max_x != INT_MAX && tphw->max_y != INT_MAX &&
1672 quirks_get_dimensions(q, QUIRK_ATTR_SIZE_HINT, &dim)) {
1673 tphw->res_x = (tphw->max_x - tphw->min_x) / dim.x;
1674 tphw->res_y = (tphw->max_y - tphw->min_y) / dim.y;
1675 }
1676 if (!bit_test(ev->key_ignore, BTN_TOUCH) &&
1677 bit_test(key_bits, BTN_TOUCH))
1678 tphw->cap_touch = true;
1679 /* XXX: libinput uses ABS_MT_PRESSURE where available */
1680 if (!bit_test(ev->abs_ignore, ABS_PRESSURE) &&
1681 bit_test(abs_bits, ABS_PRESSURE) &&
1682 ioctl(fd, EVIOCGABS(ABS_PRESSURE), &ai) >= 0) {
1683 tphw->cap_pressure = true;
1684 tphw->min_p = ai.minimum;
1685 tphw->max_p = ai.maximum;
1686 }
1687 if (tphw->cap_pressure &&
1688 quirks_get_range(q, QUIRK_ATTR_PRESSURE_RANGE, &r)) {
1689 if (r.upper == 0 && r.lower == 0) {
1690 debug("pressure-based touch detection disabled");
1691 tphw->cap_pressure = false;
1692 } else if (r.upper > tphw->max_p || r.upper < tphw->min_p ||
1693 r.lower > tphw->max_p || r.lower < tphw->min_p) {
1694 debug("discarding out-of-bounds pressure range %d:%d",
1695 r.lower, r.upper);
1696 tphw->cap_pressure = false;
1697 }
1698 }
1699 /* XXX: libinput uses ABS_MT_TOUCH_MAJOR where available */
1700 if (!bit_test(ev->abs_ignore, ABS_TOOL_WIDTH) &&
1701 bit_test(abs_bits, ABS_TOOL_WIDTH) &&
1702 quirks_get_uint32(q, QUIRK_ATTR_PALM_SIZE_THRESHOLD, &u) &&
1703 u != 0)
1704 tphw->cap_width = true;
1705 if (!bit_test(ev->abs_ignore, ABS_MT_SLOT) &&
1706 bit_test(abs_bits, ABS_MT_SLOT) &&
1707 !bit_test(ev->abs_ignore, ABS_MT_TRACKING_ID) &&
1708 bit_test(abs_bits, ABS_MT_TRACKING_ID) &&
1709 !bit_test(ev->abs_ignore, ABS_MT_POSITION_X) &&
1710 bit_test(abs_bits, ABS_MT_POSITION_X) &&
1711 !bit_test(ev->abs_ignore, ABS_MT_POSITION_Y) &&
1712 bit_test(abs_bits, ABS_MT_POSITION_Y))
1713 tphw->is_mt = true;
1714 if ( ioctl(fd, EVIOCGPROP(sizeof(prop_bits)), prop_bits) >= 0 &&
1715 !bit_test(ev->prop_ignore, INPUT_PROP_BUTTONPAD) &&
1716 bit_test(prop_bits, INPUT_PROP_BUTTONPAD))
1717 tphw->is_clickpad = true;
1718 if ( tphw->is_clickpad &&
1719 !bit_test(ev->prop_ignore, INPUT_PROP_TOPBUTTONPAD) &&
1720 bit_test(prop_bits, INPUT_PROP_TOPBUTTONPAD))
1721 tphw->is_topbuttonpad = true;
1722 }
1723
1724 static void
r_init_touchpad_info(struct quirks * q,struct tpcaps * tphw,struct tpinfo * tpinfo)1725 r_init_touchpad_info(struct quirks *q, struct tpcaps *tphw,
1726 struct tpinfo *tpinfo)
1727 {
1728 struct quirk_range r;
1729 int i;
1730 u_int u;
1731 int sz_x, sz_y;
1732
1733 *tpinfo = (struct tpinfo) {
1734 .two_finger_scroll = true,
1735 .natural_scroll = false,
1736 .three_finger_drag = false,
1737 .min_pressure_hi = 1,
1738 .min_pressure_lo = 1,
1739 .max_pressure = 130,
1740 .max_width = 16,
1741 .tap_timeout = 180, /* ms */
1742 .tap_threshold = 0,
1743 .tap_max_delta = 1.3, /* mm */
1744 .taphold_timeout = 300, /* ms */
1745 .vscroll_min_delta = 1.25, /* mm */
1746 .vscroll_hor_area = 0.0, /* mm */
1747 .vscroll_ver_area = -15.0, /* mm */
1748 };
1749
1750 quirks_get_bool(q, MOUSED_TWO_FINGER_SCROLL, &tpinfo->two_finger_scroll);
1751 quirks_get_bool(q, MOUSED_NATURAL_SCROLL, &tpinfo->natural_scroll);
1752 quirks_get_bool(q, MOUSED_THREE_FINGER_DRAG, &tpinfo->three_finger_drag);
1753 quirks_get_uint32(q, MOUSED_TAP_TIMEOUT, &tpinfo->tap_timeout);
1754 quirks_get_double(q, MOUSED_TAP_MAX_DELTA, &tpinfo->tap_max_delta);
1755 quirks_get_uint32(q, MOUSED_TAPHOLD_TIMEOUT, &tpinfo->taphold_timeout);
1756 quirks_get_double(q, MOUSED_VSCROLL_MIN_DELTA, &tpinfo->vscroll_min_delta);
1757 quirks_get_double(q, MOUSED_VSCROLL_HOR_AREA, &tpinfo->vscroll_hor_area);
1758 quirks_get_double(q, MOUSED_VSCROLL_VER_AREA, &tpinfo->vscroll_ver_area);
1759
1760 if (tphw->cap_pressure &&
1761 quirks_get_range(q, QUIRK_ATTR_PRESSURE_RANGE, &r)) {
1762 tpinfo->min_pressure_lo = r.lower;
1763 tpinfo->min_pressure_hi = r.upper;
1764 quirks_get_uint32(q, QUIRK_ATTR_PALM_PRESSURE_THRESHOLD,
1765 &tpinfo->max_pressure);
1766 quirks_get_uint32(q, MOUSED_TAP_PRESSURE_THRESHOLD,
1767 &tpinfo->tap_threshold);
1768 }
1769 if (tphw->cap_width)
1770 quirks_get_uint32(q, QUIRK_ATTR_PALM_SIZE_THRESHOLD,
1771 &tpinfo->max_width);
1772 /* Set bottom quarter as 42% - 16% - 42% sized softbuttons */
1773 if (tphw->is_clickpad) {
1774 sz_x = tphw->max_x - tphw->min_x;
1775 sz_y = tphw->max_y - tphw->min_y;
1776 i = 25;
1777 if (tphw->is_topbuttonpad)
1778 i = -i;
1779 quirks_get_int32(q, MOUSED_SOFTBUTTONS_Y, &i);
1780 tpinfo->softbuttons_y = sz_y * i / 100;
1781 u = 42;
1782 quirks_get_uint32(q, MOUSED_SOFTBUTTON2_X, &u);
1783 tpinfo->softbutton2_x = sz_x * u / 100;
1784 u = 58;
1785 quirks_get_uint32(q, MOUSED_SOFTBUTTON3_X, &u);
1786 tpinfo->softbutton3_x = sz_x * u / 100;
1787 }
1788 }
1789
1790 static void
r_init_touchpad_accel(struct tpcaps * tphw,struct accel * accel)1791 r_init_touchpad_accel(struct tpcaps *tphw, struct accel *accel)
1792 {
1793 /* Normalize pointer movement to match 200dpi mouse */
1794 accel->accelx *= DFLT_MOUSE_RESOLUTION;
1795 accel->accelx /= tphw->res_x;
1796 accel->accely *= DFLT_MOUSE_RESOLUTION;
1797 accel->accely /= tphw->res_y;
1798 accel->accelz *= DFLT_MOUSE_RESOLUTION;
1799 accel->accelz /= (tphw->res_x * DFLT_LINEHEIGHT);
1800 }
1801
1802 static void
r_init_touchpad_gesture(struct tpstate * gest)1803 r_init_touchpad_gesture(struct tpstate *gest)
1804 {
1805 gest->idletimeout = -1;
1806 }
1807
1808 static void
r_init_drift(struct quirks * q,struct drift * d)1809 r_init_drift(struct quirks *q, struct drift *d)
1810 {
1811 if (opt_drift_terminate) {
1812 d->terminate = true;
1813 d->distance = opt_drift_distance;
1814 d->time = opt_drift_time;
1815 d->after = opt_drift_after;
1816 } else if (quirks_get_bool(q, MOUSED_DRIFT_TERMINATE, &d->terminate) &&
1817 d->terminate) {
1818 quirks_get_uint32(q, MOUSED_DRIFT_DISTANCE, &d->distance);
1819 quirks_get_uint32(q, MOUSED_DRIFT_TIME, &d->time);
1820 quirks_get_uint32(q, MOUSED_DRIFT_AFTER, &d->after);
1821 } else
1822 return;
1823
1824 if (d->distance == 0 || d->time == 0 || d->after == 0) {
1825 warnx("invalid drift parameter");
1826 exit(1);
1827 }
1828
1829 debug("terminate drift: distance %d, time %d, after %d",
1830 d->distance, d->time, d->after);
1831
1832 d->time_ts = msec2ts(d->time);
1833 d->twotime_ts = msec2ts(d->time * 2);
1834 d->after_ts = msec2ts(d->after);
1835 }
1836
1837 static void
r_init_accel(struct quirks * q,struct accel * acc)1838 r_init_accel(struct quirks *q, struct accel *acc)
1839 {
1840 bool r1, r2;
1841
1842 acc->accelx = opt_accelx;
1843 if (opt_accelx == 1.0)
1844 quirks_get_double(q, MOUSED_LINEAR_ACCEL_X, &acc->accelx);
1845 acc->accely = opt_accely;
1846 if (opt_accely == 1.0)
1847 quirks_get_double(q, MOUSED_LINEAR_ACCEL_Y, &acc->accely);
1848 if (!quirks_get_double(q, MOUSED_LINEAR_ACCEL_Z, &acc->accelz))
1849 acc->accelz = 1.0;
1850 acc->lastlength[0] = acc->lastlength[1] = acc->lastlength[2] = 0.0;
1851 if (opt_exp_accel) {
1852 acc->is_exponential = true;
1853 acc->expoaccel = opt_expoaccel;
1854 acc->expoffset = opt_expoffset;
1855 return;
1856 }
1857 acc->expoaccel = acc->expoffset = 1.0;
1858 r1 = quirks_get_double(q, MOUSED_EXPONENTIAL_ACCEL, &acc->expoaccel);
1859 r2 = quirks_get_double(q, MOUSED_EXPONENTIAL_OFFSET, &acc->expoffset);
1860 if (r1 || r2)
1861 acc->is_exponential = true;
1862 }
1863
1864 static void
r_init_scroll(struct quirks * q,struct scroll * scroll)1865 r_init_scroll(struct quirks *q, struct scroll *scroll)
1866 {
1867 *scroll = (struct scroll) {
1868 .threshold = DFLT_SCROLLTHRESHOLD,
1869 .speed = DFLT_SCROLLSPEED,
1870 .state = SCROLL_NOTSCROLLING,
1871 };
1872 scroll->enable_vert = opt_virtual_scroll;
1873 if (!opt_virtual_scroll)
1874 quirks_get_bool(q, MOUSED_VIRTUAL_SCROLL_ENABLE, &scroll->enable_vert);
1875 scroll->enable_hor = opt_hvirtual_scroll;
1876 if (!opt_hvirtual_scroll)
1877 quirks_get_bool(q, MOUSED_HOR_VIRTUAL_SCROLL_ENABLE, &scroll->enable_hor);
1878 if (opt_scroll_speed >= 0)
1879 scroll->speed = opt_scroll_speed;
1880 else
1881 quirks_get_uint32(q, MOUSED_VIRTUAL_SCROLL_SPEED, &scroll->speed);
1882 if (opt_scroll_threshold >= 0)
1883 scroll->threshold = opt_scroll_threshold;
1884 else
1885 quirks_get_uint32(q, MOUSED_VIRTUAL_SCROLL_THRESHOLD, &scroll->threshold);
1886 }
1887
1888 static struct rodent *
r_init(const char * path)1889 r_init(const char *path)
1890 {
1891 struct rodent *r;
1892 struct device dev;
1893 struct quirks *q;
1894 struct kevent kev;
1895 enum device_if iftype;
1896 enum device_type type;
1897 int fd, err;
1898 bool grab;
1899 bool ignore;
1900 bool qvalid;
1901
1902 fd = open(path, O_RDWR | O_NONBLOCK);
1903 if (fd == -1) {
1904 logwarnx("unable to open %s", path);
1905 return (NULL);
1906 }
1907
1908 iftype = r_identify_if(fd);
1909 switch (iftype) {
1910 case DEVICE_IF_UNKNOWN:
1911 debug("cannot determine interface type on %s", path);
1912 close(fd);
1913 errno = ENOTSUP;
1914 return (NULL);
1915 case DEVICE_IF_EVDEV:
1916 type = r_identify_evdev(fd);
1917 break;
1918 case DEVICE_IF_SYSMOUSE:
1919 type = r_identify_sysmouse(fd);
1920 break;
1921 default:
1922 debug("unsupported interface type: %s on %s",
1923 r_if(iftype), path);
1924 close(fd);
1925 errno = ENXIO;
1926 return (NULL);
1927 }
1928
1929 switch (type) {
1930 case DEVICE_TYPE_UNKNOWN:
1931 debug("cannot determine device type on %s", path);
1932 close(fd);
1933 errno = ENOTSUP;
1934 return (NULL);
1935 case DEVICE_TYPE_MOUSE:
1936 case DEVICE_TYPE_TOUCHPAD:
1937 break;
1938 default:
1939 debug("unsupported device type: %s on %s",
1940 r_name(type), path);
1941 close(fd);
1942 errno = ENXIO;
1943 return (NULL);
1944 }
1945
1946 memset(&dev, 0, sizeof(struct device));
1947 strlcpy(dev.path, path, sizeof(dev.path));
1948 dev.iftype = iftype;
1949 dev.type = type;
1950 switch (iftype) {
1951 case DEVICE_IF_EVDEV:
1952 err = r_init_dev_evdev(fd, &dev);
1953 break;
1954 case DEVICE_IF_SYSMOUSE:
1955 err = r_init_dev_sysmouse(fd, &dev);
1956 break;
1957 default:
1958 debug("unsupported interface type: %s on %s",
1959 r_if(iftype), path);
1960 err = ENXIO;
1961 }
1962 if (err != 0) {
1963 debug("failed to initialize device: %s %s on %s",
1964 r_if(iftype), r_name(type), path);
1965 close(fd);
1966 errno = err;
1967 return (NULL);
1968 }
1969
1970 debug("port: %s interface: %s type: %s model: %s",
1971 path, r_if(iftype), r_name(type), dev.name);
1972
1973 q = quirks_fetch_for_device(quirks, &dev);
1974
1975 qvalid = quirks_get_bool(q, MOUSED_IGNORE_DEVICE, &ignore);
1976 if (qvalid && ignore) {
1977 debug("%s: device ignored", path);
1978 close(fd);
1979 quirks_unref(q);
1980 errno = EPERM;
1981 return (NULL);
1982 }
1983
1984 switch (iftype) {
1985 case DEVICE_IF_EVDEV:
1986 grab = opt_grab;
1987 if (!grab)
1988 qvalid = quirks_get_bool(q, MOUSED_GRAB_DEVICE, &grab);
1989 if (qvalid && grab && ioctl(fd, EVIOCGRAB, 1) == -1) {
1990 logwarnx("failed to grab %s", path);
1991 err = errno;
1992 }
1993 break;
1994 case DEVICE_IF_SYSMOUSE:
1995 if (opt_resolution == MOUSE_RES_UNKNOWN && opt_rate == 0)
1996 break;
1997 if (opt_resolution != MOUSE_RES_UNKNOWN)
1998 dev.mode.resolution = opt_resolution;
1999 if (opt_resolution != 0)
2000 dev.mode.rate = opt_rate;
2001 if (ioctl(fd, MOUSE_SETMODE, &dev.mode) < 0)
2002 debug("failed to MOUSE_SETMODE for device %s", path);
2003 break;
2004 default:
2005 debug("unsupported interface type: %s on %s",
2006 r_if(iftype), path);
2007 err = ENXIO;
2008 }
2009 if (err != 0) {
2010 debug("failed to initialize device: %s %s on %s",
2011 r_if(iftype), r_name(type), path);
2012 close(fd);
2013 quirks_unref(q);
2014 errno = err;
2015 return (NULL);
2016 }
2017
2018 r = calloc(1, sizeof(struct rodent));
2019 memcpy(&r->dev, &dev, sizeof(struct device));
2020 r->mfd = fd;
2021
2022 EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, r);
2023 err = kevent(kfd, &kev, 1, NULL, 0, NULL);
2024 if (err == -1) {
2025 logwarnx("failed to register kevent on %s", path);
2026 close(fd);
2027 free(r);
2028 quirks_unref(q);
2029 return (NULL);
2030 }
2031
2032 if (iftype == DEVICE_IF_EVDEV)
2033 r_init_evstate(q, &r->ev);
2034 r_init_buttons(q, &r->btstate, &r->e3b);
2035 r_init_scroll(q, &r->scroll);
2036 r_init_accel(q, &r->accel);
2037 switch (type) {
2038 case DEVICE_TYPE_TOUCHPAD:
2039 r_init_touchpad_hw(fd, q, &r->tp.hw, &r->ev);
2040 r_init_touchpad_info(q, &r->tp.hw, &r->tp.info);
2041 r_init_touchpad_accel(&r->tp.hw, &r->accel);
2042 r_init_touchpad_gesture(&r->tp.gest);
2043 break;
2044
2045 case DEVICE_TYPE_MOUSE:
2046 r_init_drift(q, &r->drift);
2047 break;
2048
2049 default:
2050 debug("unsupported device type: %s", r_name(type));
2051 break;
2052 }
2053
2054 quirks_unref(q);
2055
2056 SLIST_INSERT_HEAD(&rodents, r, next);
2057
2058 return (r);
2059 }
2060
2061 static void
r_init_all(void)2062 r_init_all(void)
2063 {
2064 char path[22] = "/dev/input/";
2065 DIR *dirp;
2066 struct dirent *dp;
2067
2068 dirp = opendir("/dev/input");
2069 if (dirp == NULL)
2070 logerr(1, "Failed to open /dev/input");
2071
2072 while ((dp = readdir(dirp)) != NULL) {
2073 if (fnmatch("event[0-9]*", dp->d_name, 0) == 0) {
2074 strncpy(path + 11, dp->d_name, 10);
2075 (void)r_init(path);
2076 }
2077 }
2078 (void)closedir(dirp);
2079
2080 return;
2081 }
2082
2083 static void
r_deinit(struct rodent * r)2084 r_deinit(struct rodent *r)
2085 {
2086 struct kevent ke[3];
2087
2088 if (r == NULL)
2089 return;
2090 if (r->mfd != -1) {
2091 EV_SET(ke, r->mfd, EVFILT_READ, EV_DELETE, 0, 0, r);
2092 EV_SET(ke + 1, r->mfd << 1, EVFILT_TIMER, EV_DELETE, 0, 0, r);
2093 EV_SET(ke + 2, r->mfd << 1 | 1,
2094 EVFILT_TIMER, EV_DELETE, 0, 0, r);
2095 kevent(kfd, ke, nitems(ke), NULL, 0, NULL);
2096 close(r->mfd);
2097 }
2098 SLIST_REMOVE(&rodents, r, rodent, next);
2099 debug("destroy device: port: %s model: %s", r->dev.path, r->dev.name);
2100 free(r);
2101 }
2102
2103 static void
r_deinit_all(void)2104 r_deinit_all(void)
2105 {
2106 while (!SLIST_EMPTY(&rodents))
2107 r_deinit(SLIST_FIRST(&rodents));
2108 }
2109
2110 static int
r_protocol_evdev(enum device_type type,struct tpad * tp,struct evstate * ev,struct input_event * ie,mousestatus_t * act)2111 r_protocol_evdev(enum device_type type, struct tpad *tp, struct evstate *ev,
2112 struct input_event *ie, mousestatus_t *act)
2113 {
2114 const struct tpcaps *tphw = &tp->hw;
2115 const struct tpinfo *tpinfo = &tp->info;
2116
2117 static int butmapev[8] = { /* evdev */
2118 0,
2119 MOUSE_BUTTON1DOWN,
2120 MOUSE_BUTTON3DOWN,
2121 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
2122 MOUSE_BUTTON2DOWN,
2123 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
2124 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
2125 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
2126 };
2127 struct timespec ietime;
2128
2129 /* Drop ignored codes */
2130 switch (ie->type) {
2131 case EV_REL:
2132 if (bit_test(ev->rel_ignore, ie->code))
2133 return (0);
2134 case EV_ABS:
2135 if (bit_test(ev->abs_ignore, ie->code))
2136 return (0);
2137 case EV_KEY:
2138 if (bit_test(ev->key_ignore, ie->code))
2139 return (0);
2140 }
2141
2142 if (debug > 1)
2143 debug("received event 0x%02x, 0x%04x, %d",
2144 ie->type, ie->code, ie->value);
2145
2146 switch (ie->type) {
2147 case EV_REL:
2148 switch (ie->code) {
2149 case REL_X:
2150 ev->dx += ie->value;
2151 break;
2152 case REL_Y:
2153 ev->dy += ie->value;
2154 break;
2155 case REL_WHEEL:
2156 ev->dz += ie->value;
2157 break;
2158 case REL_HWHEEL:
2159 ev->dw += ie->value;
2160 break;
2161 }
2162 break;
2163 case EV_ABS:
2164 switch (ie->code) {
2165 case ABS_X:
2166 if (!tphw->is_mt)
2167 ev->dx += ie->value - ev->st.x;
2168 ev->st.x = ie->value;
2169 break;
2170 case ABS_Y:
2171 if (!tphw->is_mt)
2172 ev->dy += ie->value - ev->st.y;
2173 ev->st.y = ie->value;
2174 break;
2175 case ABS_PRESSURE:
2176 ev->st.p = ie->value;
2177 break;
2178 case ABS_TOOL_WIDTH:
2179 ev->st.w = ie->value;
2180 break;
2181 case ABS_MT_SLOT:
2182 if (tphw->is_mt)
2183 ev->slot = ie->value;
2184 break;
2185 case ABS_MT_TRACKING_ID:
2186 if (tphw->is_mt &&
2187 ev->slot >= 0 && ev->slot < MAX_FINGERS) {
2188 if (ie->value != -1 && ev->mt[ev->slot].id > 0 &&
2189 ie->value + 1 != ev->mt[ev->slot].id) {
2190 debug("tracking id changed %d->%d",
2191 ie->value, ev->mt[ev->slot].id - 1);
2192 ev->mt[ev->slot].id = 0;
2193 } else
2194 ev->mt[ev->slot].id = ie->value + 1;
2195 }
2196 break;
2197 case ABS_MT_POSITION_X:
2198 if (tphw->is_mt &&
2199 ev->slot >= 0 && ev->slot < MAX_FINGERS) {
2200 /* Find fastest finger */
2201 int dx = ie->value - ev->mt[ev->slot].x;
2202 if (abs(dx) > abs(ev->dx))
2203 ev->dx = dx;
2204 ev->mt[ev->slot].x = ie->value;
2205 }
2206 break;
2207 case ABS_MT_POSITION_Y:
2208 if (tphw->is_mt &&
2209 ev->slot >= 0 && ev->slot < MAX_FINGERS) {
2210 /* Find fastest finger */
2211 int dy = ie->value - ev->mt[ev->slot].y;
2212 if (abs(dy) > abs(ev->dy))
2213 ev->dy = dy;
2214 ev->mt[ev->slot].y = ie->value;
2215 }
2216 break;
2217 }
2218 break;
2219 case EV_KEY:
2220 switch (ie->code) {
2221 case BTN_TOUCH:
2222 ev->st.id = ie->value != 0 ? 1 : 0;
2223 break;
2224 case BTN_TOOL_FINGER:
2225 ev->nfingers = ie->value != 0 ? 1 : ev->nfingers;
2226 break;
2227 case BTN_TOOL_DOUBLETAP:
2228 ev->nfingers = ie->value != 0 ? 2 : ev->nfingers;
2229 break;
2230 case BTN_TOOL_TRIPLETAP:
2231 ev->nfingers = ie->value != 0 ? 3 : ev->nfingers;
2232 break;
2233 case BTN_TOOL_QUADTAP:
2234 ev->nfingers = ie->value != 0 ? 4 : ev->nfingers;
2235 break;
2236 case BTN_TOOL_QUINTTAP:
2237 ev->nfingers = ie->value != 0 ? 5 : ev->nfingers;
2238 break;
2239 case BTN_LEFT ... BTN_LEFT + 7:
2240 ev->buttons &= ~(1 << (ie->code - BTN_LEFT));
2241 ev->buttons |= ((!!ie->value) << (ie->code - BTN_LEFT));
2242 break;
2243 }
2244 break;
2245 }
2246
2247 if ( ie->type != EV_SYN ||
2248 (ie->code != SYN_REPORT && ie->code != SYN_DROPPED))
2249 return (0);
2250
2251 /*
2252 * assembly full package
2253 */
2254
2255 ietime.tv_sec = ie->time.tv_sec;
2256 ietime.tv_nsec = ie->time.tv_usec * 1000;
2257
2258 if (!tphw->cap_pressure && ev->st.id != 0)
2259 ev->st.p = MAX(tpinfo->min_pressure_hi, tpinfo->tap_threshold);
2260 if (tphw->cap_touch && ev->st.id == 0)
2261 ev->st.p = 0;
2262
2263 act->obutton = act->button;
2264 act->button = butmapev[ev->buttons & MOUSE_SYS_STDBUTTONS];
2265 act->button |= (ev->buttons & ~MOUSE_SYS_STDBUTTONS);
2266
2267 if (type == DEVICE_TYPE_TOUCHPAD) {
2268 if (debug > 1)
2269 debug("absolute data %d,%d,%d,%d", ev->st.x, ev->st.y,
2270 ev->st.p, ev->st.w);
2271 switch (r_gestures(tp, ev->st.x, ev->st.y, ev->st.p, ev->st.w,
2272 ev->nfingers, &ietime, act)) {
2273 case GEST_IGNORE:
2274 ev->dx = 0;
2275 ev->dy = 0;
2276 ev->dz = 0;
2277 ev->acc_dx = ev->acc_dy = 0;
2278 debug("gesture IGNORE");
2279 break;
2280 case GEST_ACCUMULATE: /* Revertable pointer movement. */
2281 ev->acc_dx += ev->dx;
2282 ev->acc_dy += ev->dy;
2283 debug("gesture ACCUMULATE %d,%d", ev->dx, ev->dy);
2284 ev->dx = 0;
2285 ev->dy = 0;
2286 break;
2287 case GEST_MOVE: /* Pointer movement. */
2288 ev->dx += ev->acc_dx;
2289 ev->dy += ev->acc_dy;
2290 ev->acc_dx = ev->acc_dy = 0;
2291 debug("gesture MOVE %d,%d", ev->dx, ev->dy);
2292 break;
2293 case GEST_VSCROLL: /* Vertical scrolling. */
2294 if (tpinfo->natural_scroll)
2295 ev->dz = -ev->dy;
2296 else
2297 ev->dz = ev->dy;
2298 ev->dx = -ev->acc_dx;
2299 ev->dy = -ev->acc_dy;
2300 ev->acc_dx = ev->acc_dy = 0;
2301 debug("gesture VSCROLL %d", ev->dz);
2302 break;
2303 case GEST_HSCROLL: /* Horizontal scrolling. */
2304 /*
2305 if (ev.dx != 0) {
2306 if (tpinfo->natural_scroll)
2307 act->button |= (ev.dx > 0)
2308 ? MOUSE_BUTTON6DOWN
2309 : MOUSE_BUTTON7DOWN;
2310 else
2311 act->button |= (ev.dx > 0)
2312 ? MOUSE_BUTTON7DOWN
2313 : MOUSE_BUTTON6DOWN;
2314 }
2315 */
2316 ev->dx = -ev->acc_dx;
2317 ev->dy = -ev->acc_dy;
2318 ev->acc_dx = ev->acc_dy = 0;
2319 debug("gesture HSCROLL %d", ev->dw);
2320 break;
2321 }
2322 }
2323
2324 debug("assembled full packet %d,%d,%d", ev->dx, ev->dy, ev->dz);
2325 act->dx = ev->dx;
2326 act->dy = ev->dy;
2327 act->dz = ev->dz;
2328 ev->dx = ev->dy = ev->dz = ev->dw = 0;
2329
2330 /* has something changed? */
2331 act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
2332 | (act->obutton ^ act->button);
2333
2334 return (act->flags);
2335 }
2336
2337 static int
r_protocol_sysmouse(uint8_t * pBuf,mousestatus_t * act)2338 r_protocol_sysmouse(uint8_t *pBuf, mousestatus_t *act)
2339 {
2340 static int butmapmsc[8] = { /* sysmouse */
2341 0,
2342 MOUSE_BUTTON3DOWN,
2343 MOUSE_BUTTON2DOWN,
2344 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
2345 MOUSE_BUTTON1DOWN,
2346 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
2347 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
2348 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
2349 };
2350
2351 debug("%02x %02x %02x %02x %02x %02x %02x %02x", pBuf[0], pBuf[1],
2352 pBuf[2], pBuf[3], pBuf[4], pBuf[5], pBuf[6], pBuf[7]);
2353
2354 if ((pBuf[0] & MOUSE_SYS_SYNCMASK) != MOUSE_SYS_SYNC)
2355 return (0);
2356
2357 act->button = butmapmsc[(~pBuf[0]) & MOUSE_SYS_STDBUTTONS];
2358 act->dx = (signed char)(pBuf[1]) + (signed char)(pBuf[3]);
2359 act->dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4]));
2360 act->dz = ((signed char)(pBuf[5] << 1) + (signed char)(pBuf[6] << 1)) >> 1;
2361 act->button |= ((~pBuf[7] & MOUSE_SYS_EXTBUTTONS) << 3);
2362
2363 /* has something changed? */
2364 act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
2365 | (act->obutton ^ act->button);
2366
2367 return (act->flags);
2368 }
2369
2370 static void
r_vscroll_detect(struct rodent * r,struct scroll * sc,mousestatus_t * act)2371 r_vscroll_detect(struct rodent *r, struct scroll *sc, mousestatus_t *act)
2372 {
2373 mousestatus_t newaction;
2374
2375 /* Allow middle button drags to scroll up and down */
2376 if (act->button == MOUSE_BUTTON2DOWN) {
2377 if (sc->state == SCROLL_NOTSCROLLING) {
2378 sc->state = SCROLL_PREPARE;
2379 sc->movement = sc->hmovement = 0;
2380 debug("PREPARING TO SCROLL");
2381 }
2382 return;
2383 }
2384
2385 /* This isn't a middle button down... move along... */
2386 switch (sc->state) {
2387 case SCROLL_SCROLLING:
2388 /*
2389 * We were scrolling, someone let go of button 2.
2390 * Now turn autoscroll off.
2391 */
2392 sc->state = SCROLL_NOTSCROLLING;
2393 debug("DONE WITH SCROLLING / %d", sc->state);
2394 break;
2395 case SCROLL_PREPARE:
2396 newaction = *act;
2397
2398 /* We were preparing to scroll, but we never moved... */
2399 r_timestamp(act, &r->btstate, &r->e3b, &r->drift);
2400 r_statetrans(r, act, &newaction,
2401 A(newaction.button & MOUSE_BUTTON1DOWN,
2402 act->button & MOUSE_BUTTON3DOWN));
2403
2404 /* Send middle down */
2405 newaction.button = MOUSE_BUTTON2DOWN;
2406 r_click(&newaction, &r->btstate);
2407
2408 /* Send middle up */
2409 r_timestamp(&newaction, &r->btstate, &r->e3b, &r->drift);
2410 newaction.obutton = newaction.button;
2411 newaction.button = act->button;
2412 r_click(&newaction, &r->btstate);
2413 break;
2414 default:
2415 break;
2416 }
2417 }
2418
2419 static void
r_vscroll(struct scroll * sc,mousestatus_t * act)2420 r_vscroll(struct scroll *sc, mousestatus_t *act)
2421 {
2422 switch (sc->state) {
2423 case SCROLL_PREPARE:
2424 /* Middle button down, waiting for movement threshold */
2425 if (act->dy == 0 && act->dx == 0)
2426 break;
2427 if (sc->enable_vert) {
2428 sc->movement += act->dy;
2429 if ((u_int)abs(sc->movement) > sc->threshold)
2430 sc->state = SCROLL_SCROLLING;
2431 }
2432 if (sc->enable_hor) {
2433 sc->hmovement += act->dx;
2434 if ((u_int)abs(sc->hmovement) > sc->threshold)
2435 sc->state = SCROLL_SCROLLING;
2436 }
2437 if (sc->state == SCROLL_SCROLLING)
2438 sc->movement = sc->hmovement = 0;
2439 break;
2440 case SCROLL_SCROLLING:
2441 if (sc->enable_vert) {
2442 sc->movement += act->dy;
2443 debug("SCROLL: %d", sc->movement);
2444 if (sc->movement < -(int)sc->speed) {
2445 /* Scroll down */
2446 act->dz = -1;
2447 sc->movement = 0;
2448 }
2449 else if (sc->movement > (int)sc->speed) {
2450 /* Scroll up */
2451 act->dz = 1;
2452 sc->movement = 0;
2453 }
2454 }
2455 if (sc->enable_hor) {
2456 sc->hmovement += act->dx;
2457 debug("HORIZONTAL SCROLL: %d", sc->hmovement);
2458
2459 if (sc->hmovement < -(int)sc->speed) {
2460 act->dz = -2;
2461 sc->hmovement = 0;
2462 }
2463 else if (sc->hmovement > (int)sc->speed) {
2464 act->dz = 2;
2465 sc->hmovement = 0;
2466 }
2467 }
2468
2469 /* Don't move while scrolling */
2470 act->dx = act->dy = 0;
2471 break;
2472 default:
2473 break;
2474 }
2475 }
2476
2477 static bool
r_drift(struct drift * drift,mousestatus_t * act)2478 r_drift (struct drift *drift, mousestatus_t *act)
2479 {
2480 struct timespec tmp;
2481
2482 /* X or/and Y movement only - possibly drift */
2483 tssub(&drift->current_ts, &drift->last_activity, &tmp);
2484 if (tscmp(&tmp, &drift->after_ts, >)) {
2485 tssub(&drift->current_ts, &drift->since, &tmp);
2486 if (tscmp(&tmp, &drift->time_ts, <)) {
2487 drift->last.x += act->dx;
2488 drift->last.y += act->dy;
2489 } else {
2490 /* discard old accumulated steps (drift) */
2491 if (tscmp(&tmp, &drift->twotime_ts, >))
2492 drift->previous.x = drift->previous.y = 0;
2493 else
2494 drift->previous = drift->last;
2495 drift->last.x = act->dx;
2496 drift->last.y = act->dy;
2497 drift->since = drift->current_ts;
2498 }
2499 if ((u_int)abs(drift->last.x) + abs(drift->last.y) > drift->distance) {
2500 /* real movement, pass all accumulated steps */
2501 act->dx = drift->previous.x + drift->last.x;
2502 act->dy = drift->previous.y + drift->last.y;
2503 /* and reset accumulators */
2504 tsclr(&drift->since);
2505 drift->last.x = drift->last.y = 0;
2506 /* drift_previous will be cleared at next movement*/
2507 drift->last_activity = drift->current_ts;
2508 } else {
2509 return (true); /* don't pass current movement to
2510 * console driver */
2511 }
2512 }
2513 return (false);
2514 }
2515
2516 static int
r_statetrans(struct rodent * r,mousestatus_t * a1,mousestatus_t * a2,int trans)2517 r_statetrans(struct rodent *r, mousestatus_t *a1, mousestatus_t *a2, int trans)
2518 {
2519 struct e3bstate *e3b = &r->e3b;
2520 bool changed;
2521 int flags;
2522
2523 a2->dx = a1->dx;
2524 a2->dy = a1->dy;
2525 a2->dz = a1->dz;
2526 a2->obutton = a2->button;
2527 a2->button = a1->button;
2528 a2->flags = a1->flags;
2529 changed = false;
2530
2531 if (!e3b->enabled)
2532 return (false);
2533
2534 if (debug > 2)
2535 debug("state:%d, trans:%d -> state:%d",
2536 e3b->mouse_button_state, trans,
2537 states[e3b->mouse_button_state].s[trans]);
2538 /*
2539 * Avoid re-ordering button and movement events. While a button
2540 * event is deferred, throw away up to BUTTON2_MAXMOVE movement
2541 * events to allow for mouse jitter. If more movement events
2542 * occur, then complete the deferred button events immediately.
2543 */
2544 if ((a2->dx != 0 || a2->dy != 0) &&
2545 S_DELAYED(states[e3b->mouse_button_state].s[trans])) {
2546 if (++e3b->mouse_move_delayed > BUTTON2_MAXMOVE) {
2547 e3b->mouse_move_delayed = 0;
2548 e3b->mouse_button_state =
2549 states[e3b->mouse_button_state].s[A_TIMEOUT];
2550 changed = true;
2551 } else
2552 a2->dx = a2->dy = 0;
2553 } else
2554 e3b->mouse_move_delayed = 0;
2555 if (e3b->mouse_button_state != states[e3b->mouse_button_state].s[trans])
2556 changed = true;
2557 if (changed)
2558 clock_gettime(CLOCK_MONOTONIC_FAST,
2559 &e3b->mouse_button_state_ts);
2560 e3b->mouse_button_state = states[e3b->mouse_button_state].s[trans];
2561 a2->button &= ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN |
2562 MOUSE_BUTTON3DOWN);
2563 a2->button &= states[e3b->mouse_button_state].mask;
2564 a2->button |= states[e3b->mouse_button_state].buttons;
2565 flags = a2->flags & MOUSE_POSCHANGED;
2566 flags |= a2->obutton ^ a2->button;
2567 if (flags & MOUSE_BUTTON2DOWN) {
2568 a2->flags = flags & MOUSE_BUTTON2DOWN;
2569 r_timestamp(a2, &r->btstate, e3b, &r->drift);
2570 }
2571 a2->flags = flags;
2572
2573 return (changed);
2574 }
2575
2576 static char *
skipspace(char * s)2577 skipspace(char *s)
2578 {
2579 while(isspace(*s))
2580 ++s;
2581 return (s);
2582 }
2583
2584 static bool
r_installmap(char * arg,struct btstate * bt)2585 r_installmap(char *arg, struct btstate *bt)
2586 {
2587 u_long pbutton;
2588 u_long lbutton;
2589 char *s;
2590
2591 while (*arg) {
2592 arg = skipspace(arg);
2593 s = arg;
2594 while (isdigit(*arg))
2595 ++arg;
2596 arg = skipspace(arg);
2597 if ((arg <= s) || (*arg != '='))
2598 return (false);
2599 lbutton = strtoul(s, NULL, 10);
2600
2601 arg = skipspace(++arg);
2602 s = arg;
2603 while (isdigit(*arg))
2604 ++arg;
2605 if ((arg <= s) || (!isspace(*arg) && (*arg != '\0')))
2606 return (false);
2607 pbutton = strtoul(s, NULL, 10);
2608
2609 if (lbutton == 0 || lbutton > MOUSE_MAXBUTTON)
2610 return (false);
2611 if (pbutton == 0 || pbutton > MOUSE_MAXBUTTON)
2612 return (false);
2613 bt->p2l[pbutton - 1] = 1 << (lbutton - 1);
2614 bt->mstate[lbutton - 1] = &bt->bstate[pbutton - 1];
2615 }
2616
2617 return (true);
2618 }
2619
2620 static char *
r_installzmap(char ** argv,int argc,int * idx,struct btstate * bt)2621 r_installzmap(char **argv, int argc, int* idx, struct btstate *bt)
2622 {
2623 char *arg, *errstr;
2624 u_long i, j;
2625
2626 arg = argv[*idx];
2627 ++*idx;
2628 if (strcmp(arg, "x") == 0) {
2629 bt->zmap[0] = MOUSE_XAXIS;
2630 return (NULL);
2631 }
2632 if (strcmp(arg, "y") == 0) {
2633 bt->zmap[0] = MOUSE_YAXIS;
2634 return (NULL);
2635 }
2636 i = strtoul(arg, NULL, 10);
2637 /*
2638 * Use button i for negative Z axis movement and
2639 * button (i + 1) for positive Z axis movement.
2640 */
2641 if (i == 0 || i >= MOUSE_MAXBUTTON) {
2642 asprintf(&errstr, "invalid argument `%s'", arg);
2643 return (errstr);
2644 }
2645 bt->zmap[0] = i;
2646 bt->zmap[1] = i + 1;
2647 debug("optind: %d, optarg: '%s'", *idx, arg);
2648 for (j = 1; j < ZMAP_MAXBUTTON; ++j) {
2649 if ((*idx >= argc) || !isdigit(*argv[*idx]))
2650 break;
2651 i = strtoul(argv[*idx], NULL, 10);
2652 if (i == 0 || i >= MOUSE_MAXBUTTON) {
2653 asprintf(&errstr, "invalid argument `%s'", argv[*idx]);
2654 return (errstr);
2655 }
2656 bt->zmap[j] = i;
2657 ++*idx;
2658 }
2659 if ((bt->zmap[2] != 0) && (bt->zmap[3] == 0))
2660 bt->zmap[3] = bt->zmap[2] + 1;
2661
2662 return (NULL);
2663 }
2664
2665 static void
r_map(mousestatus_t * act1,mousestatus_t * act2,struct btstate * bt)2666 r_map(mousestatus_t *act1, mousestatus_t *act2, struct btstate *bt)
2667 {
2668 int pb;
2669 int pbuttons;
2670 int lbuttons;
2671
2672 pbuttons = act1->button;
2673 lbuttons = 0;
2674
2675 act2->obutton = act2->button;
2676 if (pbuttons & bt->wmode) {
2677 pbuttons &= ~bt->wmode;
2678 act1->dz = act1->dy;
2679 act1->dx = 0;
2680 act1->dy = 0;
2681 }
2682 act2->dx = act1->dx;
2683 act2->dy = act1->dy;
2684 act2->dz = act1->dz;
2685
2686 switch (bt->zmap[0]) {
2687 case 0: /* do nothing */
2688 break;
2689 case MOUSE_XAXIS:
2690 if (act1->dz != 0) {
2691 act2->dx = act1->dz;
2692 act2->dz = 0;
2693 }
2694 break;
2695 case MOUSE_YAXIS:
2696 if (act1->dz != 0) {
2697 act2->dy = act1->dz;
2698 act2->dz = 0;
2699 }
2700 break;
2701 default: /* buttons */
2702 pbuttons &= ~(bt->zmap[0] | bt->zmap[1]
2703 | bt->zmap[2] | bt->zmap[3]);
2704 if ((act1->dz < -1) && bt->zmap[2]) {
2705 pbuttons |= bt->zmap[2];
2706 bt->zstate[2].count = 1;
2707 } else if (act1->dz < 0) {
2708 pbuttons |= bt->zmap[0];
2709 bt->zstate[0].count = 1;
2710 } else if ((act1->dz > 1) && bt->zmap[3]) {
2711 pbuttons |= bt->zmap[3];
2712 bt->zstate[3].count = 1;
2713 } else if (act1->dz > 0) {
2714 pbuttons |= bt->zmap[1];
2715 bt->zstate[1].count = 1;
2716 }
2717 act2->dz = 0;
2718 break;
2719 }
2720
2721 for (pb = 0; (pb < MOUSE_MAXBUTTON) && (pbuttons != 0); ++pb) {
2722 lbuttons |= (pbuttons & 1) ? bt->p2l[pb] : 0;
2723 pbuttons >>= 1;
2724 }
2725 act2->button = lbuttons;
2726
2727 act2->flags =
2728 ((act2->dx || act2->dy || act2->dz) ? MOUSE_POSCHANGED : 0)
2729 | (act2->obutton ^ act2->button);
2730 }
2731
2732 static void
r_timestamp(mousestatus_t * act,struct btstate * bt,struct e3bstate * e3b,struct drift * drift)2733 r_timestamp(mousestatus_t *act, struct btstate *bt, struct e3bstate *e3b,
2734 struct drift *drift)
2735 {
2736 struct timespec ts;
2737 struct timespec ts1;
2738 struct timespec ts2;
2739 int button;
2740 int mask;
2741 int i;
2742
2743 mask = act->flags & MOUSE_BUTTONS;
2744 #if 0
2745 if (mask == 0)
2746 return;
2747 #endif
2748
2749 clock_gettime(CLOCK_MONOTONIC_FAST, &ts1);
2750 drift->current_ts = ts1;
2751
2752 /* double click threshold */
2753 ts = tssubms(&ts1, bt->clickthreshold);
2754 debug("ts: %jd %ld", (intmax_t)ts.tv_sec, ts.tv_nsec);
2755
2756 /* 3 button emulation timeout */
2757 ts2 = tssubms(&ts1, e3b->button2timeout);
2758
2759 button = MOUSE_BUTTON1DOWN;
2760 for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
2761 if (mask & 1) {
2762 if (act->button & button) {
2763 /* the button is down */
2764 debug(" : %jd %ld",
2765 (intmax_t)bt->bstate[i].ts.tv_sec,
2766 bt->bstate[i].ts.tv_nsec);
2767 if (tscmp(&ts, &bt->bstate[i].ts, >)) {
2768 bt->bstate[i].count = 1;
2769 } else {
2770 ++bt->bstate[i].count;
2771 }
2772 bt->bstate[i].ts = ts1;
2773 } else {
2774 /* the button is up */
2775 bt->bstate[i].ts = ts1;
2776 }
2777 } else {
2778 if (act->button & button) {
2779 /* the button has been down */
2780 if (tscmp(&ts2, &bt->bstate[i].ts, >)) {
2781 bt->bstate[i].count = 1;
2782 bt->bstate[i].ts = ts1;
2783 act->flags |= button;
2784 debug("button %d timeout", i + 1);
2785 }
2786 } else {
2787 /* the button has been up */
2788 }
2789 }
2790 button <<= 1;
2791 mask >>= 1;
2792 }
2793 }
2794
2795 static bool
r_timeout(struct e3bstate * e3b)2796 r_timeout(struct e3bstate *e3b)
2797 {
2798 struct timespec ts;
2799 struct timespec ts1;
2800
2801 if (states[e3b->mouse_button_state].timeout)
2802 return (true);
2803 clock_gettime(CLOCK_MONOTONIC_FAST, &ts1);
2804 ts = tssubms(&ts1, e3b->button2timeout);
2805 return (tscmp(&ts, &e3b->mouse_button_state_ts, >));
2806 }
2807
2808 static void
r_move(mousestatus_t * act,struct accel * acc)2809 r_move(mousestatus_t *act, struct accel *acc)
2810 {
2811 struct mouse_info mouse;
2812
2813 bzero(&mouse, sizeof(mouse));
2814 if (acc->is_exponential) {
2815 expoacc(acc, act->dx, act->dy, act->dz,
2816 &mouse.u.data.x, &mouse.u.data.y, &mouse.u.data.z);
2817 } else {
2818 linacc(acc, act->dx, act->dy, act->dz,
2819 &mouse.u.data.x, &mouse.u.data.y, &mouse.u.data.z);
2820 }
2821 mouse.operation = MOUSE_MOTION_EVENT;
2822 mouse.u.data.buttons = act->button;
2823 if (debug < 2 && !paused)
2824 ioctl(cfd, CONS_MOUSECTL, &mouse);
2825 }
2826
2827 static void
r_click(mousestatus_t * act,struct btstate * bt)2828 r_click(mousestatus_t *act, struct btstate *bt)
2829 {
2830 struct mouse_info mouse;
2831 int button;
2832 int mask;
2833 int i;
2834
2835 mask = act->flags & MOUSE_BUTTONS;
2836 if (mask == 0)
2837 return;
2838
2839 button = MOUSE_BUTTON1DOWN;
2840 for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
2841 if (mask & 1) {
2842 debug("mstate[%d]->count:%d", i, bt->mstate[i]->count);
2843 if (act->button & button) {
2844 /* the button is down */
2845 mouse.u.event.value = bt->mstate[i]->count;
2846 } else {
2847 /* the button is up */
2848 mouse.u.event.value = 0;
2849 }
2850 mouse.operation = MOUSE_BUTTON_EVENT;
2851 mouse.u.event.id = button;
2852 if (debug < 2 && !paused)
2853 ioctl(cfd, CONS_MOUSECTL, &mouse);
2854 debug("button %d count %d", i + 1,
2855 mouse.u.event.value);
2856 }
2857 button <<= 1;
2858 mask >>= 1;
2859 }
2860 }
2861
2862 static enum gesture
r_gestures(struct tpad * tp,int x0,int y0,u_int z,int w,int nfingers,struct timespec * time,mousestatus_t * ms)2863 r_gestures(struct tpad *tp, int x0, int y0, u_int z, int w, int nfingers,
2864 struct timespec *time, mousestatus_t *ms)
2865 {
2866 struct tpstate *gest = &tp->gest;
2867 const struct tpcaps *tphw = &tp->hw;
2868 const struct tpinfo *tpinfo = &tp->info;
2869 int tap_timeout = tpinfo->tap_timeout;
2870
2871 /*
2872 * Check pressure to detect a real wanted action on the
2873 * touchpad.
2874 */
2875 if (z >= tpinfo->min_pressure_hi ||
2876 (gest->fingerdown && z >= tpinfo->min_pressure_lo)) {
2877 /* XXX Verify values? */
2878 bool two_finger_scroll = tpinfo->two_finger_scroll;
2879 bool three_finger_drag = tpinfo->three_finger_drag;
2880 int max_width = tpinfo->max_width;
2881 u_int max_pressure = tpinfo->max_pressure;
2882 int margin_top = tpinfo->margin_top;
2883 int margin_right = tpinfo->margin_right;
2884 int margin_bottom = tpinfo->margin_bottom;
2885 int margin_left = tpinfo->margin_left;
2886 int vscroll_hor_area = tpinfo->vscroll_hor_area * tphw->res_x;
2887 int vscroll_ver_area = tpinfo->vscroll_ver_area * tphw->res_y;;
2888
2889 int max_x = tphw->max_x;
2890 int max_y = tphw->max_y;
2891 int min_x = tphw->min_x;
2892 int min_y = tphw->min_y;
2893
2894 int dx, dy;
2895 int start_x, start_y;
2896 int tap_max_delta_x, tap_max_delta_y;
2897 int prev_nfingers;
2898
2899 /* Palm detection. */
2900 if (nfingers == 1 &&
2901 ((tphw->cap_width && w > max_width) ||
2902 (tphw->cap_pressure && z > max_pressure))) {
2903 /*
2904 * We consider the packet irrelevant for the current
2905 * action when:
2906 * - there is a single active touch
2907 * - the width isn't comprised in:
2908 * [0; max_width]
2909 * - the pressure isn't comprised in:
2910 * [min_pressure; max_pressure]
2911 *
2912 * Note that this doesn't terminate the current action.
2913 */
2914 debug("palm detected! (%d)", z);
2915 return(GEST_IGNORE);
2916 }
2917
2918 /*
2919 * Limit the coordinates to the specified margins because
2920 * this area isn't very reliable.
2921 */
2922 if (margin_left != 0 && x0 <= min_x + margin_left)
2923 x0 = min_x + margin_left;
2924 else if (margin_right != 0 && x0 >= max_x - margin_right)
2925 x0 = max_x - margin_right;
2926 if (margin_bottom != 0 && y0 <= min_y + margin_bottom)
2927 y0 = min_y + margin_bottom;
2928 else if (margin_top != 0 && y0 >= max_y - margin_top)
2929 y0 = max_y - margin_top;
2930
2931 debug("packet: [%d, %d], %d, %d", x0, y0, z, w);
2932
2933 /*
2934 * If the action is just beginning, init the structure and
2935 * compute tap timeout.
2936 */
2937 if (!gest->fingerdown) {
2938 debug("----");
2939
2940 /* Reset pressure peak. */
2941 gest->zmax = 0;
2942
2943 /* Reset fingers count. */
2944 gest->fingers_nb = 0;
2945
2946 /* Reset virtual scrolling state. */
2947 gest->in_vscroll = 0;
2948
2949 /* Compute tap timeout. */
2950 if (tap_timeout != 0)
2951 gest->taptimeout = tsaddms(time, tap_timeout);
2952 else
2953 tsclr(&gest->taptimeout);
2954
2955 gest->fingerdown = true;
2956
2957 gest->start_x = x0;
2958 gest->start_y = y0;
2959 }
2960
2961 prev_nfingers = gest->prev_nfingers;
2962
2963 gest->prev_x = x0;
2964 gest->prev_y = y0;
2965 gest->prev_nfingers = nfingers;
2966
2967 start_x = gest->start_x;
2968 start_y = gest->start_y;
2969
2970 /* Process ClickPad softbuttons */
2971 if (tphw->is_clickpad && ms->button & MOUSE_BUTTON1DOWN) {
2972 int y_ok, center_bt, center_x, right_bt, right_x;
2973 y_ok = tpinfo->softbuttons_y < 0
2974 ? start_y < min_y - tpinfo->softbuttons_y
2975 : start_y > max_y - tpinfo->softbuttons_y;
2976
2977 center_bt = MOUSE_BUTTON2DOWN;
2978 center_x = min_x + tpinfo->softbutton2_x;
2979 right_bt = MOUSE_BUTTON3DOWN;
2980 right_x = min_x + tpinfo->softbutton3_x;
2981
2982 if (center_x > 0 && right_x > 0 && center_x > right_x) {
2983 center_bt = MOUSE_BUTTON3DOWN;
2984 center_x = min_x + tpinfo->softbutton3_x;
2985 right_bt = MOUSE_BUTTON2DOWN;
2986 right_x = min_x + tpinfo->softbutton2_x;
2987 }
2988
2989 if (right_x > 0 && start_x > right_x && y_ok)
2990 ms->button = (ms->button &
2991 ~MOUSE_BUTTON1DOWN) | right_bt;
2992 else if (center_x > 0 && start_x > center_x && y_ok)
2993 ms->button = (ms->button &
2994 ~MOUSE_BUTTON1DOWN) | center_bt;
2995 }
2996
2997 /* If in tap-hold or three fingers, add the recorded button. */
2998 if (gest->in_taphold || (nfingers == 3 && three_finger_drag))
2999 ms->button |= gest->tap_button;
3000
3001 /*
3002 * For tap, we keep the maximum number of fingers and the
3003 * pressure peak.
3004 */
3005 gest->fingers_nb = MAX(nfingers, gest->fingers_nb);
3006 gest->zmax = MAX(z, gest->zmax);
3007
3008 dx = abs(x0 - start_x);
3009 dy = abs(y0 - start_y);
3010
3011 /*
3012 * A scrolling action must not conflict with a tap action.
3013 * Here are the conditions to consider a scrolling action:
3014 * - the action in a configurable area
3015 * - one of the following:
3016 * . the distance between the last packet and the
3017 * first should be above a configurable minimum
3018 * . tap timed out
3019 */
3020 if (!gest->in_taphold && !ms->button &&
3021 (!gest->in_vscroll || two_finger_scroll) &&
3022 (tscmp(time, &gest->taptimeout, >) ||
3023 ((gest->fingers_nb == 2 || !two_finger_scroll) &&
3024 (dx >= tpinfo->vscroll_min_delta * tphw->res_x ||
3025 dy >= tpinfo->vscroll_min_delta * tphw->res_y)))) {
3026 /*
3027 * Handle two finger scrolling.
3028 * Note that we don't rely on fingers_nb
3029 * as that keeps the maximum number of fingers.
3030 */
3031 if (two_finger_scroll) {
3032 if (nfingers == 2) {
3033 gest->in_vscroll += dy ? 2 : 0;
3034 gest->in_vscroll += dx ? 1 : 0;
3035 }
3036 } else {
3037 /* Check for horizontal scrolling. */
3038 if ((vscroll_hor_area > 0 &&
3039 start_y <= min_y + vscroll_hor_area) ||
3040 (vscroll_hor_area < 0 &&
3041 start_y >= max_y + vscroll_hor_area))
3042 gest->in_vscroll += 2;
3043
3044 /* Check for vertical scrolling. */
3045 if ((vscroll_ver_area > 0 &&
3046 start_x <= min_x + vscroll_ver_area) ||
3047 (vscroll_ver_area < 0 &&
3048 start_x >= max_x + vscroll_ver_area))
3049 gest->in_vscroll += 1;
3050 }
3051 /* Avoid conflicts if area overlaps. */
3052 if (gest->in_vscroll >= 3)
3053 gest->in_vscroll = (dx > dy) ? 2 : 1;
3054 }
3055 /*
3056 * Reset two finger scrolling when the number of fingers
3057 * is different from two or any button is pressed.
3058 */
3059 if (two_finger_scroll && gest->in_vscroll != 0 &&
3060 (nfingers != 2 || ms->button))
3061 gest->in_vscroll = 0;
3062
3063 debug("virtual scrolling: %s "
3064 "(direction=%d, dx=%d, dy=%d, fingers=%d)",
3065 gest->in_vscroll != 0 ? "YES" : "NO",
3066 gest->in_vscroll, dx, dy, gest->fingers_nb);
3067
3068 /* Workaround cursor jump on finger set changes */
3069 if (prev_nfingers != nfingers)
3070 return (GEST_IGNORE);
3071
3072 switch (gest->in_vscroll) {
3073 case 1:
3074 return (GEST_VSCROLL);
3075 case 2:
3076 return (GEST_HSCROLL);
3077 default:
3078 /* NO-OP */;
3079 }
3080
3081 /* Max delta is disabled for multi-fingers tap. */
3082 if (gest->fingers_nb == 1 &&
3083 tscmp(time, &gest->taptimeout, <=)) {
3084 tap_max_delta_x = tpinfo->tap_max_delta * tphw->res_x;
3085 tap_max_delta_y = tpinfo->tap_max_delta * tphw->res_y;
3086
3087 debug("dx=%d, dy=%d, deltax=%d, deltay=%d",
3088 dx, dy, tap_max_delta_x, tap_max_delta_y);
3089 if (dx > tap_max_delta_x || dy > tap_max_delta_y) {
3090 debug("not a tap");
3091 tsclr(&gest->taptimeout);
3092 }
3093 }
3094
3095 if (tscmp(time, &gest->taptimeout, <=))
3096 return (gest->fingers_nb > 1 ?
3097 GEST_IGNORE : GEST_ACCUMULATE);
3098 else
3099 return (GEST_MOVE);
3100 }
3101
3102 /*
3103 * Handle a case when clickpad pressure drops before than
3104 * button up event when surface is released after click.
3105 * It interferes with softbuttons.
3106 */
3107 if (tphw->is_clickpad && tpinfo->softbuttons_y != 0)
3108 ms->button &= ~MOUSE_BUTTON1DOWN;
3109
3110 gest->prev_nfingers = 0;
3111
3112 if (gest->fingerdown) {
3113 /*
3114 * An action is currently taking place but the pressure
3115 * dropped under the minimum, putting an end to it.
3116 */
3117
3118 gest->fingerdown = false;
3119
3120 /* Check for tap. */
3121 debug("zmax=%d fingers=%d", gest->zmax, gest->fingers_nb);
3122 if (!gest->in_vscroll && gest->zmax >= tpinfo->tap_threshold &&
3123 tscmp(time, &gest->taptimeout, <=)) {
3124 /*
3125 * We have a tap if:
3126 * - the maximum pressure went over tap_threshold
3127 * - the action ended before tap_timeout
3128 *
3129 * To handle tap-hold, we must delay any button push to
3130 * the next action.
3131 */
3132 if (gest->in_taphold) {
3133 /*
3134 * This is the second and last tap of a
3135 * double tap action, not a tap-hold.
3136 */
3137 gest->in_taphold = false;
3138
3139 /*
3140 * For double-tap to work:
3141 * - no button press is emitted (to
3142 * simulate a button release)
3143 * - PSM_FLAGS_FINGERDOWN is set to
3144 * force the next packet to emit a
3145 * button press)
3146 */
3147 debug("button RELEASE: %d", gest->tap_button);
3148 gest->fingerdown = true;
3149
3150 /* Schedule button press on next event */
3151 gest->idletimeout = 0;
3152 } else {
3153 /*
3154 * This is the first tap: we set the
3155 * tap-hold state and notify the button
3156 * down event.
3157 */
3158 gest->in_taphold = true;
3159 gest->idletimeout = tpinfo->taphold_timeout;
3160 gest->taptimeout = tsaddms(time, tap_timeout);
3161
3162 switch (gest->fingers_nb) {
3163 case 3:
3164 gest->tap_button =
3165 MOUSE_BUTTON2DOWN;
3166 break;
3167 case 2:
3168 gest->tap_button =
3169 MOUSE_BUTTON3DOWN;
3170 break;
3171 default:
3172 gest->tap_button =
3173 MOUSE_BUTTON1DOWN;
3174 }
3175 debug("button PRESS: %d", gest->tap_button);
3176 ms->button |= gest->tap_button;
3177 }
3178 } else {
3179 /*
3180 * Not enough pressure or timeout: reset
3181 * tap-hold state.
3182 */
3183 if (gest->in_taphold) {
3184 debug("button RELEASE: %d", gest->tap_button);
3185 gest->in_taphold = false;
3186 } else {
3187 debug("not a tap-hold");
3188 }
3189 }
3190 } else if (!gest->fingerdown && gest->in_taphold) {
3191 /*
3192 * For a tap-hold to work, the button must remain down at
3193 * least until timeout (where the in_taphold flags will be
3194 * cleared) or during the next action.
3195 */
3196 if (tscmp(time, &gest->taptimeout, <=)) {
3197 ms->button |= gest->tap_button;
3198 } else {
3199 debug("button RELEASE: %d", gest->tap_button);
3200 gest->in_taphold = false;
3201 }
3202 }
3203
3204 return (GEST_IGNORE);
3205 }
3206