2 * Copyright © 2014 Red Hat, Inc.
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29 #include "evdev-mt-touchpad.h"
31 #define DEFAULT_ACCEL_NUMERATOR 1200.0
32 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
35 tp_hysteresis(int in, int center, int margin)
37 int diff = in - center;
38 if (abs(diff) <= margin)
42 return center + diff - margin;
44 return center + diff + margin;
47 static inline struct tp_motion *
48 tp_motion_history_offset(struct tp_touch *t, int offset)
51 (t->history.index - offset + TOUCHPAD_HISTORY_LENGTH) %
52 TOUCHPAD_HISTORY_LENGTH;
54 return &t->history.samples[offset_index];
58 tp_filter_motion(struct tp_dispatch *tp,
59 double *dx, double *dy, uint64_t time)
61 struct motion_params motion;
63 motion.dx = *dx * tp->accel.x_scale_coeff;
64 motion.dy = *dy * tp->accel.y_scale_coeff;
66 if (motion.dx != 0.0 || motion.dy != 0.0)
67 filter_dispatch(tp->filter, &motion, tp, time);
74 tp_motion_history_push(struct tp_touch *t)
76 int motion_index = (t->history.index + 1) % TOUCHPAD_HISTORY_LENGTH;
78 if (t->history.count < TOUCHPAD_HISTORY_LENGTH)
81 t->history.samples[motion_index].x = t->x;
82 t->history.samples[motion_index].y = t->y;
83 t->history.index = motion_index;
87 tp_motion_hysteresis(struct tp_dispatch *tp,
93 if (t->history.count == 0) {
94 t->hysteresis.center_x = t->x;
95 t->hysteresis.center_y = t->y;
98 t->hysteresis.center_x,
99 tp->hysteresis.margin_x);
101 t->hysteresis.center_y,
102 tp->hysteresis.margin_y);
103 t->hysteresis.center_x = x;
104 t->hysteresis.center_y = y;
111 tp_motion_history_reset(struct tp_touch *t)
113 t->history.count = 0;
116 static inline struct tp_touch *
117 tp_current_touch(struct tp_dispatch *tp)
119 return &tp->touches[min(tp->slot, tp->ntouches - 1)];
122 static inline struct tp_touch *
123 tp_get_touch(struct tp_dispatch *tp, unsigned int slot)
125 assert(slot < tp->ntouches);
126 return &tp->touches[slot];
130 tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t)
132 if (t->state != TOUCH_UPDATE) {
133 tp_motion_history_reset(t);
135 t->state = TOUCH_BEGIN;
136 t->pinned.is_pinned = false;
138 assert(tp->nfingers_down >= 1);
139 tp->queued |= TOUCHPAD_EVENT_MOTION;
144 tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t)
146 if (t->state == TOUCH_NONE)
150 t->is_pointer = false;
151 t->palm.is_palm = false;
152 t->state = TOUCH_END;
153 t->pinned.is_pinned = false;
154 assert(tp->nfingers_down >= 1);
156 tp->queued |= TOUCHPAD_EVENT_MOTION;
160 tp_estimate_delta(int x0, int x1, int x2, int x3)
162 return (x0 + x1 - x2 - x3) / 4;
166 tp_get_delta(struct tp_touch *t, double *dx, double *dy)
168 if (t->history.count < 4) {
174 *dx = tp_estimate_delta(tp_motion_history_offset(t, 0)->x,
175 tp_motion_history_offset(t, 1)->x,
176 tp_motion_history_offset(t, 2)->x,
177 tp_motion_history_offset(t, 3)->x);
178 *dy = tp_estimate_delta(tp_motion_history_offset(t, 0)->y,
179 tp_motion_history_offset(t, 1)->y,
180 tp_motion_history_offset(t, 2)->y,
181 tp_motion_history_offset(t, 3)->y);
185 tp_process_absolute(struct tp_dispatch *tp,
186 const struct input_event *e,
189 struct tp_touch *t = tp_current_touch(tp);
192 case ABS_MT_POSITION_X:
196 tp->queued |= TOUCHPAD_EVENT_MOTION;
198 case ABS_MT_POSITION_Y:
202 tp->queued |= TOUCHPAD_EVENT_MOTION;
207 case ABS_MT_TRACKING_ID:
210 tp_begin_touch(tp, t);
217 tp_process_absolute_st(struct tp_dispatch *tp,
218 const struct input_event *e,
221 struct tp_touch *t = tp_current_touch(tp);
228 tp->queued |= TOUCHPAD_EVENT_MOTION;
234 tp->queued |= TOUCHPAD_EVENT_MOTION;
240 tp_process_fake_touch(struct tp_dispatch *tp,
241 const struct input_event *e,
245 unsigned int fake_touches;
246 unsigned int nfake_touches;
250 if (e->code != BTN_TOUCH &&
251 (e->code < BTN_TOOL_DOUBLETAP || e->code > BTN_TOOL_QUADTAP))
254 shift = e->code == BTN_TOUCH ? 0 : (e->code - BTN_TOOL_DOUBLETAP + 1);
257 tp->fake_touches |= 1 << shift;
259 tp->fake_touches &= ~(0x1 << shift);
261 fake_touches = tp->fake_touches;
263 while (fake_touches) {
268 for (i = 0; i < tp->ntouches; i++) {
269 t = tp_get_touch(tp, i);
270 if (i >= nfake_touches) {
271 if (t->state != TOUCH_NONE) {
275 } else if (t->state != TOUCH_UPDATE &&
276 t->state != TOUCH_BEGIN) {
277 t->state = TOUCH_NONE;
278 tp_begin_touch(tp, t);
284 assert(tp->nfingers_down == nfake_touches);
288 tp_process_key(struct tp_dispatch *tp,
289 const struct input_event *e,
296 tp_process_button(tp, e, time);
299 case BTN_TOOL_DOUBLETAP:
300 case BTN_TOOL_TRIPLETAP:
301 case BTN_TOOL_QUADTAP:
303 tp_process_fake_touch(tp, e, time);
309 tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t)
311 unsigned int xdist, ydist;
313 if (!t->pinned.is_pinned)
316 xdist = abs(t->x - t->pinned.center_x);
317 ydist = abs(t->y - t->pinned.center_y);
319 if (xdist * xdist + ydist * ydist >=
320 tp->buttons.motion_dist * tp->buttons.motion_dist) {
321 t->pinned.is_pinned = false;
322 tp_set_pointer(tp, t);
327 tp_pin_fingers(struct tp_dispatch *tp)
331 tp_for_each_touch(tp, t) {
332 t->is_pointer = false;
333 t->pinned.is_pinned = true;
334 t->pinned.center_x = t->x;
335 t->pinned.center_y = t->y;
340 tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
342 return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
344 !t->pinned.is_pinned && tp_button_touch_active(tp, t);
348 tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t)
350 struct tp_touch *tmp = NULL;
352 /* Only set the touch as pointer if we don't have one yet */
353 tp_for_each_touch(tp, tmp) {
358 if (tp_touch_active(tp, t))
359 t->is_pointer = true;
363 tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
365 const int PALM_TIMEOUT = 200; /* ms */
366 const int DIRECTIONS = NE|E|SE|SW|W|NW;
368 /* If labelled a touch as palm, we unlabel as palm when
369 we move out of the palm edge zone within the timeout, provided
370 the direction is within 45 degrees of the horizontal.
372 if (t->palm.is_palm) {
373 if (time < t->palm.time + PALM_TIMEOUT &&
374 (t->x > tp->palm.left_edge && t->x < tp->palm.right_edge)) {
375 int dirs = vector_get_direction(t->x - t->palm.x, t->y - t->palm.y);
376 if ((dirs & DIRECTIONS) && !(dirs & ~DIRECTIONS)) {
377 t->palm.is_palm = false;
378 tp_set_pointer(tp, t);
384 /* palm must start in exclusion zone, it's ok to move into
385 the zone without being a palm */
386 if (t->state != TOUCH_BEGIN ||
387 (t->x > tp->palm.left_edge && t->x < tp->palm.right_edge))
390 /* don't detect palm in software button areas, it's
391 likely that legitimate touches start in the area
392 covered by the exclusion zone */
393 if (tp->buttons.is_clickpad &&
394 tp_button_is_inside_softbutton_area(tp, t))
397 t->palm.is_palm = true;
404 tp_process_state(struct tp_dispatch *tp, uint64_t time)
407 struct tp_touch *first = tp_get_touch(tp, 0);
409 tp_for_each_touch(tp, t) {
410 if (!tp->has_mt && t != first && first->fake) {
414 t->dirty = first->dirty;
415 } else if (!t->dirty) {
419 tp_palm_detect(tp, t, time);
421 tp_motion_hysteresis(tp, t);
422 tp_motion_history_push(t);
424 tp_unpin_finger(tp, t);
427 tp_button_handle_state(tp, time);
430 * We have a physical button down event on a clickpad. To avoid
431 * spurious pointer moves by the clicking finger we pin all fingers.
432 * We unpin fingers when they move more then a certain threshold to
433 * to allow drag and drop.
435 if ((tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) &&
436 tp->buttons.is_clickpad)
441 tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
445 tp_for_each_touch(tp, t) {
449 if (t->state == TOUCH_END) {
450 t->state = TOUCH_NONE;
452 } else if (t->state == TOUCH_BEGIN)
453 t->state = TOUCH_UPDATE;
458 tp->buttons.old_state = tp->buttons.state;
460 tp->queued = TOUCHPAD_EVENT_NONE;
464 tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time)
468 double dx = 0, dy =0;
471 tp_for_each_touch(tp, t) {
472 if (tp_touch_active(tp, t) && t->dirty) {
474 tp_get_delta(t, &tmpx, &tmpy);
479 /* Stop spurious MOTION events at the end of scrolling */
480 t->is_pointer = false;
489 tp_filter_motion(tp, &dx, &dy, time);
491 /* Require at least five px scrolling to start */
492 if (dy <= -5.0 || dy >= 5.0)
493 tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
495 if (dx <= -5.0 || dx >= 5.0)
496 tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
499 (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))) {
500 pointer_notify_axis(&tp->device->base,
502 LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
507 (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))) {
508 pointer_notify_axis(&tp->device->base,
510 LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
516 tp_stop_scroll_events(struct tp_dispatch *tp, uint64_t time)
518 /* terminate scrolling with a zero scroll event */
519 if (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))
520 pointer_notify_axis(&tp->device->base,
522 LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
524 if (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))
525 pointer_notify_axis(&tp->device->base,
527 LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
530 tp->scroll.direction = 0;
534 tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
537 int nfingers_down = 0;
539 /* Only count active touches for 2 finger scrolling */
540 tp_for_each_touch(tp, t) {
541 if (tp_touch_active(tp, t))
545 if (nfingers_down != 2) {
546 tp_stop_scroll_events(tp, time);
550 tp_post_twofinger_scroll(tp, time);
555 tp_post_events(struct tp_dispatch *tp, uint64_t time)
557 struct tp_touch *t = tp_current_touch(tp);
561 consumed |= tp_tap_handle_state(tp, time);
562 consumed |= tp_post_button_events(tp, time);
565 tp_stop_scroll_events(tp, time);
569 if (tp_post_scroll_events(tp, time) != 0)
572 if (!t->is_pointer) {
573 tp_for_each_touch(tp, t) {
579 if (!t->is_pointer ||
581 t->history.count < TOUCHPAD_MIN_SAMPLES)
584 tp_get_delta(t, &dx, &dy);
585 tp_filter_motion(tp, &dx, &dy, time);
587 if (dx != 0.0 || dy != 0.0)
588 pointer_notify_motion(&tp->device->base, time, dx, dy);
592 tp_process(struct evdev_dispatch *dispatch,
593 struct evdev_device *device,
594 struct input_event *e,
597 struct tp_dispatch *tp =
598 (struct tp_dispatch *)dispatch;
603 tp_process_absolute(tp, e, time);
605 tp_process_absolute_st(tp, e, time);
608 tp_process_key(tp, e, time);
611 tp_process_state(tp, time);
612 tp_post_events(tp, time);
613 tp_post_process_state(tp, time);
619 tp_destroy(struct evdev_dispatch *dispatch)
621 struct tp_dispatch *tp =
622 (struct tp_dispatch*)dispatch;
625 tp_destroy_buttons(tp);
627 filter_destroy(tp->filter);
632 static struct evdev_dispatch_interface tp_interface = {
638 tp_init_touch(struct tp_dispatch *tp,
645 tp_init_slots(struct tp_dispatch *tp,
646 struct evdev_device *device)
649 const struct input_absinfo *absinfo;
651 absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_SLOT);
653 tp->ntouches = absinfo->maximum + 1;
654 tp->slot = absinfo->value;
661 { BTN_TOOL_QUINTTAP, 5 },
662 { BTN_TOOL_QUADTAP, 4 },
663 { BTN_TOOL_TRIPLETAP, 3 },
664 { BTN_TOOL_DOUBLETAP, 2 },
672 ARRAY_FOR_EACH(max_touches, m) {
673 if (libevdev_has_event_code(device->evdev,
676 tp->ntouches = m->ntouches;
681 tp->touches = calloc(tp->ntouches,
682 sizeof(struct tp_touch));
686 for (i = 0; i < tp->ntouches; i++)
687 tp_init_touch(tp, &tp->touches[i]);
693 tp_init_accel(struct tp_dispatch *tp, double diagonal)
695 struct motion_filter *accel;
699 res_x = libevdev_get_abs_resolution(tp->device->evdev,
701 res_y = libevdev_get_abs_resolution(tp->device->evdev,
704 res_x = libevdev_get_abs_resolution(tp->device->evdev,
706 res_y = libevdev_get_abs_resolution(tp->device->evdev,
711 * Not all touchpads report the same amount of units/mm (resolution).
712 * Normalize motion events to a resolution of 15.74 units/mm
713 * (== 400 dpi) as base (unaccelerated) speed. This also evens out any
714 * differences in x and y resolution, so that a circle on the
715 * touchpad does not turn into an elipse on the screen.
717 * We pick 400dpi as thats one of the many default resolutions
718 * for USB mice, so we end up with a similar base speed on the device.
720 if (res_x > 1 && res_y > 1) {
721 tp->accel.x_scale_coeff = (400/25.4) / res_x;
722 tp->accel.y_scale_coeff = (400/25.4) / res_y;
725 * For touchpads where the driver does not provide resolution, fall
726 * back to scaling motion events based on the diagonal size in units.
728 tp->accel.x_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
729 tp->accel.y_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
732 accel = create_pointer_accelator_filter(
733 pointer_accel_profile_smooth_simple);
743 tp_init_scroll(struct tp_dispatch *tp)
745 tp->scroll.direction = 0;
751 tp_init_palmdetect(struct tp_dispatch *tp,
752 struct evdev_device *device)
756 width = abs(device->abs.absinfo_x->maximum -
757 device->abs.absinfo_x->minimum);
759 /* palm edges are 5% of the width on each side */
760 tp->palm.right_edge = device->abs.absinfo_x->maximum - width * 0.05;
761 tp->palm.left_edge = device->abs.absinfo_x->minimum + width * 0.05;
768 tp_init(struct tp_dispatch *tp,
769 struct evdev_device *device)
774 tp->base.interface = &tp_interface;
777 if (tp_init_slots(tp, device) != 0)
780 width = abs(device->abs.absinfo_x->maximum -
781 device->abs.absinfo_x->minimum);
782 height = abs(device->abs.absinfo_y->maximum -
783 device->abs.absinfo_y->minimum);
784 diagonal = sqrt(width*width + height*height);
786 tp->hysteresis.margin_x =
787 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
788 tp->hysteresis.margin_y =
789 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
791 if (tp_init_scroll(tp) != 0)
794 if (tp_init_accel(tp, diagonal) != 0)
797 if (tp_init_tap(tp) != 0)
800 if (tp_init_buttons(tp, device) != 0)
803 if (tp_init_palmdetect(tp, device) != 0)
809 struct evdev_dispatch *
810 evdev_mt_touchpad_create(struct evdev_device *device)
812 struct tp_dispatch *tp;
814 tp = zalloc(sizeof *tp);
818 if (tp_init(tp, device) != 0) {
819 tp_destroy(&tp->base);