1 /*
2 * Copyright © 2014 Red Hat, Inc.
3 * Copyright © 2014 Lyude Paul
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24 #include "config.h"
25 #include "libinput-version.h"
26 #include "evdev-tablet.h"
27
28 #include <assert.h>
29 #include <stdbool.h>
30 #include <string.h>
31
32 #if HAVE_LIBWACOM
33 #include <libwacom/libwacom.h>
34 #endif
35
36 /* The tablet sends events every ~2ms , 50ms should be plenty enough to
37 detect out-of-range.
38 This value is higher during test suite runs */
39 static int FORCED_PROXOUT_TIMEOUT = 50 * 1000; /* µs */
40
41 #define tablet_set_status(tablet_,s_) (tablet_)->status |= (s_)
42 #define tablet_unset_status(tablet_,s_) (tablet_)->status &= ~(s_)
43 #define tablet_has_status(tablet_,s_) (!!((tablet_)->status & (s_)))
44
45 static inline void
tablet_get_pressed_buttons(struct tablet_dispatch * tablet,struct button_state * buttons)46 tablet_get_pressed_buttons(struct tablet_dispatch *tablet,
47 struct button_state *buttons)
48 {
49 size_t i;
50 const struct button_state *state = &tablet->button_state,
51 *prev_state = &tablet->prev_button_state;
52
53 for (i = 0; i < sizeof(buttons->bits); i++)
54 buttons->bits[i] = state->bits[i] & ~(prev_state->bits[i]);
55 }
56
57 static inline void
tablet_get_released_buttons(struct tablet_dispatch * tablet,struct button_state * buttons)58 tablet_get_released_buttons(struct tablet_dispatch *tablet,
59 struct button_state *buttons)
60 {
61 size_t i;
62 const struct button_state *state = &tablet->button_state,
63 *prev_state = &tablet->prev_button_state;
64
65 for (i = 0; i < sizeof(buttons->bits); i++)
66 buttons->bits[i] = prev_state->bits[i] &
67 ~(state->bits[i]);
68 }
69
70 /* Merge the previous state with the current one so all buttons look like
71 * they just got pressed in this frame */
72 static inline void
tablet_force_button_presses(struct tablet_dispatch * tablet)73 tablet_force_button_presses(struct tablet_dispatch *tablet)
74 {
75 struct button_state *state = &tablet->button_state,
76 *prev_state = &tablet->prev_button_state;
77 size_t i;
78
79 for (i = 0; i < sizeof(state->bits); i++) {
80 state->bits[i] = state->bits[i] | prev_state->bits[i];
81 prev_state->bits[i] = 0;
82 }
83 }
84
85 static inline size_t
tablet_history_size(const struct tablet_dispatch * tablet)86 tablet_history_size(const struct tablet_dispatch *tablet)
87 {
88 return ARRAY_LENGTH(tablet->history.samples);
89 }
90
91 static inline void
tablet_history_reset(struct tablet_dispatch * tablet)92 tablet_history_reset(struct tablet_dispatch *tablet)
93 {
94 tablet->history.count = 0;
95 }
96
97 static inline void
tablet_history_push(struct tablet_dispatch * tablet,const struct tablet_axes * axes)98 tablet_history_push(struct tablet_dispatch *tablet,
99 const struct tablet_axes *axes)
100 {
101 unsigned int index = (tablet->history.index + 1) %
102 tablet_history_size(tablet);
103
104 tablet->history.samples[index] = *axes;
105 tablet->history.index = index;
106 tablet->history.count = min(tablet->history.count + 1,
107 tablet_history_size(tablet));
108
109 if (tablet->history.count < tablet_history_size(tablet))
110 tablet_history_push(tablet, axes);
111 }
112
113 /**
114 * Return a previous axis state, where index of 0 means "most recent", 1 is
115 * "one before most recent", etc.
116 */
117 static inline const struct tablet_axes*
tablet_history_get(const struct tablet_dispatch * tablet,unsigned int index)118 tablet_history_get(const struct tablet_dispatch *tablet, unsigned int index)
119 {
120 size_t sz = tablet_history_size(tablet);
121
122 assert(index < sz);
123 assert(index < tablet->history.count);
124
125 index = (tablet->history.index + sz - index) % sz;
126 return &tablet->history.samples[index];
127 }
128
129 static inline void
tablet_reset_changed_axes(struct tablet_dispatch * tablet)130 tablet_reset_changed_axes(struct tablet_dispatch *tablet)
131 {
132 memset(tablet->changed_axes, 0, sizeof(tablet->changed_axes));
133 }
134
135 static bool
tablet_device_has_axis(struct tablet_dispatch * tablet,enum libinput_tablet_tool_axis axis)136 tablet_device_has_axis(struct tablet_dispatch *tablet,
137 enum libinput_tablet_tool_axis axis)
138 {
139 struct libevdev *evdev = tablet->device->evdev;
140 bool has_axis = false;
141 unsigned int code;
142
143 if (axis == LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z) {
144 has_axis = (libevdev_has_event_code(evdev,
145 EV_KEY,
146 BTN_TOOL_MOUSE) &&
147 libevdev_has_event_code(evdev,
148 EV_ABS,
149 ABS_TILT_X) &&
150 libevdev_has_event_code(evdev,
151 EV_ABS,
152 ABS_TILT_Y));
153 code = axis_to_evcode(axis);
154 has_axis |= libevdev_has_event_code(evdev,
155 EV_ABS,
156 code);
157 } else if (axis == LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL) {
158 has_axis = libevdev_has_event_code(evdev,
159 EV_REL,
160 REL_WHEEL);
161 } else {
162 code = axis_to_evcode(axis);
163 has_axis = libevdev_has_event_code(evdev,
164 EV_ABS,
165 code);
166 }
167
168 return has_axis;
169 }
170
171 static inline bool
tablet_filter_axis_fuzz(const struct tablet_dispatch * tablet,const struct evdev_device * device,const struct input_event * e,enum libinput_tablet_tool_axis axis)172 tablet_filter_axis_fuzz(const struct tablet_dispatch *tablet,
173 const struct evdev_device *device,
174 const struct input_event *e,
175 enum libinput_tablet_tool_axis axis)
176 {
177 int delta, fuzz;
178 int current, previous;
179
180 previous = tablet->prev_value[axis];
181 current = e->value;
182 delta = previous - current;
183
184 fuzz = libevdev_get_abs_fuzz(device->evdev, e->code);
185
186 /* ABS_DISTANCE doesn't have have fuzz set and causes continuous
187 * updates for the cursor/lens tools. Add a minimum fuzz of 2, same
188 * as the xf86-input-wacom driver
189 */
190 switch (e->code) {
191 case ABS_DISTANCE:
192 fuzz = max(2, fuzz);
193 break;
194 default:
195 break;
196 }
197
198 return abs(delta) <= fuzz;
199 }
200
201 static void
tablet_process_absolute(struct tablet_dispatch * tablet,struct evdev_device * device,struct input_event * e,uint64_t time)202 tablet_process_absolute(struct tablet_dispatch *tablet,
203 struct evdev_device *device,
204 struct input_event *e,
205 uint64_t time)
206 {
207 enum libinput_tablet_tool_axis axis;
208
209 switch (e->code) {
210 case ABS_X:
211 case ABS_Y:
212 case ABS_Z:
213 case ABS_PRESSURE:
214 case ABS_TILT_X:
215 case ABS_TILT_Y:
216 case ABS_DISTANCE:
217 case ABS_WHEEL:
218 axis = evcode_to_axis(e->code);
219 if (axis == LIBINPUT_TABLET_TOOL_AXIS_NONE) {
220 evdev_log_bug_libinput(device,
221 "Invalid ABS event code %#x\n",
222 e->code);
223 break;
224 }
225
226 tablet->prev_value[axis] = tablet->current_value[axis];
227 if (tablet_filter_axis_fuzz(tablet, device, e, axis))
228 break;
229
230 tablet->current_value[axis] = e->value;
231 set_bit(tablet->changed_axes, axis);
232 tablet_set_status(tablet, TABLET_AXES_UPDATED);
233 break;
234 /* tool_id is the identifier for the tool we can use in libwacom
235 * to identify it (if we have one anyway) */
236 case ABS_MISC:
237 tablet->current_tool_id = e->value;
238 break;
239 /* Intuos 3 strip data. Should only happen on the Pad device, not on
240 the Pen device. */
241 case ABS_RX:
242 case ABS_RY:
243 /* Only on the 4D mouse (Intuos2), obsolete */
244 case ABS_RZ:
245 /* Only on the 4D mouse (Intuos2), obsolete.
246 The 24HD sends ABS_THROTTLE on the Pad device for the second
247 wheel but we shouldn't get here on kernel >= 3.17.
248 */
249 case ABS_THROTTLE:
250 default:
251 evdev_log_info(device,
252 "Unhandled ABS event code %#x\n",
253 e->code);
254 break;
255 }
256 }
257
258 static void
tablet_change_to_left_handed(struct evdev_device * device)259 tablet_change_to_left_handed(struct evdev_device *device)
260 {
261 struct tablet_dispatch *tablet = tablet_dispatch(device->dispatch);
262
263 if (device->left_handed.enabled == device->left_handed.want_enabled)
264 return;
265
266 if (!tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY))
267 return;
268
269 device->left_handed.enabled = device->left_handed.want_enabled;
270 }
271
272 static void
tablet_update_tool(struct tablet_dispatch * tablet,struct evdev_device * device,enum libinput_tablet_tool_type tool,bool enabled)273 tablet_update_tool(struct tablet_dispatch *tablet,
274 struct evdev_device *device,
275 enum libinput_tablet_tool_type tool,
276 bool enabled)
277 {
278 assert(tool != LIBINPUT_TOOL_NONE);
279
280 if (enabled) {
281 tablet->current_tool_type = tool;
282 tablet_set_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY);
283 tablet_unset_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
284 }
285 else if (!tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY)) {
286 tablet_set_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
287 }
288 }
289
290 static inline double
normalize_slider(const struct input_absinfo * absinfo)291 normalize_slider(const struct input_absinfo *absinfo)
292 {
293 double range = absinfo->maximum - absinfo->minimum;
294 double value = (absinfo->value - absinfo->minimum) / range;
295
296 return value * 2 - 1;
297 }
298
299 static inline double
normalize_distance(const struct input_absinfo * absinfo)300 normalize_distance(const struct input_absinfo *absinfo)
301 {
302 double range = absinfo->maximum - absinfo->minimum;
303 double value = (absinfo->value - absinfo->minimum) / range;
304
305 return value;
306 }
307
308 static inline double
normalize_pressure(const struct input_absinfo * absinfo,struct libinput_tablet_tool * tool)309 normalize_pressure(const struct input_absinfo *absinfo,
310 struct libinput_tablet_tool *tool)
311 {
312 double range = absinfo->maximum - absinfo->minimum;
313 int offset = tool->has_pressure_offset ?
314 tool->pressure_offset : 0;
315 double value = (absinfo->value - offset - absinfo->minimum) / range;
316
317 return value;
318 }
319
320 static inline double
adjust_tilt(const struct input_absinfo * absinfo)321 adjust_tilt(const struct input_absinfo *absinfo)
322 {
323 double range = absinfo->maximum - absinfo->minimum;
324 double value = (absinfo->value - absinfo->minimum) / range;
325 const int WACOM_MAX_DEGREES = 64;
326
327 /* If resolution is nonzero, it's in units/radian. But require
328 * a min/max less/greater than zero so we can assume 0 is the
329 * center */
330 if (absinfo->resolution != 0 &&
331 absinfo->maximum > 0 &&
332 absinfo->minimum < 0) {
333 value = 180.0/M_PI * absinfo->value/absinfo->resolution;
334 } else {
335 /* Wacom supports physical [-64, 64] degrees, so map to that by
336 * default. If other tablets have a different physical range or
337 * nonzero physical offsets, they need extra treatment
338 * here.
339 */
340 /* Map to the (-1, 1) range */
341 value = (value * 2) - 1;
342 value *= WACOM_MAX_DEGREES;
343 }
344
345 return value;
346 }
347
348 static inline int32_t
invert_axis(const struct input_absinfo * absinfo)349 invert_axis(const struct input_absinfo *absinfo)
350 {
351 return absinfo->maximum - (absinfo->value - absinfo->minimum);
352 }
353
354 static void
convert_tilt_to_rotation(struct tablet_dispatch * tablet)355 convert_tilt_to_rotation(struct tablet_dispatch *tablet)
356 {
357 const int offset = 5;
358 double x, y;
359 double angle = 0.0;
360
361 /* Wacom Intuos 4, 5, Pro mouse calculates rotation from the x/y tilt
362 values. The device has a 175 degree CCW hardware offset but since we use
363 atan2 the effective offset is just 5 degrees.
364 */
365 x = tablet->axes.tilt.x;
366 y = tablet->axes.tilt.y;
367
368 /* atan2 is CCW, we want CW -> negate x */
369 if (x || y)
370 angle = ((180.0 * atan2(-x, y)) / M_PI);
371
372 angle = fmod(360 + angle - offset, 360);
373
374 tablet->axes.rotation = angle;
375 set_bit(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z);
376 }
377
378 static double
convert_to_degrees(const struct input_absinfo * absinfo,double offset)379 convert_to_degrees(const struct input_absinfo *absinfo, double offset)
380 {
381 /* range is [0, 360[, i.e. range + 1 */
382 double range = absinfo->maximum - absinfo->minimum + 1;
383 double value = (absinfo->value - absinfo->minimum) / range;
384
385 return fmod(value * 360.0 + offset, 360.0);
386 }
387
388 static inline double
normalize_wheel(struct tablet_dispatch * tablet,int value)389 normalize_wheel(struct tablet_dispatch *tablet,
390 int value)
391 {
392 struct evdev_device *device = tablet->device;
393
394 return value * device->scroll.wheel_click_angle.x;
395 }
396
397 static inline void
tablet_update_xy(struct tablet_dispatch * tablet,struct evdev_device * device)398 tablet_update_xy(struct tablet_dispatch *tablet,
399 struct evdev_device *device)
400 {
401 const struct input_absinfo *absinfo;
402 int value;
403
404 if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_X) ||
405 bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_Y)) {
406 absinfo = libevdev_get_abs_info(device->evdev, ABS_X);
407
408 if (device->left_handed.enabled)
409 value = invert_axis(absinfo);
410 else
411 value = absinfo->value;
412
413 tablet->axes.point.x = value;
414
415 absinfo = libevdev_get_abs_info(device->evdev, ABS_Y);
416
417 if (device->left_handed.enabled)
418 value = invert_axis(absinfo);
419 else
420 value = absinfo->value;
421
422 tablet->axes.point.y = value;
423
424 evdev_transform_absolute(device, &tablet->axes.point);
425 }
426 }
427
428 static inline struct normalized_coords
tablet_tool_process_delta(struct tablet_dispatch * tablet,struct libinput_tablet_tool * tool,const struct evdev_device * device,struct tablet_axes * axes,uint64_t time)429 tablet_tool_process_delta(struct tablet_dispatch *tablet,
430 struct libinput_tablet_tool *tool,
431 const struct evdev_device *device,
432 struct tablet_axes *axes,
433 uint64_t time)
434 {
435 const struct normalized_coords zero = { 0.0, 0.0 };
436 struct device_coords delta = { 0, 0 };
437 struct device_float_coords accel;
438
439 /* When tool contact changes, we probably got a cursor jump. Don't
440 try to calculate a delta for that event */
441 if (!tablet_has_status(tablet,
442 TABLET_TOOL_ENTERING_PROXIMITY) &&
443 !tablet_has_status(tablet, TABLET_TOOL_ENTERING_CONTACT) &&
444 !tablet_has_status(tablet, TABLET_TOOL_LEAVING_CONTACT) &&
445 (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_X) ||
446 bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_Y))) {
447 delta.x = axes->point.x - tablet->last_smooth_point.x;
448 delta.y = axes->point.y - tablet->last_smooth_point.y;
449 }
450
451 if (axes->point.x != tablet->last_smooth_point.x)
452 set_bit(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_X);
453 if (axes->point.y != tablet->last_smooth_point.y)
454 set_bit(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_Y);
455
456 tablet->last_smooth_point = axes->point;
457
458 accel.x = 1.0 * delta.x;
459 accel.y = 1.0 * delta.y;
460
461 if (device_float_is_zero(accel))
462 return zero;
463
464 return filter_dispatch(device->pointer.filter,
465 &accel,
466 tool,
467 time);
468 }
469
470 static inline void
tablet_update_pressure(struct tablet_dispatch * tablet,struct evdev_device * device,struct libinput_tablet_tool * tool)471 tablet_update_pressure(struct tablet_dispatch *tablet,
472 struct evdev_device *device,
473 struct libinput_tablet_tool *tool)
474 {
475 const struct input_absinfo *absinfo;
476
477 if (bit_is_set(tablet->changed_axes,
478 LIBINPUT_TABLET_TOOL_AXIS_PRESSURE)) {
479 absinfo = libevdev_get_abs_info(device->evdev, ABS_PRESSURE);
480 tablet->axes.pressure = normalize_pressure(absinfo, tool);
481 }
482 }
483
484 static inline void
tablet_update_distance(struct tablet_dispatch * tablet,struct evdev_device * device)485 tablet_update_distance(struct tablet_dispatch *tablet,
486 struct evdev_device *device)
487 {
488 const struct input_absinfo *absinfo;
489
490 if (bit_is_set(tablet->changed_axes,
491 LIBINPUT_TABLET_TOOL_AXIS_DISTANCE)) {
492 absinfo = libevdev_get_abs_info(device->evdev, ABS_DISTANCE);
493 tablet->axes.distance = normalize_distance(absinfo);
494 }
495 }
496
497 static inline void
tablet_update_slider(struct tablet_dispatch * tablet,struct evdev_device * device)498 tablet_update_slider(struct tablet_dispatch *tablet,
499 struct evdev_device *device)
500 {
501 const struct input_absinfo *absinfo;
502
503 if (bit_is_set(tablet->changed_axes,
504 LIBINPUT_TABLET_TOOL_AXIS_SLIDER)) {
505 absinfo = libevdev_get_abs_info(device->evdev, ABS_WHEEL);
506 tablet->axes.slider = normalize_slider(absinfo);
507 }
508 }
509
510 static inline void
tablet_update_tilt(struct tablet_dispatch * tablet,struct evdev_device * device)511 tablet_update_tilt(struct tablet_dispatch *tablet,
512 struct evdev_device *device)
513 {
514 const struct input_absinfo *absinfo;
515
516 /* mouse rotation resets tilt to 0 so always fetch both axes if
517 * either has changed */
518 if (bit_is_set(tablet->changed_axes,
519 LIBINPUT_TABLET_TOOL_AXIS_TILT_X) ||
520 bit_is_set(tablet->changed_axes,
521 LIBINPUT_TABLET_TOOL_AXIS_TILT_Y)) {
522
523 absinfo = libevdev_get_abs_info(device->evdev, ABS_TILT_X);
524 tablet->axes.tilt.x = adjust_tilt(absinfo);
525
526 absinfo = libevdev_get_abs_info(device->evdev, ABS_TILT_Y);
527 tablet->axes.tilt.y = adjust_tilt(absinfo);
528
529 if (device->left_handed.enabled) {
530 tablet->axes.tilt.x *= -1;
531 tablet->axes.tilt.y *= -1;
532 }
533 }
534 }
535
536 static inline void
tablet_update_artpen_rotation(struct tablet_dispatch * tablet,struct evdev_device * device)537 tablet_update_artpen_rotation(struct tablet_dispatch *tablet,
538 struct evdev_device *device)
539 {
540 const struct input_absinfo *absinfo;
541
542 if (bit_is_set(tablet->changed_axes,
543 LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z)) {
544 absinfo = libevdev_get_abs_info(device->evdev,
545 ABS_Z);
546 /* artpen has 0 with buttons pointing east */
547 tablet->axes.rotation = convert_to_degrees(absinfo, 90);
548 }
549 }
550
551 static inline void
tablet_update_mouse_rotation(struct tablet_dispatch * tablet,struct evdev_device * device)552 tablet_update_mouse_rotation(struct tablet_dispatch *tablet,
553 struct evdev_device *device)
554 {
555 if (bit_is_set(tablet->changed_axes,
556 LIBINPUT_TABLET_TOOL_AXIS_TILT_X) ||
557 bit_is_set(tablet->changed_axes,
558 LIBINPUT_TABLET_TOOL_AXIS_TILT_Y)) {
559 convert_tilt_to_rotation(tablet);
560 }
561 }
562
563 static inline void
tablet_update_rotation(struct tablet_dispatch * tablet,struct evdev_device * device)564 tablet_update_rotation(struct tablet_dispatch *tablet,
565 struct evdev_device *device)
566 {
567 /* We must check ROTATION_Z after TILT_X/Y so that the tilt axes are
568 * already normalized and set if we have the mouse/lens tool */
569 if (tablet->current_tool_type == LIBINPUT_TABLET_TOOL_TYPE_MOUSE ||
570 tablet->current_tool_type == LIBINPUT_TABLET_TOOL_TYPE_LENS) {
571 tablet_update_mouse_rotation(tablet, device);
572 clear_bit(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_TILT_X);
573 clear_bit(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_TILT_Y);
574 tablet->axes.tilt.x = 0;
575 tablet->axes.tilt.y = 0;
576
577 /* tilt is already converted to left-handed, so mouse
578 * rotation is converted to left-handed automatically */
579 } else {
580
581 tablet_update_artpen_rotation(tablet, device);
582
583 if (device->left_handed.enabled) {
584 double r = tablet->axes.rotation;
585 tablet->axes.rotation = fmod(180 + r, 360);
586 }
587 }
588 }
589
590 static inline void
tablet_update_wheel(struct tablet_dispatch * tablet,struct evdev_device * device)591 tablet_update_wheel(struct tablet_dispatch *tablet,
592 struct evdev_device *device)
593 {
594 int a;
595
596 a = LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL;
597 if (bit_is_set(tablet->changed_axes, a)) {
598 /* tablet->axes.wheel_discrete is already set */
599 tablet->axes.wheel = normalize_wheel(tablet,
600 tablet->axes.wheel_discrete);
601 } else {
602 tablet->axes.wheel = 0;
603 tablet->axes.wheel_discrete = 0;
604 }
605 }
606
607 static void
tablet_smoothen_axes(const struct tablet_dispatch * tablet,struct tablet_axes * axes)608 tablet_smoothen_axes(const struct tablet_dispatch *tablet,
609 struct tablet_axes *axes)
610 {
611 size_t i;
612 size_t count = tablet_history_size(tablet);
613 struct tablet_axes smooth = { 0 };
614
615 for (i = 0; i < count; i++) {
616 const struct tablet_axes *a = tablet_history_get(tablet, i);
617
618 smooth.point.x += a->point.x;
619 smooth.point.y += a->point.y;
620
621 smooth.tilt.x += a->tilt.x;
622 smooth.tilt.y += a->tilt.y;
623 }
624
625 axes->point.x = smooth.point.x/count;
626 axes->point.y = smooth.point.y/count;
627
628 axes->tilt.x = smooth.tilt.x/count;
629 axes->tilt.y = smooth.tilt.y/count;
630 }
631
632 static bool
tablet_check_notify_axes(struct tablet_dispatch * tablet,struct evdev_device * device,struct libinput_tablet_tool * tool,struct tablet_axes * axes_out,uint64_t time)633 tablet_check_notify_axes(struct tablet_dispatch *tablet,
634 struct evdev_device *device,
635 struct libinput_tablet_tool *tool,
636 struct tablet_axes *axes_out,
637 uint64_t time)
638 {
639 struct tablet_axes axes = {0};
640 const char tmp[sizeof(tablet->changed_axes)] = {0};
641 bool rc = false;
642
643 if (memcmp(tmp, tablet->changed_axes, sizeof(tmp)) == 0) {
644 axes = tablet->axes;
645 goto out;
646 }
647
648 tablet_update_xy(tablet, device);
649 tablet_update_pressure(tablet, device, tool);
650 tablet_update_distance(tablet, device);
651 tablet_update_slider(tablet, device);
652 tablet_update_tilt(tablet, device);
653 tablet_update_wheel(tablet, device);
654 /* We must check ROTATION_Z after TILT_X/Y so that the tilt axes are
655 * already normalized and set if we have the mouse/lens tool */
656 tablet_update_rotation(tablet, device);
657
658 axes.point = tablet->axes.point;
659 axes.pressure = tablet->axes.pressure;
660 axes.distance = tablet->axes.distance;
661 axes.slider = tablet->axes.slider;
662 axes.tilt = tablet->axes.tilt;
663 axes.wheel = tablet->axes.wheel;
664 axes.wheel_discrete = tablet->axes.wheel_discrete;
665 axes.rotation = tablet->axes.rotation;
666
667 rc = true;
668
669 out:
670 /* The tool position often jumps to a different spot when contact changes.
671 * If tool contact changes, clear the history to prevent axis smoothing
672 * from trying to average over the spatial discontinuity. */
673 if (tablet_has_status(tablet, TABLET_TOOL_ENTERING_CONTACT) ||
674 tablet_has_status(tablet, TABLET_TOOL_LEAVING_CONTACT)) {
675 tablet_history_reset(tablet);
676 }
677
678 tablet_history_push(tablet, &tablet->axes);
679 tablet_smoothen_axes(tablet, &axes);
680
681 /* The delta relies on the last *smooth* point, so we do it last */
682 axes.delta = tablet_tool_process_delta(tablet, tool, device, &axes, time);
683
684 *axes_out = axes;
685
686 return rc;
687 }
688
689 static void
tablet_update_button(struct tablet_dispatch * tablet,uint32_t evcode,uint32_t enable)690 tablet_update_button(struct tablet_dispatch *tablet,
691 uint32_t evcode,
692 uint32_t enable)
693 {
694 switch (evcode) {
695 case BTN_LEFT:
696 case BTN_RIGHT:
697 case BTN_MIDDLE:
698 case BTN_SIDE:
699 case BTN_EXTRA:
700 case BTN_FORWARD:
701 case BTN_BACK:
702 case BTN_TASK:
703 case BTN_STYLUS:
704 case BTN_STYLUS2:
705 break;
706 default:
707 evdev_log_info(tablet->device,
708 "Unhandled button %s (%#x)\n",
709 libevdev_event_code_get_name(EV_KEY, evcode),
710 evcode);
711 return;
712 }
713
714 if (enable) {
715 set_bit(tablet->button_state.bits, evcode);
716 tablet_set_status(tablet, TABLET_BUTTONS_PRESSED);
717 } else {
718 clear_bit(tablet->button_state.bits, evcode);
719 tablet_set_status(tablet, TABLET_BUTTONS_RELEASED);
720 }
721 }
722
723 static inline enum libinput_tablet_tool_type
tablet_evcode_to_tool(int code)724 tablet_evcode_to_tool(int code)
725 {
726 enum libinput_tablet_tool_type type;
727
728 switch (code) {
729 case BTN_TOOL_PEN: type = LIBINPUT_TABLET_TOOL_TYPE_PEN; break;
730 case BTN_TOOL_RUBBER: type = LIBINPUT_TABLET_TOOL_TYPE_ERASER; break;
731 case BTN_TOOL_BRUSH: type = LIBINPUT_TABLET_TOOL_TYPE_BRUSH; break;
732 case BTN_TOOL_PENCIL: type = LIBINPUT_TABLET_TOOL_TYPE_PENCIL; break;
733 case BTN_TOOL_AIRBRUSH: type = LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH; break;
734 case BTN_TOOL_MOUSE: type = LIBINPUT_TABLET_TOOL_TYPE_MOUSE; break;
735 case BTN_TOOL_LENS: type = LIBINPUT_TABLET_TOOL_TYPE_LENS; break;
736 default:
737 abort();
738 }
739
740 return type;
741 }
742
743 static void
tablet_process_key(struct tablet_dispatch * tablet,struct evdev_device * device,struct input_event * e,uint64_t time)744 tablet_process_key(struct tablet_dispatch *tablet,
745 struct evdev_device *device,
746 struct input_event *e,
747 uint64_t time)
748 {
749 switch (e->code) {
750 case BTN_TOOL_FINGER:
751 evdev_log_bug_libinput(device,
752 "Invalid tool 'finger' on tablet interface\n");
753 break;
754 case BTN_TOOL_PEN:
755 case BTN_TOOL_RUBBER:
756 case BTN_TOOL_BRUSH:
757 case BTN_TOOL_PENCIL:
758 case BTN_TOOL_AIRBRUSH:
759 case BTN_TOOL_MOUSE:
760 case BTN_TOOL_LENS:
761 tablet_update_tool(tablet,
762 device,
763 tablet_evcode_to_tool(e->code),
764 e->value);
765 break;
766 case BTN_TOUCH:
767 if (!bit_is_set(tablet->axis_caps,
768 LIBINPUT_TABLET_TOOL_AXIS_PRESSURE)) {
769 if (e->value)
770 tablet_set_status(tablet,
771 TABLET_TOOL_ENTERING_CONTACT);
772 else
773 tablet_set_status(tablet,
774 TABLET_TOOL_LEAVING_CONTACT);
775 }
776 break;
777 default:
778 tablet_update_button(tablet, e->code, e->value);
779 break;
780 }
781 }
782
783 static void
tablet_process_relative(struct tablet_dispatch * tablet,struct evdev_device * device,struct input_event * e,uint64_t time)784 tablet_process_relative(struct tablet_dispatch *tablet,
785 struct evdev_device *device,
786 struct input_event *e,
787 uint64_t time)
788 {
789 enum libinput_tablet_tool_axis axis;
790
791 switch (e->code) {
792 case REL_WHEEL:
793 axis = rel_evcode_to_axis(e->code);
794 if (axis == LIBINPUT_TABLET_TOOL_AXIS_NONE) {
795 evdev_log_bug_libinput(device,
796 "Invalid ABS event code %#x\n",
797 e->code);
798 break;
799 }
800 set_bit(tablet->changed_axes, axis);
801 tablet->axes.wheel_discrete = -1 * e->value;
802 tablet_set_status(tablet, TABLET_AXES_UPDATED);
803 break;
804 default:
805 evdev_log_info(device,
806 "Unhandled relative axis %s (%#x)\n",
807 libevdev_event_code_get_name(EV_REL, e->code),
808 e->code);
809 return;
810 }
811 }
812
813 static void
tablet_process_misc(struct tablet_dispatch * tablet,struct evdev_device * device,struct input_event * e,uint64_t time)814 tablet_process_misc(struct tablet_dispatch *tablet,
815 struct evdev_device *device,
816 struct input_event *e,
817 uint64_t time)
818 {
819 switch (e->code) {
820 case MSC_SERIAL:
821 if (e->value != -1)
822 tablet->current_tool_serial = e->value;
823
824 break;
825 case MSC_SCAN:
826 break;
827 default:
828 evdev_log_info(device,
829 "Unhandled MSC event code %s (%#x)\n",
830 libevdev_event_code_get_name(EV_MSC, e->code),
831 e->code);
832 break;
833 }
834 }
835
836 static inline void
copy_axis_cap(const struct tablet_dispatch * tablet,struct libinput_tablet_tool * tool,enum libinput_tablet_tool_axis axis)837 copy_axis_cap(const struct tablet_dispatch *tablet,
838 struct libinput_tablet_tool *tool,
839 enum libinput_tablet_tool_axis axis)
840 {
841 if (bit_is_set(tablet->axis_caps, axis))
842 set_bit(tool->axis_caps, axis);
843 }
844
845 static inline void
copy_button_cap(const struct tablet_dispatch * tablet,struct libinput_tablet_tool * tool,uint32_t button)846 copy_button_cap(const struct tablet_dispatch *tablet,
847 struct libinput_tablet_tool *tool,
848 uint32_t button)
849 {
850 struct libevdev *evdev = tablet->device->evdev;
851 if (libevdev_has_event_code(evdev, EV_KEY, button))
852 set_bit(tool->buttons, button);
853 }
854
855 static inline int
tool_set_bits_from_libwacom(const struct tablet_dispatch * tablet,struct libinput_tablet_tool * tool)856 tool_set_bits_from_libwacom(const struct tablet_dispatch *tablet,
857 struct libinput_tablet_tool *tool)
858 {
859 int rc = 1;
860
861 #if HAVE_LIBWACOM
862 WacomDeviceDatabase *db;
863 const WacomStylus *s = NULL;
864 int code;
865 WacomStylusType type;
866 WacomAxisTypeFlags axes;
867
868 db = libwacom_database_new();
869 if (!db) {
870 evdev_log_info(tablet->device,
871 "Failed to initialize libwacom context.\n");
872 goto out;
873 }
874 s = libwacom_stylus_get_for_id(db, tool->tool_id);
875 if (!s)
876 goto out;
877
878 type = libwacom_stylus_get_type(s);
879 if (type == WSTYLUS_PUCK) {
880 for (code = BTN_LEFT;
881 code < BTN_LEFT + libwacom_stylus_get_num_buttons(s);
882 code++)
883 copy_button_cap(tablet, tool, code);
884 } else {
885 if (libwacom_stylus_get_num_buttons(s) >= 2)
886 copy_button_cap(tablet, tool, BTN_STYLUS2);
887 if (libwacom_stylus_get_num_buttons(s) >= 1)
888 copy_button_cap(tablet, tool, BTN_STYLUS);
889 }
890
891 if (libwacom_stylus_has_wheel(s))
892 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL);
893
894 axes = libwacom_stylus_get_axes(s);
895
896 if (axes & WACOM_AXIS_TYPE_TILT) {
897 /* tilt on the puck is converted to rotation */
898 if (type == WSTYLUS_PUCK) {
899 set_bit(tool->axis_caps,
900 LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z);
901 } else {
902 copy_axis_cap(tablet,
903 tool,
904 LIBINPUT_TABLET_TOOL_AXIS_TILT_X);
905 copy_axis_cap(tablet,
906 tool,
907 LIBINPUT_TABLET_TOOL_AXIS_TILT_Y);
908 }
909 }
910 if (axes & WACOM_AXIS_TYPE_ROTATION_Z)
911 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z);
912 if (axes & WACOM_AXIS_TYPE_DISTANCE)
913 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_DISTANCE);
914 if (axes & WACOM_AXIS_TYPE_SLIDER)
915 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_SLIDER);
916 if (axes & WACOM_AXIS_TYPE_PRESSURE)
917 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);
918
919 rc = 0;
920 out:
921 if (db)
922 libwacom_database_destroy(db);
923 #endif
924 return rc;
925 }
926
927 static void
tool_set_bits(const struct tablet_dispatch * tablet,struct libinput_tablet_tool * tool)928 tool_set_bits(const struct tablet_dispatch *tablet,
929 struct libinput_tablet_tool *tool)
930 {
931 enum libinput_tablet_tool_type type = tool->type;
932
933 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_X);
934 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_Y);
935
936 #if HAVE_LIBWACOM
937 if (tool_set_bits_from_libwacom(tablet, tool) == 0)
938 return;
939 #endif
940 /* If we don't have libwacom, we simply copy any axis we have on the
941 tablet onto the tool. Except we know that mice only have rotation
942 anyway.
943 */
944 switch (type) {
945 case LIBINPUT_TABLET_TOOL_TYPE_PEN:
946 case LIBINPUT_TABLET_TOOL_TYPE_ERASER:
947 case LIBINPUT_TABLET_TOOL_TYPE_PENCIL:
948 case LIBINPUT_TABLET_TOOL_TYPE_BRUSH:
949 case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH:
950 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);
951 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_DISTANCE);
952 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_TILT_X);
953 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_TILT_Y);
954 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_SLIDER);
955
956 /* Rotation is special, it can be either ABS_Z or
957 * BTN_TOOL_MOUSE+ABS_TILT_X/Y. Aiptek tablets have
958 * mouse+tilt (and thus rotation), but they do not have
959 * ABS_Z. So let's not copy the axis bit if we don't have
960 * ABS_Z, otherwise we try to get the value from it later on
961 * proximity in and go boom because the absinfo isn't there.
962 */
963 if (libevdev_has_event_code(tablet->device->evdev, EV_ABS,
964 ABS_Z))
965 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z);
966 break;
967 case LIBINPUT_TABLET_TOOL_TYPE_MOUSE:
968 case LIBINPUT_TABLET_TOOL_TYPE_LENS:
969 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z);
970 copy_axis_cap(tablet, tool, LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL);
971 break;
972 default:
973 break;
974 }
975
976 /* If we don't have libwacom, copy all pen-related buttons from the
977 tablet vs all mouse-related buttons */
978 switch (type) {
979 case LIBINPUT_TABLET_TOOL_TYPE_PEN:
980 case LIBINPUT_TABLET_TOOL_TYPE_BRUSH:
981 case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH:
982 case LIBINPUT_TABLET_TOOL_TYPE_PENCIL:
983 case LIBINPUT_TABLET_TOOL_TYPE_ERASER:
984 copy_button_cap(tablet, tool, BTN_STYLUS);
985 copy_button_cap(tablet, tool, BTN_STYLUS2);
986 break;
987 case LIBINPUT_TABLET_TOOL_TYPE_MOUSE:
988 case LIBINPUT_TABLET_TOOL_TYPE_LENS:
989 copy_button_cap(tablet, tool, BTN_LEFT);
990 copy_button_cap(tablet, tool, BTN_MIDDLE);
991 copy_button_cap(tablet, tool, BTN_RIGHT);
992 copy_button_cap(tablet, tool, BTN_SIDE);
993 copy_button_cap(tablet, tool, BTN_EXTRA);
994 break;
995 default:
996 break;
997 }
998 }
999
1000 static inline int
axis_range_percentage(const struct input_absinfo * a,double percent)1001 axis_range_percentage(const struct input_absinfo *a, double percent)
1002 {
1003 return (a->maximum - a->minimum) * percent/100.0 + a->minimum;
1004 }
1005
1006 static struct libinput_tablet_tool *
tablet_get_tool(struct tablet_dispatch * tablet,enum libinput_tablet_tool_type type,uint32_t tool_id,uint32_t serial)1007 tablet_get_tool(struct tablet_dispatch *tablet,
1008 enum libinput_tablet_tool_type type,
1009 uint32_t tool_id,
1010 uint32_t serial)
1011 {
1012 struct libinput *libinput = tablet_libinput_context(tablet);
1013 struct libinput_tablet_tool *tool = NULL, *t;
1014 struct list *tool_list;
1015
1016 if (serial) {
1017 tool_list = &libinput->tool_list;
1018 /* Check if we already have the tool in our list of tools */
1019 list_for_each(t, tool_list, link) {
1020 if (type == t->type && serial == t->serial) {
1021 tool = t;
1022 break;
1023 }
1024 }
1025 }
1026
1027 /* If we get a tool with a delayed serial number, we already created
1028 * a 0-serial number tool for it earlier. Re-use that, even though
1029 * it means we can't distinguish this tool from others.
1030 * https://bugs.freedesktop.org/show_bug.cgi?id=97526
1031 */
1032 if (!tool) {
1033 tool_list = &tablet->tool_list;
1034 /* We can't guarantee that tools without serial numbers are
1035 * unique, so we keep them local to the tablet that they come
1036 * into proximity of instead of storing them in the global tool
1037 * list
1038 * Same as above, but don't bother checking the serial number
1039 */
1040 list_for_each(t, tool_list, link) {
1041 if (type == t->type) {
1042 tool = t;
1043 break;
1044 }
1045 }
1046
1047 /* Didn't find the tool but we have a serial. Switch
1048 * tool_list back so we create in the correct list */
1049 if (!tool && serial)
1050 tool_list = &libinput->tool_list;
1051 }
1052
1053 /* If we didn't already have the new_tool in our list of tools,
1054 * add it */
1055 if (!tool) {
1056 const struct input_absinfo *pressure;
1057
1058 tool = zalloc(sizeof *tool);
1059
1060 *tool = (struct libinput_tablet_tool) {
1061 .type = type,
1062 .serial = serial,
1063 .tool_id = tool_id,
1064 .refcount = 1,
1065 };
1066
1067 tool->pressure_offset = 0;
1068 tool->has_pressure_offset = false;
1069 tool->pressure_threshold.lower = 0;
1070 tool->pressure_threshold.upper = 1;
1071
1072 pressure = libevdev_get_abs_info(tablet->device->evdev,
1073 ABS_PRESSURE);
1074 if (pressure) {
1075 tool->pressure_offset = pressure->minimum;
1076
1077 /* 5 and 1% of the pressure range */
1078 tool->pressure_threshold.upper =
1079 axis_range_percentage(pressure, 5);
1080 tool->pressure_threshold.lower =
1081 axis_range_percentage(pressure, 1);
1082 }
1083
1084 tool_set_bits(tablet, tool);
1085
1086 list_insert(tool_list, &tool->link);
1087 }
1088
1089 return tool;
1090 }
1091
1092 static void
tablet_notify_button_mask(struct tablet_dispatch * tablet,struct evdev_device * device,uint64_t time,struct libinput_tablet_tool * tool,const struct button_state * buttons,enum libinput_button_state state)1093 tablet_notify_button_mask(struct tablet_dispatch *tablet,
1094 struct evdev_device *device,
1095 uint64_t time,
1096 struct libinput_tablet_tool *tool,
1097 const struct button_state *buttons,
1098 enum libinput_button_state state)
1099 {
1100 struct libinput_device *base = &device->base;
1101 size_t i;
1102 size_t nbits = 8 * sizeof(buttons->bits);
1103 enum libinput_tablet_tool_tip_state tip_state;
1104
1105 tip_state = tablet_has_status(tablet, TABLET_TOOL_IN_CONTACT) ?
1106 LIBINPUT_TABLET_TOOL_TIP_DOWN : LIBINPUT_TABLET_TOOL_TIP_UP;
1107
1108 for (i = 0; i < nbits; i++) {
1109 if (!bit_is_set(buttons->bits, i))
1110 continue;
1111
1112 tablet_notify_button(base,
1113 time,
1114 tool,
1115 tip_state,
1116 &tablet->axes,
1117 i,
1118 state);
1119 }
1120 }
1121
1122 static void
tablet_notify_buttons(struct tablet_dispatch * tablet,struct evdev_device * device,uint64_t time,struct libinput_tablet_tool * tool,enum libinput_button_state state)1123 tablet_notify_buttons(struct tablet_dispatch *tablet,
1124 struct evdev_device *device,
1125 uint64_t time,
1126 struct libinput_tablet_tool *tool,
1127 enum libinput_button_state state)
1128 {
1129 struct button_state buttons;
1130
1131 if (state == LIBINPUT_BUTTON_STATE_PRESSED)
1132 tablet_get_pressed_buttons(tablet, &buttons);
1133 else
1134 tablet_get_released_buttons(tablet, &buttons);
1135
1136 tablet_notify_button_mask(tablet,
1137 device,
1138 time,
1139 tool,
1140 &buttons,
1141 state);
1142 }
1143
1144 static void
sanitize_pressure_distance(struct tablet_dispatch * tablet,struct libinput_tablet_tool * tool)1145 sanitize_pressure_distance(struct tablet_dispatch *tablet,
1146 struct libinput_tablet_tool *tool)
1147 {
1148 bool tool_in_contact;
1149 const struct input_absinfo *distance,
1150 *pressure;
1151
1152 distance = libevdev_get_abs_info(tablet->device->evdev, ABS_DISTANCE);
1153 pressure = libevdev_get_abs_info(tablet->device->evdev, ABS_PRESSURE);
1154
1155 if (!pressure || !distance)
1156 return;
1157
1158 if (!bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_DISTANCE) &&
1159 !bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE))
1160 return;
1161
1162 tool_in_contact = (pressure->value > tool->pressure_offset);
1163
1164 /* Keep distance and pressure mutually exclusive */
1165 if (distance &&
1166 (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_DISTANCE) ||
1167 bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE)) &&
1168 distance->value > distance->minimum &&
1169 pressure->value > pressure->minimum) {
1170 if (tool_in_contact) {
1171 clear_bit(tablet->changed_axes,
1172 LIBINPUT_TABLET_TOOL_AXIS_DISTANCE);
1173 tablet->axes.distance = 0;
1174 } else {
1175 clear_bit(tablet->changed_axes,
1176 LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);
1177 tablet->axes.pressure = 0;
1178 }
1179 } else if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE) &&
1180 !tool_in_contact) {
1181 /* Make sure that the last axis value sent to the caller is a 0 */
1182 if (tablet->axes.pressure == 0)
1183 clear_bit(tablet->changed_axes,
1184 LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);
1185 else
1186 tablet->axes.pressure = 0;
1187 }
1188 }
1189
1190 static inline void
sanitize_mouse_lens_rotation(struct tablet_dispatch * tablet)1191 sanitize_mouse_lens_rotation(struct tablet_dispatch *tablet)
1192 {
1193 /* If we have a mouse/lens cursor and the tilt changed, the rotation
1194 changed. Mark this, calculate the angle later */
1195 if ((tablet->current_tool_type == LIBINPUT_TABLET_TOOL_TYPE_MOUSE ||
1196 tablet->current_tool_type == LIBINPUT_TABLET_TOOL_TYPE_LENS) &&
1197 (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_TILT_X) ||
1198 bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_TILT_Y)))
1199 set_bit(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z);
1200 }
1201
1202 static void
sanitize_tablet_axes(struct tablet_dispatch * tablet,struct libinput_tablet_tool * tool)1203 sanitize_tablet_axes(struct tablet_dispatch *tablet,
1204 struct libinput_tablet_tool *tool)
1205 {
1206 sanitize_pressure_distance(tablet, tool);
1207 sanitize_mouse_lens_rotation(tablet);
1208 }
1209
1210 static void
detect_pressure_offset(struct tablet_dispatch * tablet,struct evdev_device * device,struct libinput_tablet_tool * tool)1211 detect_pressure_offset(struct tablet_dispatch *tablet,
1212 struct evdev_device *device,
1213 struct libinput_tablet_tool *tool)
1214 {
1215 const struct input_absinfo *pressure, *distance;
1216 int offset;
1217
1218 if (!bit_is_set(tablet->changed_axes,
1219 LIBINPUT_TABLET_TOOL_AXIS_PRESSURE))
1220 return;
1221
1222 pressure = libevdev_get_abs_info(device->evdev, ABS_PRESSURE);
1223 distance = libevdev_get_abs_info(device->evdev, ABS_DISTANCE);
1224
1225 if (!pressure || !distance)
1226 return;
1227
1228 offset = pressure->value - pressure->minimum;
1229
1230 if (tool->has_pressure_offset) {
1231 if (offset < tool->pressure_offset)
1232 tool->pressure_offset = offset;
1233 return;
1234 }
1235
1236 if (offset == 0)
1237 return;
1238
1239 /* we only set a pressure offset on proximity in */
1240 if (!tablet_has_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY))
1241 return;
1242
1243 /* If we're closer than 50% of the distance axis, skip pressure
1244 * offset detection, too likely to be wrong */
1245 if (distance->value < axis_range_percentage(distance, 50))
1246 return;
1247
1248 if (offset > axis_range_percentage(pressure, 20)) {
1249 evdev_log_error(device,
1250 "Ignoring pressure offset greater than 20%% detected on tool %s (serial %#x). "
1251 "See http://wayland.freedesktop.org/libinput/doc/%s/tablet-support.html\n",
1252 tablet_tool_type_to_string(tool->type),
1253 tool->serial,
1254 LIBINPUT_VERSION);
1255 return;
1256 }
1257
1258 evdev_log_info(device,
1259 "Pressure offset detected on tool %s (serial %#x). "
1260 "See http://wayland.freedesktop.org/libinput/doc/%s/tablet-support.html\n",
1261 tablet_tool_type_to_string(tool->type),
1262 tool->serial,
1263 LIBINPUT_VERSION);
1264 tool->pressure_offset = offset;
1265 tool->has_pressure_offset = true;
1266 tool->pressure_threshold.lower = pressure->minimum;
1267 }
1268
1269 static void
detect_tool_contact(struct tablet_dispatch * tablet,struct evdev_device * device,struct libinput_tablet_tool * tool)1270 detect_tool_contact(struct tablet_dispatch *tablet,
1271 struct evdev_device *device,
1272 struct libinput_tablet_tool *tool)
1273 {
1274 const struct input_absinfo *p;
1275 int pressure;
1276
1277 if (!bit_is_set(tool->axis_caps, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE))
1278 return;
1279
1280 /* if we have pressure, always use that for contact, not BTN_TOUCH */
1281 if (tablet_has_status(tablet, TABLET_TOOL_ENTERING_CONTACT))
1282 evdev_log_bug_libinput(device,
1283 "Invalid status: entering contact\n");
1284 if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_CONTACT) &&
1285 !tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY))
1286 evdev_log_bug_libinput(device,
1287 "Invalid status: leaving contact\n");
1288
1289 p = libevdev_get_abs_info(tablet->device->evdev, ABS_PRESSURE);
1290 if (!p) {
1291 evdev_log_bug_libinput(device,
1292 "Missing pressure axis\n");
1293 return;
1294 }
1295 pressure = p->value;
1296
1297 if (tool->has_pressure_offset)
1298 pressure -= (tool->pressure_offset - p->minimum);
1299
1300 if (pressure <= tool->pressure_threshold.lower &&
1301 tablet_has_status(tablet, TABLET_TOOL_IN_CONTACT)) {
1302 tablet_set_status(tablet, TABLET_TOOL_LEAVING_CONTACT);
1303 } else if (pressure >= tool->pressure_threshold.upper &&
1304 !tablet_has_status(tablet, TABLET_TOOL_IN_CONTACT)) {
1305 tablet_set_status(tablet, TABLET_TOOL_ENTERING_CONTACT);
1306 }
1307 }
1308
1309 static void
tablet_mark_all_axes_changed(struct tablet_dispatch * tablet,struct libinput_tablet_tool * tool)1310 tablet_mark_all_axes_changed(struct tablet_dispatch *tablet,
1311 struct libinput_tablet_tool *tool)
1312 {
1313 static_assert(sizeof(tablet->changed_axes) ==
1314 sizeof(tool->axis_caps),
1315 "Mismatching array sizes");
1316
1317 memcpy(tablet->changed_axes,
1318 tool->axis_caps,
1319 sizeof(tablet->changed_axes));
1320 }
1321
1322 static void
tablet_update_proximity_state(struct tablet_dispatch * tablet,struct evdev_device * device,struct libinput_tablet_tool * tool)1323 tablet_update_proximity_state(struct tablet_dispatch *tablet,
1324 struct evdev_device *device,
1325 struct libinput_tablet_tool *tool)
1326 {
1327 const struct input_absinfo *distance;
1328 int dist_max = tablet->cursor_proximity_threshold;
1329 int dist;
1330
1331 distance = libevdev_get_abs_info(tablet->device->evdev, ABS_DISTANCE);
1332 if (!distance)
1333 return;
1334
1335 dist = distance->value;
1336 if (dist == 0)
1337 return;
1338
1339 /* Tool got into permitted range */
1340 if (dist < dist_max &&
1341 (tablet_has_status(tablet, TABLET_TOOL_OUT_OF_RANGE) ||
1342 tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY))) {
1343 tablet_unset_status(tablet,
1344 TABLET_TOOL_OUT_OF_RANGE);
1345 tablet_unset_status(tablet,
1346 TABLET_TOOL_OUT_OF_PROXIMITY);
1347 tablet_set_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY);
1348 tablet_mark_all_axes_changed(tablet, tool);
1349
1350 tablet_set_status(tablet, TABLET_BUTTONS_PRESSED);
1351 tablet_force_button_presses(tablet);
1352 return;
1353 }
1354
1355 if (dist < dist_max)
1356 return;
1357
1358 /* Still out of range/proximity */
1359 if (tablet_has_status(tablet, TABLET_TOOL_OUT_OF_RANGE) ||
1360 tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY))
1361 return;
1362
1363 /* Tool entered prox but is outside of permitted range */
1364 if (tablet_has_status(tablet,
1365 TABLET_TOOL_ENTERING_PROXIMITY)) {
1366 tablet_set_status(tablet,
1367 TABLET_TOOL_OUT_OF_RANGE);
1368 tablet_unset_status(tablet,
1369 TABLET_TOOL_ENTERING_PROXIMITY);
1370 return;
1371 }
1372
1373 /* Tool was in prox and is now outside of range. Set leaving
1374 * proximity, on the next event it will be OUT_OF_PROXIMITY and thus
1375 * caught by the above conditions */
1376 tablet_set_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
1377 }
1378
1379 static inline bool
tablet_send_proximity_in(struct tablet_dispatch * tablet,struct libinput_tablet_tool * tool,struct evdev_device * device,struct tablet_axes * axes,uint64_t time)1380 tablet_send_proximity_in(struct tablet_dispatch *tablet,
1381 struct libinput_tablet_tool *tool,
1382 struct evdev_device *device,
1383 struct tablet_axes *axes,
1384 uint64_t time)
1385 {
1386 if (!tablet_has_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY))
1387 return false;
1388
1389 tablet_notify_proximity(&device->base,
1390 time,
1391 tool,
1392 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
1393 tablet->changed_axes,
1394 axes);
1395 tablet_unset_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY);
1396 tablet_unset_status(tablet, TABLET_AXES_UPDATED);
1397
1398 tablet_reset_changed_axes(tablet);
1399 axes->delta.x = 0;
1400 axes->delta.y = 0;
1401
1402 return true;
1403 }
1404
1405 static inline bool
tablet_send_proximity_out(struct tablet_dispatch * tablet,struct libinput_tablet_tool * tool,struct evdev_device * device,struct tablet_axes * axes,uint64_t time)1406 tablet_send_proximity_out(struct tablet_dispatch *tablet,
1407 struct libinput_tablet_tool *tool,
1408 struct evdev_device *device,
1409 struct tablet_axes *axes,
1410 uint64_t time)
1411 {
1412 if (!tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY))
1413 return false;
1414
1415 tablet_notify_proximity(&device->base,
1416 time,
1417 tool,
1418 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT,
1419 tablet->changed_axes,
1420 axes);
1421
1422 tablet_set_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
1423 tablet_unset_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
1424
1425 tablet_reset_changed_axes(tablet);
1426 axes->delta.x = 0;
1427 axes->delta.y = 0;
1428
1429 return true;
1430 }
1431
1432 static inline bool
tablet_send_tip(struct tablet_dispatch * tablet,struct libinput_tablet_tool * tool,struct evdev_device * device,struct tablet_axes * axes,uint64_t time)1433 tablet_send_tip(struct tablet_dispatch *tablet,
1434 struct libinput_tablet_tool *tool,
1435 struct evdev_device *device,
1436 struct tablet_axes *axes,
1437 uint64_t time)
1438 {
1439 if (tablet_has_status(tablet, TABLET_TOOL_ENTERING_CONTACT)) {
1440 tablet_notify_tip(&device->base,
1441 time,
1442 tool,
1443 LIBINPUT_TABLET_TOOL_TIP_DOWN,
1444 tablet->changed_axes,
1445 axes);
1446 tablet_unset_status(tablet, TABLET_AXES_UPDATED);
1447 tablet_unset_status(tablet, TABLET_TOOL_ENTERING_CONTACT);
1448 tablet_set_status(tablet, TABLET_TOOL_IN_CONTACT);
1449
1450 tablet_reset_changed_axes(tablet);
1451 axes->delta.x = 0;
1452 axes->delta.y = 0;
1453
1454 return true;
1455 }
1456
1457 if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_CONTACT)) {
1458 tablet_notify_tip(&device->base,
1459 time,
1460 tool,
1461 LIBINPUT_TABLET_TOOL_TIP_UP,
1462 tablet->changed_axes,
1463 axes);
1464 tablet_unset_status(tablet, TABLET_AXES_UPDATED);
1465 tablet_unset_status(tablet, TABLET_TOOL_LEAVING_CONTACT);
1466 tablet_unset_status(tablet, TABLET_TOOL_IN_CONTACT);
1467
1468 tablet_reset_changed_axes(tablet);
1469 axes->delta.x = 0;
1470 axes->delta.y = 0;
1471
1472 return true;
1473 }
1474
1475 return false;
1476 }
1477
1478 static inline void
tablet_send_axes(struct tablet_dispatch * tablet,struct libinput_tablet_tool * tool,struct evdev_device * device,struct tablet_axes * axes,uint64_t time)1479 tablet_send_axes(struct tablet_dispatch *tablet,
1480 struct libinput_tablet_tool *tool,
1481 struct evdev_device *device,
1482 struct tablet_axes *axes,
1483 uint64_t time)
1484 {
1485 enum libinput_tablet_tool_tip_state tip_state;
1486
1487 if (!tablet_has_status(tablet, TABLET_AXES_UPDATED))
1488 return;
1489
1490 if (tablet_has_status(tablet,
1491 TABLET_TOOL_IN_CONTACT))
1492 tip_state = LIBINPUT_TABLET_TOOL_TIP_DOWN;
1493 else
1494 tip_state = LIBINPUT_TABLET_TOOL_TIP_UP;
1495
1496 tablet_notify_axis(&device->base,
1497 time,
1498 tool,
1499 tip_state,
1500 tablet->changed_axes,
1501 axes);
1502 tablet_unset_status(tablet, TABLET_AXES_UPDATED);
1503 tablet_reset_changed_axes(tablet);
1504 axes->delta.x = 0;
1505 axes->delta.y = 0;
1506 }
1507
1508 static inline void
tablet_send_buttons(struct tablet_dispatch * tablet,struct libinput_tablet_tool * tool,struct evdev_device * device,uint64_t time)1509 tablet_send_buttons(struct tablet_dispatch *tablet,
1510 struct libinput_tablet_tool *tool,
1511 struct evdev_device *device,
1512 uint64_t time)
1513 {
1514 if (tablet_has_status(tablet, TABLET_BUTTONS_RELEASED)) {
1515 tablet_notify_buttons(tablet,
1516 device,
1517 time,
1518 tool,
1519 LIBINPUT_BUTTON_STATE_RELEASED);
1520 tablet_unset_status(tablet, TABLET_BUTTONS_RELEASED);
1521 }
1522
1523 if (tablet_has_status(tablet, TABLET_BUTTONS_PRESSED)) {
1524 tablet_notify_buttons(tablet,
1525 device,
1526 time,
1527 tool,
1528 LIBINPUT_BUTTON_STATE_PRESSED);
1529 tablet_unset_status(tablet, TABLET_BUTTONS_PRESSED);
1530 }
1531 }
1532
1533 static void
tablet_send_events(struct tablet_dispatch * tablet,struct libinput_tablet_tool * tool,struct evdev_device * device,uint64_t time)1534 tablet_send_events(struct tablet_dispatch *tablet,
1535 struct libinput_tablet_tool *tool,
1536 struct evdev_device *device,
1537 uint64_t time)
1538 {
1539 struct tablet_axes axes = {0};
1540
1541 if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY)) {
1542 /* Tool is leaving proximity, we can't rely on the last axis
1543 * information (it'll be mostly 0), so we just get the
1544 * current state and skip over updating the axes.
1545 */
1546 axes = tablet->axes;
1547
1548 /* Dont' send an axis event, but we may have a tip event
1549 * update */
1550 tablet_unset_status(tablet, TABLET_AXES_UPDATED);
1551 } else {
1552 tablet_check_notify_axes(tablet, device, tool, &axes, time);
1553 }
1554
1555 assert(tablet->axes.delta.x == 0);
1556 assert(tablet->axes.delta.y == 0);
1557
1558 tablet_send_proximity_in(tablet, tool, device, &axes, time);
1559 if (!tablet_send_tip(tablet, tool, device, &axes, time))
1560 tablet_send_axes(tablet, tool, device, &axes, time);
1561
1562 tablet_unset_status(tablet, TABLET_TOOL_ENTERING_CONTACT);
1563 tablet_reset_changed_axes(tablet);
1564
1565 tablet_send_buttons(tablet, tool, device, time);
1566
1567 if (tablet_send_proximity_out(tablet, tool, device, &axes, time)) {
1568 tablet_change_to_left_handed(device);
1569 tablet_history_reset(tablet);
1570 }
1571 }
1572
1573 static void
tablet_flush(struct tablet_dispatch * tablet,struct evdev_device * device,uint64_t time)1574 tablet_flush(struct tablet_dispatch *tablet,
1575 struct evdev_device *device,
1576 uint64_t time)
1577 {
1578 struct libinput_tablet_tool *tool;
1579
1580 if (tablet->current_tool_type == LIBINPUT_TOOL_NONE)
1581 return;
1582
1583 tool = tablet_get_tool(tablet,
1584 tablet->current_tool_type,
1585 tablet->current_tool_id,
1586 tablet->current_tool_serial);
1587
1588 if (!tool)
1589 return; /* OOM */
1590
1591 if (tool->type == LIBINPUT_TABLET_TOOL_TYPE_MOUSE ||
1592 tool->type == LIBINPUT_TABLET_TOOL_TYPE_LENS)
1593 tablet_update_proximity_state(tablet, device, tool);
1594
1595 if (tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY) ||
1596 tablet_has_status(tablet, TABLET_TOOL_OUT_OF_RANGE))
1597 return;
1598
1599 if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY)) {
1600 /* Release all stylus buttons */
1601 memset(tablet->button_state.bits,
1602 0,
1603 sizeof(tablet->button_state.bits));
1604 tablet_set_status(tablet, TABLET_BUTTONS_RELEASED);
1605 if (tablet_has_status(tablet, TABLET_TOOL_IN_CONTACT))
1606 tablet_set_status(tablet, TABLET_TOOL_LEAVING_CONTACT);
1607 } else if (tablet_has_status(tablet, TABLET_AXES_UPDATED) ||
1608 tablet_has_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY)) {
1609 if (tablet_has_status(tablet,
1610 TABLET_TOOL_ENTERING_PROXIMITY))
1611 tablet_mark_all_axes_changed(tablet, tool);
1612 detect_pressure_offset(tablet, device, tool);
1613 detect_tool_contact(tablet, device, tool);
1614 sanitize_tablet_axes(tablet, tool);
1615 }
1616
1617 tablet_send_events(tablet, tool, device, time);
1618 }
1619
1620 static inline void
tablet_set_touch_device_enabled(struct evdev_device * touch_device,bool enable,uint64_t time)1621 tablet_set_touch_device_enabled(struct evdev_device *touch_device,
1622 bool enable,
1623 uint64_t time)
1624 {
1625 struct evdev_dispatch *dispatch;
1626
1627 if (touch_device == NULL)
1628 return;
1629
1630 dispatch = touch_device->dispatch;
1631 if (dispatch->interface->toggle_touch)
1632 dispatch->interface->toggle_touch(dispatch,
1633 touch_device,
1634 enable,
1635 time);
1636 }
1637
1638 static inline void
tablet_toggle_touch_device(struct tablet_dispatch * tablet,struct evdev_device * tablet_device,uint64_t time)1639 tablet_toggle_touch_device(struct tablet_dispatch *tablet,
1640 struct evdev_device *tablet_device,
1641 uint64_t time)
1642 {
1643 bool enable_events;
1644
1645 enable_events = tablet_has_status(tablet,
1646 TABLET_TOOL_OUT_OF_RANGE) ||
1647 tablet_has_status(tablet, TABLET_NONE) ||
1648 tablet_has_status(tablet,
1649 TABLET_TOOL_LEAVING_PROXIMITY) ||
1650 tablet_has_status(tablet,
1651 TABLET_TOOL_OUT_OF_PROXIMITY);
1652
1653 tablet_set_touch_device_enabled(tablet->touch_device,
1654 enable_events,
1655 time);
1656 }
1657
1658 static inline void
tablet_reset_state(struct tablet_dispatch * tablet)1659 tablet_reset_state(struct tablet_dispatch *tablet)
1660 {
1661 /* Update state */
1662 memcpy(&tablet->prev_button_state,
1663 &tablet->button_state,
1664 sizeof(tablet->button_state));
1665 }
1666
1667 static inline void
tablet_proximity_out_quirk_set_timer(struct tablet_dispatch * tablet,uint64_t time)1668 tablet_proximity_out_quirk_set_timer(struct tablet_dispatch *tablet,
1669 uint64_t time)
1670 {
1671 libinput_timer_set(&tablet->quirks.prox_out_timer,
1672 time + FORCED_PROXOUT_TIMEOUT);
1673 }
1674
1675 static void
tablet_proximity_out_quirk_timer_func(uint64_t now,void * data)1676 tablet_proximity_out_quirk_timer_func(uint64_t now, void *data)
1677 {
1678 struct tablet_dispatch *tablet = data;
1679 struct timeval tv = us2tv(now);
1680 struct input_event events[2] = {
1681 { .input_event_sec = tv.tv_sec,
1682 .input_event_usec = tv.tv_usec,
1683 .type = EV_KEY,
1684 .code = BTN_TOOL_PEN,
1685 .value = 0 },
1686 { .input_event_sec = tv.tv_sec,
1687 .input_event_usec = tv.tv_usec,
1688 .type = EV_SYN,
1689 .code = SYN_REPORT,
1690 .value = 0 },
1691 };
1692 struct input_event *e;
1693
1694 if (tablet->quirks.last_event_time > now - FORCED_PROXOUT_TIMEOUT) {
1695 tablet_proximity_out_quirk_set_timer(tablet,
1696 tablet->quirks.last_event_time);
1697 return;
1698 }
1699
1700 tablet->quirks.proximity_out_in_progress = true;
1701 ARRAY_FOR_EACH(events, e) {
1702 tablet->base.interface->process(&tablet->base,
1703 tablet->device,
1704 e,
1705 now);
1706 }
1707 tablet->quirks.proximity_out_in_progress = false;
1708
1709 tablet->quirks.proximity_out_forced = true;
1710 }
1711
1712 /**
1713 * Handling for the proximity out workaround. Some tablets only send
1714 * BTN_TOOL_PEN on the very first event, then leave it set even when the pen
1715 * leaves the detectable range. To libinput this looks like we always have
1716 * the pen in proximity.
1717 *
1718 * To avoid this, we set a timer on BTN_TOOL_PEN in. We expect the tablet to
1719 * continuously send events, and while it's doing so we keep updating the
1720 * timer. Once we go Xms without an event we assume proximity out and inject
1721 * a BTN_TOOL_PEN event into the sequence through the timer func.
1722 *
1723 * We need to remember that we did that, on the first event after the
1724 * timeout we need to inject a BTN_TOOL_PEN event again to force proximity
1725 * in.
1726 *
1727 * Other tools never send the BTN_TOOL_PEN event. For those tools, we
1728 * piggyback along with the proximity out quirks by injecting
1729 * the event during the first event frame.
1730 */
1731 static inline void
tablet_proximity_quirk_update(struct tablet_dispatch * tablet,struct evdev_device * device,struct input_event * e,uint64_t time)1732 tablet_proximity_quirk_update(struct tablet_dispatch *tablet,
1733 struct evdev_device *device,
1734 struct input_event *e,
1735 uint64_t time)
1736 {
1737 /* LIBINPUT_TOOL_NONE can only happpen on the first event after
1738 * init. By pretending we forced a proximity out, we can inject a
1739 * BTN_TOOL_PEN and move on from there. */
1740 if (e->type == EV_SYN &&
1741 tablet_has_status(tablet, TABLET_AXES_UPDATED) &&
1742 tablet->current_tool_type == LIBINPUT_TOOL_NONE) {
1743 tablet->quirks.proximity_out_forced = true;
1744 tablet->quirks.need_to_force_prox_out = true;
1745 }
1746
1747 if (!tablet->quirks.need_to_force_prox_out)
1748 return;
1749
1750 if (e->type == EV_SYN) {
1751 /* If the timer function forced prox out before,
1752 fake a BTN_TOOL_PEN event */
1753 if (tablet->quirks.proximity_out_forced) {
1754 struct timeval tv = us2tv(time);
1755 struct input_event fake_event = {
1756 .input_event_sec = tv.tv_sec,
1757 .input_event_usec = tv.tv_usec,
1758 .type = EV_KEY,
1759 .code = BTN_TOOL_PEN,
1760 .value = 1,
1761 };
1762
1763 tablet->base.interface->process(&tablet->base,
1764 device,
1765 &fake_event,
1766 time);
1767 tablet->quirks.proximity_out_forced = false;
1768 }
1769 tablet->quirks.last_event_time = time;
1770 } else if (e->type == EV_KEY && e->code == BTN_TOOL_PEN) {
1771 if (e->value) {
1772 tablet_proximity_out_quirk_set_timer(tablet, time);
1773 } else {
1774 /* If we get a BTN_TOOL_PEN 0 when *not* injecting
1775 * events it means the tablet will give us the right
1776 * events after all and we can disable our
1777 * timer-based proximity out.
1778 */
1779 if (!tablet->quirks.proximity_out_in_progress)
1780 tablet->quirks.need_to_force_prox_out = false;
1781
1782 libinput_timer_cancel(&tablet->quirks.prox_out_timer);
1783 }
1784 }
1785 }
1786
1787 static void
tablet_process(struct evdev_dispatch * dispatch,struct evdev_device * device,struct input_event * e,uint64_t time)1788 tablet_process(struct evdev_dispatch *dispatch,
1789 struct evdev_device *device,
1790 struct input_event *e,
1791 uint64_t time)
1792 {
1793 struct tablet_dispatch *tablet = tablet_dispatch(dispatch);
1794
1795 /* Warning: this may inject events */
1796 tablet_proximity_quirk_update(tablet, device, e, time);
1797
1798 switch (e->type) {
1799 case EV_ABS:
1800 tablet_process_absolute(tablet, device, e, time);
1801 break;
1802 case EV_REL:
1803 tablet_process_relative(tablet, device, e, time);
1804 break;
1805 case EV_KEY:
1806 tablet_process_key(tablet, device, e, time);
1807 break;
1808 case EV_MSC:
1809 tablet_process_misc(tablet, device, e, time);
1810 break;
1811 case EV_SYN:
1812 tablet_flush(tablet, device, time);
1813 tablet_toggle_touch_device(tablet, device, time);
1814 tablet_reset_state(tablet);
1815 break;
1816 default:
1817 evdev_log_error(device,
1818 "Unexpected event type %s (%#x)\n",
1819 libevdev_event_type_get_name(e->type),
1820 e->type);
1821 break;
1822 }
1823 }
1824
1825 static void
tablet_suspend(struct evdev_dispatch * dispatch,struct evdev_device * device)1826 tablet_suspend(struct evdev_dispatch *dispatch,
1827 struct evdev_device *device)
1828 {
1829 struct tablet_dispatch *tablet = tablet_dispatch(dispatch);
1830 struct libinput *li = tablet_libinput_context(tablet);
1831 uint64_t now = libinput_now(li);
1832
1833 tablet_set_touch_device_enabled(tablet->touch_device, true, now);
1834
1835 if (!tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY)) {
1836 tablet_set_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
1837 tablet_flush(tablet, device, libinput_now(li));
1838 }
1839 }
1840
1841 static void
tablet_destroy(struct evdev_dispatch * dispatch)1842 tablet_destroy(struct evdev_dispatch *dispatch)
1843 {
1844 struct tablet_dispatch *tablet = tablet_dispatch(dispatch);
1845 struct libinput_tablet_tool *tool, *tmp;
1846
1847 libinput_timer_cancel(&tablet->quirks.prox_out_timer);
1848 libinput_timer_destroy(&tablet->quirks.prox_out_timer);
1849
1850 list_for_each_safe(tool, tmp, &tablet->tool_list, link) {
1851 libinput_tablet_tool_unref(tool);
1852 }
1853
1854 free(tablet);
1855 }
1856
1857 static void
tablet_device_added(struct evdev_device * device,struct evdev_device * added_device)1858 tablet_device_added(struct evdev_device *device,
1859 struct evdev_device *added_device)
1860 {
1861 struct tablet_dispatch *tablet = tablet_dispatch(device->dispatch);
1862
1863 if (libinput_device_get_device_group(&device->base) !=
1864 libinput_device_get_device_group(&added_device->base))
1865 return;
1866
1867 /* Touch screens or external touchpads only */
1868 if (evdev_device_has_capability(added_device, LIBINPUT_DEVICE_CAP_TOUCH) ||
1869 (evdev_device_has_capability(added_device, LIBINPUT_DEVICE_CAP_POINTER) &&
1870 (added_device->tags & EVDEV_TAG_EXTERNAL_TOUCHPAD)))
1871 tablet->touch_device = added_device;
1872 }
1873
1874 static void
tablet_device_removed(struct evdev_device * device,struct evdev_device * removed_device)1875 tablet_device_removed(struct evdev_device *device,
1876 struct evdev_device *removed_device)
1877 {
1878 struct tablet_dispatch *tablet = tablet_dispatch(device->dispatch);
1879
1880 if (tablet->touch_device == removed_device)
1881 tablet->touch_device = NULL;
1882 }
1883
1884 static void
tablet_check_initial_proximity(struct evdev_device * device,struct evdev_dispatch * dispatch)1885 tablet_check_initial_proximity(struct evdev_device *device,
1886 struct evdev_dispatch *dispatch)
1887 {
1888 struct tablet_dispatch *tablet = tablet_dispatch(dispatch);
1889 struct libinput *li = tablet_libinput_context(tablet);
1890 bool tool_in_prox = false;
1891 int code, state;
1892 enum libinput_tablet_tool_type tool;
1893
1894 for (tool = LIBINPUT_TABLET_TOOL_TYPE_PEN;
1895 tool <= LIBINPUT_TABLET_TOOL_TYPE_MAX;
1896 tool++) {
1897 code = tablet_tool_to_evcode(tool);
1898
1899 /* we only expect one tool to be in proximity at a time */
1900 if (libevdev_fetch_event_value(device->evdev,
1901 EV_KEY,
1902 code,
1903 &state) && state) {
1904 tool_in_prox = true;
1905 break;
1906 }
1907 }
1908
1909 if (!tool_in_prox)
1910 return;
1911
1912 tablet_update_tool(tablet, device, tool, state);
1913 if (tablet->quirks.need_to_force_prox_out)
1914 tablet_proximity_out_quirk_set_timer(tablet, libinput_now(li));
1915
1916 tablet->current_tool_id =
1917 libevdev_get_event_value(device->evdev,
1918 EV_ABS,
1919 ABS_MISC);
1920
1921 /* we can't fetch MSC_SERIAL from the kernel, so we set the serial
1922 * to 0 for now. On the first real event from the device we get the
1923 * serial (if any) and that event will be converted into a proximity
1924 * event */
1925 tablet->current_tool_serial = 0;
1926 }
1927
1928 static struct evdev_dispatch_interface tablet_interface = {
1929 .process = tablet_process,
1930 .suspend = tablet_suspend,
1931 .remove = NULL,
1932 .destroy = tablet_destroy,
1933 .device_added = tablet_device_added,
1934 .device_removed = tablet_device_removed,
1935 .device_suspended = NULL,
1936 .device_resumed = NULL,
1937 .post_added = tablet_check_initial_proximity,
1938 .toggle_touch = NULL,
1939 .get_switch_state = NULL,
1940 };
1941
1942 static void
tablet_init_calibration(struct tablet_dispatch * tablet,struct evdev_device * device)1943 tablet_init_calibration(struct tablet_dispatch *tablet,
1944 struct evdev_device *device)
1945 {
1946 if (libevdev_has_property(device->evdev, INPUT_PROP_DIRECT))
1947 evdev_init_calibration(device, &tablet->calibration);
1948 }
1949
1950 static void
tablet_init_proximity_threshold(struct tablet_dispatch * tablet,struct evdev_device * device)1951 tablet_init_proximity_threshold(struct tablet_dispatch *tablet,
1952 struct evdev_device *device)
1953 {
1954 /* This rules out most of the bamboos and other devices, we're
1955 * pretty much down to
1956 */
1957 if (!libevdev_has_event_code(device->evdev, EV_KEY, BTN_TOOL_MOUSE) &&
1958 !libevdev_has_event_code(device->evdev, EV_KEY, BTN_TOOL_LENS))
1959 return;
1960
1961 /* 42 is the default proximity threshold the xf86-input-wacom driver
1962 * uses for Intuos/Cintiq models. Graphire models have a threshold
1963 * of 10 but since they haven't been manufactured in ages and the
1964 * intersection of users having a graphire, running libinput and
1965 * wanting to use the mouse/lens cursor tool is small enough to not
1966 * worry about it for now. If we need to, we can introduce a udev
1967 * property later.
1968 *
1969 * Value is in device coordinates.
1970 */
1971 tablet->cursor_proximity_threshold = 42;
1972 }
1973
1974 static uint32_t
tablet_accel_config_get_profiles(struct libinput_device * libinput_device)1975 tablet_accel_config_get_profiles(struct libinput_device *libinput_device)
1976 {
1977 return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
1978 }
1979
1980 static enum libinput_config_status
tablet_accel_config_set_profile(struct libinput_device * libinput_device,enum libinput_config_accel_profile profile)1981 tablet_accel_config_set_profile(struct libinput_device *libinput_device,
1982 enum libinput_config_accel_profile profile)
1983 {
1984 return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
1985 }
1986
1987 static enum libinput_config_accel_profile
tablet_accel_config_get_profile(struct libinput_device * libinput_device)1988 tablet_accel_config_get_profile(struct libinput_device *libinput_device)
1989 {
1990 return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
1991 }
1992
1993 static enum libinput_config_accel_profile
tablet_accel_config_get_default_profile(struct libinput_device * libinput_device)1994 tablet_accel_config_get_default_profile(struct libinput_device *libinput_device)
1995 {
1996 return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
1997 }
1998
1999 static int
tablet_init_accel(struct tablet_dispatch * tablet,struct evdev_device * device)2000 tablet_init_accel(struct tablet_dispatch *tablet, struct evdev_device *device)
2001 {
2002 const struct input_absinfo *x, *y;
2003 struct motion_filter *filter;
2004
2005 x = device->abs.absinfo_x;
2006 y = device->abs.absinfo_y;
2007
2008 filter = create_pointer_accelerator_filter_tablet(x->resolution,
2009 y->resolution);
2010 if (!filter)
2011 return -1;
2012
2013 evdev_device_init_pointer_acceleration(device, filter);
2014
2015 /* we override the profile hooks for accel configuration with hooks
2016 * that don't allow selection of profiles */
2017 device->pointer.config.get_profiles = tablet_accel_config_get_profiles;
2018 device->pointer.config.set_profile = tablet_accel_config_set_profile;
2019 device->pointer.config.get_profile = tablet_accel_config_get_profile;
2020 device->pointer.config.get_default_profile = tablet_accel_config_get_default_profile;
2021
2022 return 0;
2023 }
2024
2025 static void
tablet_init_left_handed(struct evdev_device * device)2026 tablet_init_left_handed(struct evdev_device *device)
2027 {
2028 if (evdev_tablet_has_left_handed(device))
2029 evdev_init_left_handed(device,
2030 tablet_change_to_left_handed);
2031 }
2032
2033 static bool
tablet_reject_device(struct evdev_device * device)2034 tablet_reject_device(struct evdev_device *device)
2035 {
2036 struct libevdev *evdev = device->evdev;
2037 double w, h;
2038 bool has_xy, has_pen, has_btn_stylus, has_size;
2039
2040 has_xy = libevdev_has_event_code(evdev, EV_ABS, ABS_X) &&
2041 libevdev_has_event_code(evdev, EV_ABS, ABS_Y);
2042 has_pen = libevdev_has_event_code(evdev, EV_KEY, BTN_TOOL_PEN);
2043 has_btn_stylus = libevdev_has_event_code(evdev, EV_KEY, BTN_STYLUS);
2044 has_size = evdev_device_get_size(device, &w, &h) == 0;
2045
2046 if (has_xy && (has_pen || has_btn_stylus) && has_size)
2047 return false;
2048
2049 evdev_log_bug_libinput(device,
2050 "missing tablet capabilities:%s%s%s%s. "
2051 "Ignoring this device.\n",
2052 has_xy ? "" : " xy",
2053 has_pen ? "" : " pen",
2054 has_btn_stylus ? "" : " btn-stylus",
2055 has_size ? "" : " resolution");
2056 return true;
2057 }
2058
2059 static int
tablet_init(struct tablet_dispatch * tablet,struct evdev_device * device)2060 tablet_init(struct tablet_dispatch *tablet,
2061 struct evdev_device *device)
2062 {
2063 struct libevdev *evdev = device->evdev;
2064 enum libinput_tablet_tool_axis axis;
2065 bool want_proximity_quirk = false;
2066 int rc;
2067
2068 tablet->base.dispatch_type = DISPATCH_TABLET;
2069 tablet->base.interface = &tablet_interface;
2070 tablet->device = device;
2071 tablet->status = TABLET_NONE;
2072 tablet->current_tool_type = LIBINPUT_TOOL_NONE;
2073 list_init(&tablet->tool_list);
2074
2075 if (tablet_reject_device(device))
2076 return -1;
2077
2078 if (!libevdev_has_event_code(evdev, EV_KEY, BTN_TOOL_PEN)) {
2079 libevdev_enable_event_code(evdev, EV_KEY, BTN_TOOL_PEN, NULL);
2080 want_proximity_quirk = true;
2081 tablet->quirks.proximity_out_forced = true;
2082 }
2083
2084 /* Our rotation code only works with Wacoms, let's wait until
2085 * someone shouts */
2086 if (evdev_device_get_id_vendor(device) != VENDOR_ID_WACOM) {
2087 libevdev_disable_event_code(evdev, EV_KEY, BTN_TOOL_MOUSE);
2088 libevdev_disable_event_code(evdev, EV_KEY, BTN_TOOL_LENS);
2089 }
2090
2091 tablet_init_calibration(tablet, device);
2092 tablet_init_proximity_threshold(tablet, device);
2093 rc = tablet_init_accel(tablet, device);
2094 if (rc != 0)
2095 return rc;
2096
2097 tablet_init_left_handed(device);
2098
2099 for (axis = LIBINPUT_TABLET_TOOL_AXIS_X;
2100 axis <= LIBINPUT_TABLET_TOOL_AXIS_MAX;
2101 axis++) {
2102 if (tablet_device_has_axis(tablet, axis))
2103 set_bit(tablet->axis_caps, axis);
2104 }
2105
2106 tablet_set_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
2107
2108 if (evdev_device_has_model_quirk(device,
2109 QUIRK_MODEL_TABLET_NO_PROXIMITY_OUT))
2110 want_proximity_quirk = true;
2111
2112 if (want_proximity_quirk)
2113 tablet->quirks.need_to_force_prox_out = true;
2114
2115 libinput_timer_init(&tablet->quirks.prox_out_timer,
2116 tablet_libinput_context(tablet),
2117 "proxout",
2118 tablet_proximity_out_quirk_timer_func,
2119 tablet);
2120
2121 return 0;
2122 }
2123
2124 struct evdev_dispatch *
evdev_tablet_create(struct evdev_device * device)2125 evdev_tablet_create(struct evdev_device *device)
2126 {
2127 struct tablet_dispatch *tablet;
2128
2129 /* Stop false positives caused by the forced proximity code */
2130 if (getenv("LIBINPUT_RUNNING_TEST_SUITE"))
2131 FORCED_PROXOUT_TIMEOUT = 150 * 1000; /* µs */
2132
2133 tablet = zalloc(sizeof *tablet);
2134
2135 if (tablet_init(tablet, device) != 0) {
2136 tablet_destroy(&tablet->base);
2137 return NULL;
2138 }
2139
2140 return &tablet->base;
2141 }
2142