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.
30 #include "evdev-mt-touchpad.h"
32 /* Number found by trial-and error, seems to be 1200, divided by the
33 * TP_MAGIC_SLOWDOWN in filter.c */
34 #define DEFAULT_ACCEL_NUMERATOR 3000.0
35 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
36 #define DEFAULT_TRACKPOINT_ACTIVITY_TIMEOUT 500 /* ms */
37 #define FAKE_FINGER_OVERFLOW (1 << 7)
40 tp_hysteresis(int in, int center, int margin)
42 int diff = in - center;
43 if (abs(diff) <= margin)
47 return center + diff - margin;
49 return center + diff + margin;
52 static inline struct device_coords *
53 tp_motion_history_offset(struct tp_touch *t, int offset)
56 (t->history.index - offset + TOUCHPAD_HISTORY_LENGTH) %
57 TOUCHPAD_HISTORY_LENGTH;
59 return &t->history.samples[offset_index];
62 struct normalized_coords
63 tp_filter_motion(struct tp_dispatch *tp,
64 const struct normalized_coords *unaccelerated,
67 if (normalized_is_zero(*unaccelerated))
68 return *unaccelerated;
70 return filter_dispatch(tp->device->pointer.filter,
71 unaccelerated, tp, time);
75 tp_motion_history_push(struct tp_touch *t)
77 int motion_index = (t->history.index + 1) % TOUCHPAD_HISTORY_LENGTH;
79 if (t->history.count < TOUCHPAD_HISTORY_LENGTH)
82 t->history.samples[motion_index] = t->point;
83 t->history.index = motion_index;
87 tp_motion_hysteresis(struct tp_dispatch *tp,
93 if (t->history.count == 0) {
94 t->hysteresis_center = t->point;
97 t->hysteresis_center.x,
98 tp->hysteresis_margin.x);
100 t->hysteresis_center.y,
101 tp->hysteresis_margin.y);
102 t->hysteresis_center.x = x;
103 t->hysteresis_center.y = y;
110 tp_motion_history_reset(struct tp_touch *t)
112 t->history.count = 0;
115 static inline struct tp_touch *
116 tp_current_touch(struct tp_dispatch *tp)
118 return &tp->touches[min(tp->slot, tp->ntouches - 1)];
121 static inline struct tp_touch *
122 tp_get_touch(struct tp_dispatch *tp, unsigned int slot)
124 assert(slot < tp->ntouches);
125 return &tp->touches[slot];
128 static inline unsigned int
129 tp_fake_finger_count(struct tp_dispatch *tp)
131 if (tp->fake_touches & FAKE_FINGER_OVERFLOW)
132 return FAKE_FINGER_OVERFLOW;
133 else /* don't count BTN_TOUCH */
134 return ffs(tp->fake_touches >> 1);
138 tp_fake_finger_is_touching(struct tp_dispatch *tp)
140 return tp->fake_touches & 0x1;
144 tp_fake_finger_set(struct tp_dispatch *tp,
153 tp->fake_touches &= ~FAKE_FINGER_OVERFLOW;
156 case BTN_TOOL_FINGER:
159 case BTN_TOOL_DOUBLETAP:
160 case BTN_TOOL_TRIPLETAP:
161 case BTN_TOOL_QUADTAP:
162 shift = code - BTN_TOOL_DOUBLETAP + 2;
164 /* when QUINTTAP is released we're either switching to 6 fingers
165 (flag stays in place until BTN_TOUCH is released) or
166 one of DOUBLE/TRIPLE/QUADTAP (will clear the flag on press) */
167 case BTN_TOOL_QUINTTAP:
169 tp->fake_touches |= FAKE_FINGER_OVERFLOW;
176 tp->fake_touches &= ~FAKE_FINGER_OVERFLOW;
177 tp->fake_touches |= 1 << shift;
180 tp->fake_touches &= ~(0x1 << shift);
185 tp_new_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
187 if (t->state == TOUCH_BEGIN ||
188 t->state == TOUCH_UPDATE ||
189 t->state == TOUCH_HOVERING)
192 /* we begin the touch as hovering because until BTN_TOUCH happens we
193 * don't know if it's a touch down or not. And BTN_TOUCH may happen
194 * after ABS_MT_TRACKING_ID */
195 tp_motion_history_reset(t);
197 t->has_ended = false;
198 t->state = TOUCH_HOVERING;
199 t->pinned.is_pinned = false;
201 tp->queued |= TOUCHPAD_EVENT_MOTION;
205 tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
208 t->state = TOUCH_BEGIN;
211 assert(tp->nfingers_down >= 1);
215 * End a touch, even if the touch sequence is still active.
218 tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
222 t->state = TOUCH_NONE;
234 t->palm.is_palm = false;
235 t->state = TOUCH_END;
236 t->pinned.is_pinned = false;
238 assert(tp->nfingers_down >= 1);
240 tp->queued |= TOUCHPAD_EVENT_MOTION;
244 * End the touch sequence on ABS_MT_TRACKING_ID -1 or when the BTN_TOOL_* 0 is received.
247 tp_end_sequence(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
250 tp_end_touch(tp, t, time);
254 tp_estimate_delta(int x0, int x1, int x2, int x3)
256 return (x0 + x1 - x2 - x3) / 4.0;
259 struct normalized_coords
260 tp_get_delta(struct tp_touch *t)
262 struct device_float_coords delta;
263 const struct normalized_coords zero = { 0.0, 0.0 };
265 if (t->history.count < TOUCHPAD_MIN_SAMPLES)
268 delta.x = tp_estimate_delta(tp_motion_history_offset(t, 0)->x,
269 tp_motion_history_offset(t, 1)->x,
270 tp_motion_history_offset(t, 2)->x,
271 tp_motion_history_offset(t, 3)->x);
272 delta.y = tp_estimate_delta(tp_motion_history_offset(t, 0)->y,
273 tp_motion_history_offset(t, 1)->y,
274 tp_motion_history_offset(t, 2)->y,
275 tp_motion_history_offset(t, 3)->y);
277 return tp_normalize_delta(t->tp, delta);
281 tp_process_absolute(struct tp_dispatch *tp,
282 const struct input_event *e,
285 struct tp_touch *t = tp_current_touch(tp);
288 case ABS_MT_POSITION_X:
289 t->point.x = e->value;
292 tp->queued |= TOUCHPAD_EVENT_MOTION;
294 case ABS_MT_POSITION_Y:
295 t->point.y = e->value;
298 tp->queued |= TOUCHPAD_EVENT_MOTION;
303 case ABS_MT_TRACKING_ID:
305 tp_new_touch(tp, t, time);
307 tp_end_sequence(tp, t, time);
312 tp_process_absolute_st(struct tp_dispatch *tp,
313 const struct input_event *e,
316 struct tp_touch *t = tp_current_touch(tp);
320 t->point.x = e->value;
323 tp->queued |= TOUCHPAD_EVENT_MOTION;
326 t->point.y = e->value;
329 tp->queued |= TOUCHPAD_EVENT_MOTION;
335 tp_process_fake_touches(struct tp_dispatch *tp,
339 unsigned int nfake_touches;
340 unsigned int i, start;
342 nfake_touches = tp_fake_finger_count(tp);
343 if (nfake_touches == FAKE_FINGER_OVERFLOW)
346 start = tp->has_mt ? tp->num_slots : 0;
347 for (i = start; i < tp->ntouches; i++) {
348 t = tp_get_touch(tp, i);
349 if (i < nfake_touches)
350 tp_new_touch(tp, t, time);
352 tp_end_sequence(tp, t, time);
357 tp_process_trackpoint_button(struct tp_dispatch *tp,
358 const struct input_event *e,
361 struct evdev_dispatch *dispatch;
362 struct input_event event;
364 if (!tp->buttons.trackpoint ||
365 (tp->device->tags & EVDEV_TAG_TOUCHPAD_TRACKPOINT) == 0)
368 dispatch = tp->buttons.trackpoint->dispatch;
372 switch (event.code) {
374 event.code = BTN_LEFT;
377 event.code = BTN_RIGHT;
380 event.code = BTN_MIDDLE;
386 dispatch->interface->process(dispatch,
387 tp->buttons.trackpoint,
392 tp_process_key(struct tp_dispatch *tp,
393 const struct input_event *e,
400 tp_process_button(tp, e, time);
403 case BTN_TOOL_FINGER:
404 case BTN_TOOL_DOUBLETAP:
405 case BTN_TOOL_TRIPLETAP:
406 case BTN_TOOL_QUADTAP:
407 case BTN_TOOL_QUINTTAP:
408 tp_fake_finger_set(tp, e->code, !!e->value);
413 tp_process_trackpoint_button(tp, e, time);
419 tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t)
421 unsigned int xdist, ydist;
423 if (!t->pinned.is_pinned)
426 xdist = abs(t->point.x - t->pinned.center.x);
427 ydist = abs(t->point.y - t->pinned.center.y);
429 if (xdist * xdist + ydist * ydist >=
430 tp->buttons.motion_dist * tp->buttons.motion_dist) {
431 t->pinned.is_pinned = false;
435 /* The finger may slowly drift, adjust the center */
436 t->pinned.center.x = t->point.x + t->pinned.center.x / 2;
437 t->pinned.center.y = t->point.y + t->pinned.center.y / 2;
441 tp_pin_fingers(struct tp_dispatch *tp)
445 tp_for_each_touch(tp, t) {
446 t->pinned.is_pinned = true;
447 t->pinned.center = t->point;
452 tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
454 return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
456 !t->pinned.is_pinned &&
457 tp_button_touch_active(tp, t) &&
458 tp_edge_scroll_touch_active(tp, t);
462 tp_palm_tap_is_palm(struct tp_dispatch *tp, struct tp_touch *t)
464 if (t->state != TOUCH_BEGIN)
467 if (t->point.x > tp->palm.left_edge &&
468 t->point.x < tp->palm.right_edge)
471 /* We're inside the left/right palm edge and in the northern half of
472 * the touchpad - this tap is a palm */
473 if (t->point.y < tp->palm.vert_center)
480 tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
482 const int PALM_TIMEOUT = 200; /* ms */
483 const int DIRECTIONS = NE|E|SE|SW|W|NW;
484 struct device_float_coords delta;
487 /* If labelled a touch as palm, we unlabel as palm when
488 we move out of the palm edge zone within the timeout, provided
489 the direction is within 45 degrees of the horizontal.
491 if (t->palm.is_palm) {
492 if (time < t->palm.time + PALM_TIMEOUT &&
493 (t->point.x > tp->palm.left_edge && t->point.x < tp->palm.right_edge)) {
494 delta = device_delta(t->point, t->palm.first);
495 dirs = normalized_get_direction(
496 tp_normalize_delta(tp, delta));
497 if ((dirs & DIRECTIONS) && !(dirs & ~DIRECTIONS)) {
498 t->palm.is_palm = false;
504 /* palm must start in exclusion zone, it's ok to move into
505 the zone without being a palm */
506 if (t->state != TOUCH_BEGIN ||
507 (t->point.x > tp->palm.left_edge && t->point.x < tp->palm.right_edge))
510 /* don't detect palm in software button areas, it's
511 likely that legitimate touches start in the area
512 covered by the exclusion zone */
513 if (tp->buttons.is_clickpad &&
514 tp_button_is_inside_softbutton_area(tp, t))
517 t->palm.is_palm = true;
519 t->palm.first = t->point;
523 tp_unhover_touches(struct tp_dispatch *tp, uint64_t time)
526 unsigned int nfake_touches;
529 if (!tp->fake_touches && !tp->nfingers_down)
532 nfake_touches = tp_fake_finger_count(tp);
533 if (nfake_touches == FAKE_FINGER_OVERFLOW)
536 if (tp->nfingers_down == nfake_touches &&
537 ((tp->nfingers_down == 0 && !tp_fake_finger_is_touching(tp)) ||
538 (tp->nfingers_down > 0 && tp_fake_finger_is_touching(tp))))
541 /* if BTN_TOUCH is set and we have less fingers down than fake
542 * touches, switch each hovering touch to BEGIN
543 * until nfingers_down matches nfake_touches
545 if (tp_fake_finger_is_touching(tp) &&
546 tp->nfingers_down < nfake_touches) {
547 for (i = 0; i < (int)tp->ntouches; i++) {
548 t = tp_get_touch(tp, i);
550 if (t->state == TOUCH_HOVERING) {
551 tp_begin_touch(tp, t, time);
553 if (tp->nfingers_down >= nfake_touches)
559 /* if BTN_TOUCH is unset end all touches, we're hovering now. If we
560 * have too many touches also end some of them. This is done in
563 if (tp->nfingers_down > nfake_touches ||
564 !tp_fake_finger_is_touching(tp)) {
565 for (i = tp->ntouches - 1; i >= 0; i--) {
566 t = tp_get_touch(tp, i);
568 if (t->state == TOUCH_HOVERING ||
569 t->state == TOUCH_NONE)
572 tp_end_touch(tp, t, time);
574 if (tp_fake_finger_is_touching(tp) &&
575 tp->nfingers_down == nfake_touches)
582 tp_process_state(struct tp_dispatch *tp, uint64_t time)
585 struct tp_touch *first = tp_get_touch(tp, 0);
588 tp_process_fake_touches(tp, time);
589 tp_unhover_touches(tp, time);
591 for (i = 0; i < tp->ntouches; i++) {
592 t = tp_get_touch(tp, i);
594 /* semi-mt finger postions may "jump" when nfingers changes */
595 if (tp->semi_mt && tp->nfingers_down != tp->old_nfingers_down)
596 tp_motion_history_reset(t);
598 if (i >= tp->num_slots && t->state != TOUCH_NONE) {
599 t->point = first->point;
601 t->dirty = first->dirty;
607 tp_palm_detect(tp, t, time);
609 tp_motion_hysteresis(tp, t);
610 tp_motion_history_push(t);
612 tp_unpin_finger(tp, t);
615 tp_button_handle_state(tp, time);
616 tp_edge_scroll_handle_state(tp, time);
619 * We have a physical button down event on a clickpad. To avoid
620 * spurious pointer moves by the clicking finger we pin all fingers.
621 * We unpin fingers when they move more then a certain threshold to
622 * to allow drag and drop.
624 if ((tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) &&
625 tp->buttons.is_clickpad)
628 tp_gesture_handle_state(tp, time);
632 tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
636 tp_for_each_touch(tp, t) {
641 if (t->state == TOUCH_END) {
643 t->state = TOUCH_NONE;
645 t->state = TOUCH_HOVERING;
646 } else if (t->state == TOUCH_BEGIN) {
647 t->state = TOUCH_UPDATE;
653 tp->old_nfingers_down = tp->nfingers_down;
654 tp->buttons.old_state = tp->buttons.state;
656 tp->queued = TOUCHPAD_EVENT_NONE;
660 tp_post_events(struct tp_dispatch *tp, uint64_t time)
662 int filter_motion = 0;
664 /* Only post (top) button events while suspended */
665 if (tp->device->suspended) {
666 tp_post_button_events(tp, time);
670 filter_motion |= tp_tap_handle_state(tp, time);
671 filter_motion |= tp_post_button_events(tp, time);
673 if (filter_motion || tp->sendevents.trackpoint_active) {
674 tp_edge_scroll_stop_events(tp, time);
675 tp_gesture_stop(tp, time);
679 if (tp_edge_scroll_post_events(tp, time) != 0)
682 tp_gesture_post_events(tp, time);
686 tp_handle_state(struct tp_dispatch *tp,
689 tp_process_state(tp, time);
690 tp_post_events(tp, time);
691 tp_post_process_state(tp, time);
695 tp_process(struct evdev_dispatch *dispatch,
696 struct evdev_device *device,
697 struct input_event *e,
700 struct tp_dispatch *tp =
701 (struct tp_dispatch *)dispatch;
706 tp_process_absolute(tp, e, time);
708 tp_process_absolute_st(tp, e, time);
711 tp_process_key(tp, e, time);
714 tp_handle_state(tp, time);
720 tp_remove_sendevents(struct tp_dispatch *tp)
722 libinput_timer_cancel(&tp->sendevents.trackpoint_timer);
724 if (tp->buttons.trackpoint)
725 libinput_device_remove_event_listener(
726 &tp->sendevents.trackpoint_listener);
730 tp_remove(struct evdev_dispatch *dispatch)
732 struct tp_dispatch *tp =
733 (struct tp_dispatch*)dispatch;
736 tp_remove_buttons(tp);
737 tp_remove_sendevents(tp);
738 tp_remove_edge_scroll(tp);
739 tp_remove_gesture(tp);
743 tp_destroy(struct evdev_dispatch *dispatch)
745 struct tp_dispatch *tp =
746 (struct tp_dispatch*)dispatch;
753 tp_clear_state(struct tp_dispatch *tp)
755 uint64_t now = libinput_now(tp->device->base.seat->libinput);
758 /* Unroll the touchpad state.
759 * Release buttons first. If tp is a clickpad, the button event
760 * must come before the touch up. If it isn't, the order doesn't
763 * Then cancel all timeouts on the taps, triggering the last set
766 * Then lift all touches so the touchpad is in a neutral state.
769 tp_release_all_buttons(tp, now);
770 tp_release_all_taps(tp, now);
772 tp_for_each_touch(tp, t) {
773 tp_end_sequence(tp, t, now);
776 tp_handle_state(tp, now);
780 tp_suspend(struct tp_dispatch *tp, struct evdev_device *device)
784 /* On devices with top softwarebuttons we don't actually suspend the
785 * device, to keep the "trackpoint" buttons working. tp_post_events()
786 * will only send events for the trackpoint while suspended.
788 if (tp->buttons.has_topbuttons) {
789 evdev_notify_suspended_device(device);
790 /* Enlarge topbutton area while suspended */
791 tp_init_top_softbuttons(tp, device, 1.5);
793 evdev_device_suspend(device);
798 tp_resume(struct tp_dispatch *tp, struct evdev_device *device)
800 if (tp->buttons.has_topbuttons) {
801 /* tap state-machine is offline while suspended, reset state */
803 /* restore original topbutton area size */
804 tp_init_top_softbuttons(tp, device, 1.0);
805 evdev_notify_resumed_device(device);
807 evdev_device_resume(device);
812 tp_trackpoint_timeout(uint64_t now, void *data)
814 struct tp_dispatch *tp = data;
816 tp_tap_resume(tp, now);
817 tp->sendevents.trackpoint_active = false;
821 tp_trackpoint_event(uint64_t time, struct libinput_event *event, void *data)
823 struct tp_dispatch *tp = data;
825 /* Buttons do not count as trackpad activity, as people may use
826 the trackpoint buttons in combination with the touchpad. */
827 if (event->type == LIBINPUT_EVENT_POINTER_BUTTON)
830 if (!tp->sendevents.trackpoint_active) {
831 tp_edge_scroll_stop_events(tp, time);
832 tp_gesture_stop(tp, time);
833 tp_tap_suspend(tp, time);
834 tp->sendevents.trackpoint_active = true;
837 libinput_timer_set(&tp->sendevents.trackpoint_timer,
838 time + DEFAULT_TRACKPOINT_ACTIVITY_TIMEOUT);
842 tp_device_added(struct evdev_device *device,
843 struct evdev_device *added_device)
845 struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch;
846 unsigned int bus_tp = libevdev_get_id_bustype(device->evdev),
847 bus_trp = libevdev_get_id_bustype(added_device->evdev);
848 bool tp_is_internal, trp_is_internal;
850 tp_is_internal = bus_tp != BUS_USB && bus_tp != BUS_BLUETOOTH;
851 trp_is_internal = bus_trp != BUS_USB && bus_trp != BUS_BLUETOOTH;
853 if (tp->buttons.trackpoint == NULL &&
854 (added_device->tags & EVDEV_TAG_TRACKPOINT) &&
855 tp_is_internal && trp_is_internal) {
856 /* Don't send any pending releases to the new trackpoint */
857 tp->buttons.active_is_topbutton = false;
858 tp->buttons.trackpoint = added_device;
859 libinput_device_add_event_listener(&added_device->base,
860 &tp->sendevents.trackpoint_listener,
861 tp_trackpoint_event, tp);
864 if (tp->sendevents.current_mode !=
865 LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
868 if (added_device->tags & EVDEV_TAG_EXTERNAL_MOUSE)
869 tp_suspend(tp, device);
873 tp_device_removed(struct evdev_device *device,
874 struct evdev_device *removed_device)
876 struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch;
877 struct libinput_device *dev;
879 if (removed_device == tp->buttons.trackpoint) {
880 /* Clear any pending releases for the trackpoint */
881 if (tp->buttons.active && tp->buttons.active_is_topbutton) {
882 tp->buttons.active = 0;
883 tp->buttons.active_is_topbutton = false;
885 libinput_device_remove_event_listener(
886 &tp->sendevents.trackpoint_listener);
887 tp->buttons.trackpoint = NULL;
890 if (tp->sendevents.current_mode !=
891 LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
894 list_for_each(dev, &device->base.seat->devices_list, link) {
895 struct evdev_device *d = (struct evdev_device*)dev;
896 if (d != removed_device &&
897 (d->tags & EVDEV_TAG_EXTERNAL_MOUSE)) {
902 tp_resume(tp, device);
906 tp_tag_device(struct evdev_device *device,
907 struct udev_device *udev_device)
911 /* simple approach: touchpads on USB or Bluetooth are considered
912 * external, anything else is internal. Exception is Apple -
913 * internal touchpads are connected over USB and it doesn't have
914 * external USB touchpads anyway.
916 bustype = libevdev_get_id_bustype(device->evdev);
917 if (bustype == BUS_USB) {
918 if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_APPLE)
919 device->tags |= EVDEV_TAG_INTERNAL_TOUCHPAD;
920 } else if (bustype != BUS_BLUETOOTH)
921 device->tags |= EVDEV_TAG_INTERNAL_TOUCHPAD;
923 if (udev_device_get_property_value(udev_device,
924 "TOUCHPAD_HAS_TRACKPOINT_BUTTONS"))
925 device->tags |= EVDEV_TAG_TOUCHPAD_TRACKPOINT;
928 static struct evdev_dispatch_interface tp_interface = {
934 tp_device_removed, /* device_suspended, treat as remove */
935 tp_device_added, /* device_resumed, treat as add */
940 tp_init_touch(struct tp_dispatch *tp,
948 tp_init_slots(struct tp_dispatch *tp,
949 struct evdev_device *device)
951 const struct input_absinfo *absinfo;
956 { BTN_TOOL_QUINTTAP, 5 },
957 { BTN_TOOL_QUADTAP, 4 },
958 { BTN_TOOL_TRIPLETAP, 3 },
959 { BTN_TOOL_DOUBLETAP, 2 },
962 unsigned int i, n_btn_tool_touches = 1;
964 absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_SLOT);
966 tp->num_slots = absinfo->maximum + 1;
967 tp->slot = absinfo->value;
975 tp->semi_mt = libevdev_has_property(device->evdev, INPUT_PROP_SEMI_MT);
977 ARRAY_FOR_EACH(max_touches, m) {
978 if (libevdev_has_event_code(device->evdev,
981 n_btn_tool_touches = m->ntouches;
986 tp->ntouches = max(tp->num_slots, n_btn_tool_touches);
987 tp->touches = calloc(tp->ntouches, sizeof(struct tp_touch));
991 for (i = 0; i < tp->ntouches; i++)
992 tp_init_touch(tp, &tp->touches[i]);
998 tp_init_accel(struct tp_dispatch *tp, double diagonal)
1001 accel_profile_func_t profile;
1003 res_x = tp->device->abs.absinfo_x->resolution;
1004 res_y = tp->device->abs.absinfo_y->resolution;
1007 * Not all touchpads report the same amount of units/mm (resolution).
1008 * Normalize motion events to the default mouse DPI as base
1009 * (unaccelerated) speed. This also evens out any differences in x
1010 * and y resolution, so that a circle on the
1011 * touchpad does not turn into an elipse on the screen.
1013 if (res_x > 1 && res_y > 1) {
1014 tp->accel.x_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_x;
1015 tp->accel.y_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_y;
1018 * For touchpads where the driver does not provide resolution, fall
1019 * back to scaling motion events based on the diagonal size in units.
1021 tp->accel.x_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
1022 tp->accel.y_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
1025 switch (tp->device->model) {
1026 case EVDEV_MODEL_LENOVO_X230:
1027 profile = touchpad_lenovo_x230_accel_profile;
1030 profile = touchpad_accel_profile_linear;
1034 if (evdev_device_init_pointer_acceleration(tp->device, profile) == -1)
1041 tp_scroll_config_scroll_method_get_methods(struct libinput_device *device)
1043 struct evdev_device *evdev = (struct evdev_device*)device;
1044 struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
1045 uint32_t methods = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
1047 if (tp->ntouches >= 2)
1048 methods |= LIBINPUT_CONFIG_SCROLL_2FG;
1050 if (!tp->buttons.is_clickpad)
1051 methods |= LIBINPUT_CONFIG_SCROLL_EDGE;
1056 static enum libinput_config_status
1057 tp_scroll_config_scroll_method_set_method(struct libinput_device *device,
1058 enum libinput_config_scroll_method method)
1060 struct evdev_device *evdev = (struct evdev_device*)device;
1061 struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
1062 uint64_t time = libinput_now(device->seat->libinput);
1064 if (method == tp->scroll.method)
1065 return LIBINPUT_CONFIG_STATUS_SUCCESS;
1067 tp_edge_scroll_stop_events(tp, time);
1068 tp_gesture_stop_twofinger_scroll(tp, time);
1070 tp->scroll.method = method;
1072 return LIBINPUT_CONFIG_STATUS_SUCCESS;
1075 static enum libinput_config_scroll_method
1076 tp_scroll_config_scroll_method_get_method(struct libinput_device *device)
1078 struct evdev_device *evdev = (struct evdev_device*)device;
1079 struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
1081 return tp->scroll.method;
1084 static enum libinput_config_scroll_method
1085 tp_scroll_get_default_method(struct tp_dispatch *tp)
1087 if (tp->ntouches >= 2)
1088 return LIBINPUT_CONFIG_SCROLL_2FG;
1090 return LIBINPUT_CONFIG_SCROLL_EDGE;
1093 static enum libinput_config_scroll_method
1094 tp_scroll_config_scroll_method_get_default_method(struct libinput_device *device)
1096 struct evdev_device *evdev = (struct evdev_device*)device;
1097 struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
1099 return tp_scroll_get_default_method(tp);
1103 tp_init_scroll(struct tp_dispatch *tp, struct evdev_device *device)
1105 if (tp_edge_scroll_init(tp, device) != 0)
1108 evdev_init_natural_scroll(device);
1110 tp->scroll.config_method.get_methods = tp_scroll_config_scroll_method_get_methods;
1111 tp->scroll.config_method.set_method = tp_scroll_config_scroll_method_set_method;
1112 tp->scroll.config_method.get_method = tp_scroll_config_scroll_method_get_method;
1113 tp->scroll.config_method.get_default_method = tp_scroll_config_scroll_method_get_default_method;
1114 tp->scroll.method = tp_scroll_get_default_method(tp);
1115 tp->device->base.config.scroll_method = &tp->scroll.config_method;
1117 /* In mm for touchpads with valid resolution, see tp_init_accel() */
1118 tp->device->scroll.threshold = 5.0;
1124 tp_init_palmdetect(struct tp_dispatch *tp,
1125 struct evdev_device *device)
1129 tp->palm.right_edge = INT_MAX;
1130 tp->palm.left_edge = INT_MIN;
1131 tp->palm.vert_center = INT_MIN;
1133 width = abs(device->abs.absinfo_x->maximum -
1134 device->abs.absinfo_x->minimum);
1135 height = abs(device->abs.absinfo_y->maximum -
1136 device->abs.absinfo_y->minimum);
1138 /* Apple touchpads are always big enough to warrant palm detection */
1139 if (evdev_device_get_id_vendor(device) != VENDOR_ID_APPLE) {
1140 /* We don't know how big the touchpad is */
1141 if (device->abs.absinfo_x->resolution == 1)
1144 /* Enable palm detection on touchpads >= 70 mm. Anything smaller
1145 probably won't need it, until we find out it does */
1146 if (width/device->abs.absinfo_x->resolution < 70)
1150 /* palm edges are 5% of the width on each side */
1151 tp->palm.right_edge = device->abs.absinfo_x->maximum - width * 0.05;
1152 tp->palm.left_edge = device->abs.absinfo_x->minimum + width * 0.05;
1153 tp->palm.vert_center = device->abs.absinfo_y->minimum + height/2;
1159 tp_init_sendevents(struct tp_dispatch *tp,
1160 struct evdev_device *device)
1162 libinput_timer_init(&tp->sendevents.trackpoint_timer,
1163 tp->device->base.seat->libinput,
1164 tp_trackpoint_timeout, tp);
1169 tp_init(struct tp_dispatch *tp,
1170 struct evdev_device *device)
1175 tp->base.interface = &tp_interface;
1176 tp->device = device;
1178 if (tp_init_slots(tp, device) != 0)
1181 width = abs(device->abs.absinfo_x->maximum -
1182 device->abs.absinfo_x->minimum);
1183 height = abs(device->abs.absinfo_y->maximum -
1184 device->abs.absinfo_y->minimum);
1185 diagonal = sqrt(width*width + height*height);
1187 tp->hysteresis_margin.x =
1188 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
1189 tp->hysteresis_margin.y =
1190 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
1192 if (tp_init_accel(tp, diagonal) != 0)
1195 if (tp_init_tap(tp) != 0)
1198 if (tp_init_buttons(tp, device) != 0)
1201 if (tp_init_palmdetect(tp, device) != 0)
1204 if (tp_init_sendevents(tp, device) != 0)
1207 if (tp_init_scroll(tp, device) != 0)
1210 if (tp_init_gesture(tp) != 0)
1213 device->seat_caps |= EVDEV_DEVICE_POINTER;
1219 tp_sendevents_get_modes(struct libinput_device *device)
1221 struct evdev_device *evdev = (struct evdev_device*)device;
1222 uint32_t modes = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
1224 if (evdev->tags & EVDEV_TAG_INTERNAL_TOUCHPAD)
1225 modes |= LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
1231 tp_suspend_conditional(struct tp_dispatch *tp,
1232 struct evdev_device *device)
1234 struct libinput_device *dev;
1236 list_for_each(dev, &device->base.seat->devices_list, link) {
1237 struct evdev_device *d = (struct evdev_device*)dev;
1238 if (d->tags & EVDEV_TAG_EXTERNAL_MOUSE) {
1239 tp_suspend(tp, device);
1245 static enum libinput_config_status
1246 tp_sendevents_set_mode(struct libinput_device *device,
1247 enum libinput_config_send_events_mode mode)
1249 struct evdev_device *evdev = (struct evdev_device*)device;
1250 struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
1252 /* DISABLED overrides any DISABLED_ON_ */
1253 if ((mode & LIBINPUT_CONFIG_SEND_EVENTS_DISABLED) &&
1254 (mode & LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE))
1255 mode &= ~LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
1257 if (mode == tp->sendevents.current_mode)
1258 return LIBINPUT_CONFIG_STATUS_SUCCESS;
1261 case LIBINPUT_CONFIG_SEND_EVENTS_ENABLED:
1262 tp_resume(tp, evdev);
1264 case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED:
1265 tp_suspend(tp, evdev);
1267 case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE:
1268 tp_suspend_conditional(tp, evdev);
1271 return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
1274 tp->sendevents.current_mode = mode;
1276 return LIBINPUT_CONFIG_STATUS_SUCCESS;
1279 static enum libinput_config_send_events_mode
1280 tp_sendevents_get_mode(struct libinput_device *device)
1282 struct evdev_device *evdev = (struct evdev_device*)device;
1283 struct tp_dispatch *dispatch = (struct tp_dispatch*)evdev->dispatch;
1285 return dispatch->sendevents.current_mode;
1288 static enum libinput_config_send_events_mode
1289 tp_sendevents_get_default_mode(struct libinput_device *device)
1291 return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
1295 tp_change_to_left_handed(struct evdev_device *device)
1297 struct tp_dispatch *tp = (struct tp_dispatch *)device->dispatch;
1299 if (device->left_handed.want_enabled == device->left_handed.enabled)
1302 if (tp->buttons.state & 0x3) /* BTN_LEFT|BTN_RIGHT */
1305 /* tapping and clickfinger aren't affected by left-handed config,
1306 * so checking physical buttons is enough */
1308 device->left_handed.enabled = device->left_handed.want_enabled;
1311 struct model_lookup_t {
1313 uint16_t product_start;
1314 uint16_t product_end;
1315 enum touchpad_model model;
1318 static struct model_lookup_t model_lookup_table[] = {
1319 { 0x0002, 0x0007, 0x0007, MODEL_SYNAPTICS },
1320 { 0x0002, 0x0008, 0x0008, MODEL_ALPS },
1321 { 0x0002, 0x000e, 0x000e, MODEL_ELANTECH },
1322 { 0x05ac, 0, 0x0222, MODEL_APPLETOUCH },
1323 { 0x05ac, 0x0223, 0x0228, MODEL_UNIBODY_MACBOOK },
1324 { 0x05ac, 0x0229, 0x022b, MODEL_APPLETOUCH },
1325 { 0x05ac, 0x022c, 0xffff, MODEL_UNIBODY_MACBOOK },
1329 static enum touchpad_model
1330 tp_get_model(struct evdev_device *device)
1332 struct model_lookup_t *lookup;
1333 uint16_t vendor = libevdev_get_id_vendor(device->evdev);
1334 uint16_t product = libevdev_get_id_product(device->evdev);
1336 for (lookup = model_lookup_table; lookup->vendor; lookup++) {
1337 if (lookup->vendor == vendor &&
1338 lookup->product_start <= product &&
1339 product <= lookup->product_end)
1340 return lookup->model;
1342 return MODEL_UNKNOWN;
1345 struct evdev_dispatch *
1346 evdev_mt_touchpad_create(struct evdev_device *device)
1348 struct tp_dispatch *tp;
1350 tp = zalloc(sizeof *tp);
1354 tp->model = tp_get_model(device);
1356 if (tp_init(tp, device) != 0) {
1357 tp_destroy(&tp->base);
1361 device->base.config.sendevents = &tp->sendevents.config;
1363 tp->sendevents.current_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
1364 tp->sendevents.config.get_modes = tp_sendevents_get_modes;
1365 tp->sendevents.config.set_mode = tp_sendevents_set_mode;
1366 tp->sendevents.config.get_mode = tp_sendevents_get_mode;
1367 tp->sendevents.config.get_default_mode = tp_sendevents_get_default_mode;
1369 evdev_init_left_handed(device, tp_change_to_left_handed);