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 */
39 tp_hysteresis(int in, int center, int margin)
41 int diff = in - center;
42 if (abs(diff) <= margin)
46 return center + diff - margin;
48 return center + diff + margin;
51 static inline struct device_coords *
52 tp_motion_history_offset(struct tp_touch *t, int offset)
55 (t->history.index - offset + TOUCHPAD_HISTORY_LENGTH) %
56 TOUCHPAD_HISTORY_LENGTH;
58 return &t->history.samples[offset_index];
62 tp_filter_motion(struct tp_dispatch *tp,
63 double *dx, double *dy,
64 double *dx_unaccel, double *dy_unaccel,
67 struct motion_params motion;
73 *dx_unaccel = motion.dx;
75 *dy_unaccel = motion.dy;
77 if (motion.dx != 0.0 || motion.dy != 0.0)
78 filter_dispatch(tp->device->pointer.filter, &motion, tp, time);
85 tp_motion_history_push(struct tp_touch *t)
87 int motion_index = (t->history.index + 1) % TOUCHPAD_HISTORY_LENGTH;
89 if (t->history.count < TOUCHPAD_HISTORY_LENGTH)
92 t->history.samples[motion_index] = t->point;
93 t->history.index = motion_index;
97 tp_motion_hysteresis(struct tp_dispatch *tp,
103 if (t->history.count == 0) {
104 t->hysteresis_center = t->point;
107 t->hysteresis_center.x,
108 tp->hysteresis_margin.x);
110 t->hysteresis_center.y,
111 tp->hysteresis_margin.y);
112 t->hysteresis_center.x = x;
113 t->hysteresis_center.y = y;
120 tp_motion_history_reset(struct tp_touch *t)
122 t->history.count = 0;
125 static inline struct tp_touch *
126 tp_current_touch(struct tp_dispatch *tp)
128 return &tp->touches[min(tp->slot, tp->ntouches - 1)];
131 static inline struct tp_touch *
132 tp_get_touch(struct tp_dispatch *tp, unsigned int slot)
134 assert(slot < tp->ntouches);
135 return &tp->touches[slot];
138 static inline unsigned int
139 tp_fake_finger_count(struct tp_dispatch *tp)
141 /* don't count BTN_TOUCH */
142 return ffs(tp->fake_touches >> 1);
146 tp_fake_finger_is_touching(struct tp_dispatch *tp)
148 return tp->fake_touches & 0x1;
152 tp_fake_finger_set(struct tp_dispatch *tp,
162 case BTN_TOOL_FINGER:
165 case BTN_TOOL_DOUBLETAP:
166 case BTN_TOOL_TRIPLETAP:
167 case BTN_TOOL_QUADTAP:
168 shift = code - BTN_TOOL_DOUBLETAP + 2;
175 tp->fake_touches |= 1 << shift;
177 tp->fake_touches &= ~(0x1 << shift);
181 tp_new_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
183 if (t->state == TOUCH_BEGIN ||
184 t->state == TOUCH_UPDATE ||
185 t->state == TOUCH_HOVERING)
188 /* we begin the touch as hovering because until BTN_TOUCH happens we
189 * don't know if it's a touch down or not. And BTN_TOUCH may happen
190 * after ABS_MT_TRACKING_ID */
191 tp_motion_history_reset(t);
193 t->has_ended = false;
194 t->state = TOUCH_HOVERING;
195 t->pinned.is_pinned = false;
197 tp->queued |= TOUCHPAD_EVENT_MOTION;
201 tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
204 t->state = TOUCH_BEGIN;
207 assert(tp->nfingers_down >= 1);
211 * End a touch, even if the touch sequence is still active.
214 tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
218 t->state = TOUCH_NONE;
230 t->palm.is_palm = false;
231 t->state = TOUCH_END;
232 t->pinned.is_pinned = false;
234 assert(tp->nfingers_down >= 1);
236 tp->queued |= TOUCHPAD_EVENT_MOTION;
240 * End the touch sequence on ABS_MT_TRACKING_ID -1 or when the BTN_TOOL_* 0 is received.
243 tp_end_sequence(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
246 tp_end_touch(tp, t, time);
250 tp_estimate_delta(int x0, int x1, int x2, int x3)
252 return (x0 + x1 - x2 - x3) / 4.0;
255 struct normalized_coords
256 tp_get_delta(struct tp_touch *t)
258 double dx, dy; /* in device coords */
259 struct normalized_coords normalized = { 0.0, 0.0 };
261 if (t->history.count < TOUCHPAD_MIN_SAMPLES)
264 dx = tp_estimate_delta(tp_motion_history_offset(t, 0)->x,
265 tp_motion_history_offset(t, 1)->x,
266 tp_motion_history_offset(t, 2)->x,
267 tp_motion_history_offset(t, 3)->x);
268 dy = tp_estimate_delta(tp_motion_history_offset(t, 0)->y,
269 tp_motion_history_offset(t, 1)->y,
270 tp_motion_history_offset(t, 2)->y,
271 tp_motion_history_offset(t, 3)->y);
272 tp_normalize_delta(t->tp, dx, dy, &normalized);
278 tp_process_absolute(struct tp_dispatch *tp,
279 const struct input_event *e,
282 struct tp_touch *t = tp_current_touch(tp);
285 case ABS_MT_POSITION_X:
286 t->point.x = e->value;
289 tp->queued |= TOUCHPAD_EVENT_MOTION;
291 case ABS_MT_POSITION_Y:
292 t->point.y = e->value;
295 tp->queued |= TOUCHPAD_EVENT_MOTION;
300 case ABS_MT_TRACKING_ID:
302 tp_new_touch(tp, t, time);
304 tp_end_sequence(tp, t, time);
309 tp_process_absolute_st(struct tp_dispatch *tp,
310 const struct input_event *e,
313 struct tp_touch *t = tp_current_touch(tp);
317 t->point.x = e->value;
320 tp->queued |= TOUCHPAD_EVENT_MOTION;
323 t->point.y = e->value;
326 tp->queued |= TOUCHPAD_EVENT_MOTION;
332 tp_process_fake_touch(struct tp_dispatch *tp,
333 const struct input_event *e,
337 unsigned int nfake_touches;
338 unsigned int i, start;
340 tp_fake_finger_set(tp, e->code, e->value != 0);
342 nfake_touches = tp_fake_finger_count(tp);
344 start = tp->has_mt ? tp->real_touches : 0;
345 for (i = start; i < tp->ntouches; i++) {
346 t = tp_get_touch(tp, i);
347 if (i < nfake_touches)
348 tp_new_touch(tp, t, time);
350 tp_end_sequence(tp, t, time);
355 tp_process_trackpoint_button(struct tp_dispatch *tp,
356 const struct input_event *e,
359 struct evdev_dispatch *dispatch;
360 struct input_event event;
362 if (!tp->buttons.trackpoint ||
363 (tp->device->tags & EVDEV_TAG_TOUCHPAD_TRACKPOINT) == 0)
366 dispatch = tp->buttons.trackpoint->dispatch;
370 switch (event.code) {
372 event.code = BTN_LEFT;
375 event.code = BTN_RIGHT;
378 event.code = BTN_MIDDLE;
384 dispatch->interface->process(dispatch,
385 tp->buttons.trackpoint,
390 tp_process_key(struct tp_dispatch *tp,
391 const struct input_event *e,
398 tp_process_button(tp, e, time);
401 case BTN_TOOL_FINGER:
402 case BTN_TOOL_DOUBLETAP:
403 case BTN_TOOL_TRIPLETAP:
404 case BTN_TOOL_QUADTAP:
405 tp_process_fake_touch(tp, e, time);
410 tp_process_trackpoint_button(tp, e, time);
416 tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t)
418 unsigned int xdist, ydist;
420 if (!t->pinned.is_pinned)
423 xdist = abs(t->point.x - t->pinned.center.x);
424 ydist = abs(t->point.y - t->pinned.center.y);
426 if (xdist * xdist + ydist * ydist >=
427 tp->buttons.motion_dist * tp->buttons.motion_dist) {
428 t->pinned.is_pinned = false;
432 /* The finger may slowly drift, adjust the center */
433 t->pinned.center.x = t->point.x + t->pinned.center.x / 2;
434 t->pinned.center.y = t->point.y + t->pinned.center.y / 2;
438 tp_pin_fingers(struct tp_dispatch *tp)
442 tp_for_each_touch(tp, t) {
443 t->pinned.is_pinned = true;
444 t->pinned.center = t->point;
449 tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
451 return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
453 !t->pinned.is_pinned &&
454 tp_button_touch_active(tp, t) &&
455 tp_edge_scroll_touch_active(tp, t);
459 tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
461 const int PALM_TIMEOUT = 200; /* ms */
462 const int DIRECTIONS = NE|E|SE|SW|W|NW;
464 /* If labelled a touch as palm, we unlabel as palm when
465 we move out of the palm edge zone within the timeout, provided
466 the direction is within 45 degrees of the horizontal.
468 if (t->palm.is_palm) {
469 if (time < t->palm.time + PALM_TIMEOUT &&
470 (t->point.x > tp->palm.left_edge && t->point.x < tp->palm.right_edge)) {
471 int dirs = vector_get_direction(t->point.x - t->palm.first.x,
472 t->point.y - t->palm.first.y);
473 if ((dirs & DIRECTIONS) && !(dirs & ~DIRECTIONS)) {
474 t->palm.is_palm = false;
480 /* palm must start in exclusion zone, it's ok to move into
481 the zone without being a palm */
482 if (t->state != TOUCH_BEGIN ||
483 (t->point.x > tp->palm.left_edge && t->point.x < tp->palm.right_edge))
486 /* don't detect palm in software button areas, it's
487 likely that legitimate touches start in the area
488 covered by the exclusion zone */
489 if (tp->buttons.is_clickpad &&
490 tp_button_is_inside_softbutton_area(tp, t))
493 t->palm.is_palm = true;
495 t->palm.first = t->point;
499 tp_unhover_touches(struct tp_dispatch *tp, uint64_t time)
502 unsigned int nfake_touches;
505 if (!tp->fake_touches && !tp->nfingers_down)
508 nfake_touches = tp_fake_finger_count(tp);
509 if (tp->nfingers_down == nfake_touches &&
510 ((tp->nfingers_down == 0 && !tp_fake_finger_is_touching(tp)) ||
511 (tp->nfingers_down > 0 && tp_fake_finger_is_touching(tp))))
514 /* if BTN_TOUCH is set and we have less fingers down than fake
515 * touches, switch each hovering touch to BEGIN
516 * until nfingers_down matches nfake_touches
518 if (tp_fake_finger_is_touching(tp) &&
519 tp->nfingers_down < nfake_touches) {
520 for (i = 0; i < (int)tp->ntouches; i++) {
521 t = tp_get_touch(tp, i);
523 if (t->state == TOUCH_HOVERING) {
524 tp_begin_touch(tp, t, time);
526 if (tp->nfingers_down >= nfake_touches)
532 /* if BTN_TOUCH is unset end all touches, we're hovering now. If we
533 * have too many touches also end some of them. This is done in
536 if (tp->nfingers_down > nfake_touches ||
537 !tp_fake_finger_is_touching(tp)) {
538 for (i = tp->ntouches - 1; i >= 0; i--) {
539 t = tp_get_touch(tp, i);
541 if (t->state == TOUCH_HOVERING)
544 tp_end_touch(tp, t, time);
546 if (tp_fake_finger_is_touching(tp) &&
547 tp->nfingers_down == nfake_touches)
554 tp_process_state(struct tp_dispatch *tp, uint64_t time)
557 struct tp_touch *first = tp_get_touch(tp, 0);
560 tp_unhover_touches(tp, time);
562 for (i = 0; i < tp->ntouches; i++) {
563 t = tp_get_touch(tp, i);
565 /* semi-mt finger postions may "jump" when nfingers changes */
566 if (tp->semi_mt && tp->nfingers_down != tp->old_nfingers_down)
567 tp_motion_history_reset(t);
569 if (i >= tp->real_touches && t->state != TOUCH_NONE) {
570 t->point = first->point;
572 t->dirty = first->dirty;
578 tp_palm_detect(tp, t, time);
580 tp_motion_hysteresis(tp, t);
581 tp_motion_history_push(t);
583 tp_unpin_finger(tp, t);
586 tp_button_handle_state(tp, time);
587 tp_edge_scroll_handle_state(tp, time);
590 * We have a physical button down event on a clickpad. To avoid
591 * spurious pointer moves by the clicking finger we pin all fingers.
592 * We unpin fingers when they move more then a certain threshold to
593 * to allow drag and drop.
595 if ((tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) &&
596 tp->buttons.is_clickpad)
599 tp_gesture_handle_state(tp, time);
603 tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
607 tp_for_each_touch(tp, t) {
612 if (t->state == TOUCH_END) {
614 t->state = TOUCH_NONE;
616 t->state = TOUCH_HOVERING;
617 } else if (t->state == TOUCH_BEGIN) {
618 t->state = TOUCH_UPDATE;
624 tp->old_nfingers_down = tp->nfingers_down;
625 tp->buttons.old_state = tp->buttons.state;
627 tp->queued = TOUCHPAD_EVENT_NONE;
631 tp_post_events(struct tp_dispatch *tp, uint64_t time)
633 int filter_motion = 0;
635 /* Only post (top) button events while suspended */
636 if (tp->device->suspended) {
637 tp_post_button_events(tp, time);
641 filter_motion |= tp_tap_handle_state(tp, time);
642 filter_motion |= tp_post_button_events(tp, time);
644 if (filter_motion || tp->sendevents.trackpoint_active) {
645 tp_edge_scroll_stop_events(tp, time);
646 tp_gesture_stop(tp, time);
650 if (tp_edge_scroll_post_events(tp, time) != 0)
653 tp_gesture_post_events(tp, time);
657 tp_handle_state(struct tp_dispatch *tp,
660 tp_process_state(tp, time);
661 tp_post_events(tp, time);
662 tp_post_process_state(tp, time);
666 tp_process(struct evdev_dispatch *dispatch,
667 struct evdev_device *device,
668 struct input_event *e,
671 struct tp_dispatch *tp =
672 (struct tp_dispatch *)dispatch;
677 tp_process_absolute(tp, e, time);
679 tp_process_absolute_st(tp, e, time);
682 tp_process_key(tp, e, time);
685 tp_handle_state(tp, time);
691 tp_remove_sendevents(struct tp_dispatch *tp)
693 libinput_timer_cancel(&tp->sendevents.trackpoint_timer);
695 if (tp->buttons.trackpoint)
696 libinput_device_remove_event_listener(
697 &tp->sendevents.trackpoint_listener);
701 tp_remove(struct evdev_dispatch *dispatch)
703 struct tp_dispatch *tp =
704 (struct tp_dispatch*)dispatch;
707 tp_remove_buttons(tp);
708 tp_remove_sendevents(tp);
709 tp_remove_edge_scroll(tp);
710 tp_remove_gesture(tp);
714 tp_destroy(struct evdev_dispatch *dispatch)
716 struct tp_dispatch *tp =
717 (struct tp_dispatch*)dispatch;
724 tp_clear_state(struct tp_dispatch *tp)
726 uint64_t now = libinput_now(tp->device->base.seat->libinput);
729 /* Unroll the touchpad state.
730 * Release buttons first. If tp is a clickpad, the button event
731 * must come before the touch up. If it isn't, the order doesn't
734 * Then cancel all timeouts on the taps, triggering the last set
737 * Then lift all touches so the touchpad is in a neutral state.
740 tp_release_all_buttons(tp, now);
741 tp_release_all_taps(tp, now);
743 tp_for_each_touch(tp, t) {
744 tp_end_sequence(tp, t, now);
747 tp_handle_state(tp, now);
751 tp_suspend(struct tp_dispatch *tp, struct evdev_device *device)
755 /* On devices with top softwarebuttons we don't actually suspend the
756 * device, to keep the "trackpoint" buttons working. tp_post_events()
757 * will only send events for the trackpoint while suspended.
759 if (tp->buttons.has_topbuttons) {
760 evdev_notify_suspended_device(device);
761 /* Enlarge topbutton area while suspended */
762 tp_init_top_softbuttons(tp, device, 1.5);
764 evdev_device_suspend(device);
769 tp_resume(struct tp_dispatch *tp, struct evdev_device *device)
771 if (tp->buttons.has_topbuttons) {
772 /* tap state-machine is offline while suspended, reset state */
774 /* restore original topbutton area size */
775 tp_init_top_softbuttons(tp, device, 1.0);
776 evdev_notify_resumed_device(device);
778 evdev_device_resume(device);
783 tp_trackpoint_timeout(uint64_t now, void *data)
785 struct tp_dispatch *tp = data;
787 tp_tap_resume(tp, now);
788 tp->sendevents.trackpoint_active = false;
792 tp_trackpoint_event(uint64_t time, struct libinput_event *event, void *data)
794 struct tp_dispatch *tp = data;
796 /* Buttons do not count as trackpad activity, as people may use
797 the trackpoint buttons in combination with the touchpad. */
798 if (event->type == LIBINPUT_EVENT_POINTER_BUTTON)
801 if (!tp->sendevents.trackpoint_active) {
802 tp_edge_scroll_stop_events(tp, time);
803 tp_gesture_stop(tp, time);
804 tp_tap_suspend(tp, time);
805 tp->sendevents.trackpoint_active = true;
808 libinput_timer_set(&tp->sendevents.trackpoint_timer,
809 time + DEFAULT_TRACKPOINT_ACTIVITY_TIMEOUT);
813 tp_device_added(struct evdev_device *device,
814 struct evdev_device *added_device)
816 struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch;
818 if (tp->buttons.trackpoint == NULL &&
819 (added_device->tags & EVDEV_TAG_TRACKPOINT)) {
820 /* Don't send any pending releases to the new trackpoint */
821 tp->buttons.active_is_topbutton = false;
822 tp->buttons.trackpoint = added_device;
823 libinput_device_add_event_listener(&added_device->base,
824 &tp->sendevents.trackpoint_listener,
825 tp_trackpoint_event, tp);
828 if (tp->sendevents.current_mode !=
829 LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
832 if (added_device->tags & EVDEV_TAG_EXTERNAL_MOUSE)
833 tp_suspend(tp, device);
837 tp_device_removed(struct evdev_device *device,
838 struct evdev_device *removed_device)
840 struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch;
841 struct libinput_device *dev;
843 if (removed_device == tp->buttons.trackpoint) {
844 /* Clear any pending releases for the trackpoint */
845 if (tp->buttons.active && tp->buttons.active_is_topbutton) {
846 tp->buttons.active = 0;
847 tp->buttons.active_is_topbutton = false;
849 libinput_device_remove_event_listener(
850 &tp->sendevents.trackpoint_listener);
851 tp->buttons.trackpoint = NULL;
854 if (tp->sendevents.current_mode !=
855 LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
858 list_for_each(dev, &device->base.seat->devices_list, link) {
859 struct evdev_device *d = (struct evdev_device*)dev;
860 if (d != removed_device &&
861 (d->tags & EVDEV_TAG_EXTERNAL_MOUSE)) {
866 tp_resume(tp, device);
870 tp_tag_device(struct evdev_device *device,
871 struct udev_device *udev_device)
875 /* simple approach: touchpads on USB or Bluetooth are considered
876 * external, anything else is internal. Exception is Apple -
877 * internal touchpads are connected over USB and it doesn't have
878 * external USB touchpads anyway.
880 bustype = libevdev_get_id_bustype(device->evdev);
881 if (bustype == BUS_USB) {
882 if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_APPLE)
883 device->tags |= EVDEV_TAG_INTERNAL_TOUCHPAD;
884 } else if (bustype != BUS_BLUETOOTH)
885 device->tags |= EVDEV_TAG_INTERNAL_TOUCHPAD;
887 if (udev_device_get_property_value(udev_device,
888 "TOUCHPAD_HAS_TRACKPOINT_BUTTONS"))
889 device->tags |= EVDEV_TAG_TOUCHPAD_TRACKPOINT;
892 static struct evdev_dispatch_interface tp_interface = {
898 tp_device_removed, /* device_suspended, treat as remove */
899 tp_device_added, /* device_resumed, treat as add */
904 tp_init_touch(struct tp_dispatch *tp,
912 tp_init_slots(struct tp_dispatch *tp,
913 struct evdev_device *device)
915 const struct input_absinfo *absinfo;
920 { BTN_TOOL_QUINTTAP, 5 },
921 { BTN_TOOL_QUADTAP, 4 },
922 { BTN_TOOL_TRIPLETAP, 3 },
923 { BTN_TOOL_DOUBLETAP, 2 },
926 unsigned int i, n_btn_tool_touches = 1;
928 absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_SLOT);
930 tp->real_touches = absinfo->maximum + 1;
931 tp->slot = absinfo->value;
934 tp->real_touches = 1;
939 tp->semi_mt = libevdev_has_property(device->evdev, INPUT_PROP_SEMI_MT);
941 ARRAY_FOR_EACH(max_touches, m) {
942 if (libevdev_has_event_code(device->evdev,
945 n_btn_tool_touches = m->ntouches;
950 tp->ntouches = max(tp->real_touches, n_btn_tool_touches);
951 tp->touches = calloc(tp->ntouches, sizeof(struct tp_touch));
955 for (i = 0; i < tp->ntouches; i++)
956 tp_init_touch(tp, &tp->touches[i]);
962 tp_init_accel(struct tp_dispatch *tp, double diagonal)
966 res_x = tp->device->abs.absinfo_x->resolution;
967 res_y = tp->device->abs.absinfo_y->resolution;
970 * Not all touchpads report the same amount of units/mm (resolution).
971 * Normalize motion events to the default mouse DPI as base
972 * (unaccelerated) speed. This also evens out any differences in x
973 * and y resolution, so that a circle on the
974 * touchpad does not turn into an elipse on the screen.
976 if (res_x > 1 && res_y > 1) {
977 tp->accel.x_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_x;
978 tp->accel.y_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_y;
981 * For touchpads where the driver does not provide resolution, fall
982 * back to scaling motion events based on the diagonal size in units.
984 tp->accel.x_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
985 tp->accel.y_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
988 if (evdev_device_init_pointer_acceleration(
990 touchpad_accel_profile_linear) == -1)
997 tp_scroll_config_scroll_method_get_methods(struct libinput_device *device)
999 struct evdev_device *evdev = (struct evdev_device*)device;
1000 struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
1001 uint32_t methods = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
1003 if (tp->ntouches >= 2)
1004 methods |= LIBINPUT_CONFIG_SCROLL_2FG;
1006 if (!tp->buttons.is_clickpad)
1007 methods |= LIBINPUT_CONFIG_SCROLL_EDGE;
1012 static enum libinput_config_status
1013 tp_scroll_config_scroll_method_set_method(struct libinput_device *device,
1014 enum libinput_config_scroll_method method)
1016 struct evdev_device *evdev = (struct evdev_device*)device;
1017 struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
1018 uint64_t time = libinput_now(device->seat->libinput);
1020 if (method == tp->scroll.method)
1021 return LIBINPUT_CONFIG_STATUS_SUCCESS;
1023 tp_edge_scroll_stop_events(tp, time);
1024 tp_gesture_stop_twofinger_scroll(tp, time);
1026 tp->scroll.method = method;
1028 return LIBINPUT_CONFIG_STATUS_SUCCESS;
1031 static enum libinput_config_scroll_method
1032 tp_scroll_config_scroll_method_get_method(struct libinput_device *device)
1034 struct evdev_device *evdev = (struct evdev_device*)device;
1035 struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
1037 return tp->scroll.method;
1040 static enum libinput_config_scroll_method
1041 tp_scroll_get_default_method(struct tp_dispatch *tp)
1043 if (tp->ntouches >= 2)
1044 return LIBINPUT_CONFIG_SCROLL_2FG;
1046 return LIBINPUT_CONFIG_SCROLL_EDGE;
1049 static enum libinput_config_scroll_method
1050 tp_scroll_config_scroll_method_get_default_method(struct libinput_device *device)
1052 struct evdev_device *evdev = (struct evdev_device*)device;
1053 struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
1055 return tp_scroll_get_default_method(tp);
1059 tp_init_scroll(struct tp_dispatch *tp, struct evdev_device *device)
1061 if (tp_edge_scroll_init(tp, device) != 0)
1064 evdev_init_natural_scroll(device);
1066 tp->scroll.config_method.get_methods = tp_scroll_config_scroll_method_get_methods;
1067 tp->scroll.config_method.set_method = tp_scroll_config_scroll_method_set_method;
1068 tp->scroll.config_method.get_method = tp_scroll_config_scroll_method_get_method;
1069 tp->scroll.config_method.get_default_method = tp_scroll_config_scroll_method_get_default_method;
1070 tp->scroll.method = tp_scroll_get_default_method(tp);
1071 tp->device->base.config.scroll_method = &tp->scroll.config_method;
1073 /* In mm for touchpads with valid resolution, see tp_init_accel() */
1074 tp->device->scroll.threshold = 5.0;
1080 tp_init_palmdetect(struct tp_dispatch *tp,
1081 struct evdev_device *device)
1085 tp->palm.right_edge = INT_MAX;
1086 tp->palm.left_edge = INT_MIN;
1088 width = abs(device->abs.absinfo_x->maximum -
1089 device->abs.absinfo_x->minimum);
1091 /* Apple touchpads are always big enough to warrant palm detection */
1092 if (evdev_device_get_id_vendor(device) != VENDOR_ID_APPLE) {
1093 /* We don't know how big the touchpad is */
1094 if (device->abs.absinfo_x->resolution == 1)
1097 /* Enable palm detection on touchpads >= 80 mm. Anything smaller
1098 probably won't need it, until we find out it does */
1099 if (width/device->abs.absinfo_x->resolution < 80)
1103 /* palm edges are 5% of the width on each side */
1104 tp->palm.right_edge = device->abs.absinfo_x->maximum - width * 0.05;
1105 tp->palm.left_edge = device->abs.absinfo_x->minimum + width * 0.05;
1111 tp_init_sendevents(struct tp_dispatch *tp,
1112 struct evdev_device *device)
1114 libinput_timer_init(&tp->sendevents.trackpoint_timer,
1115 tp->device->base.seat->libinput,
1116 tp_trackpoint_timeout, tp);
1121 tp_fix_resolution(struct tp_dispatch *tp, struct evdev_device *device)
1123 struct libinput *libinput = device->base.seat->libinput;
1125 unsigned int resx, resy;
1127 prop = udev_device_get_property_value(device->udev_device,
1128 "TOUCHPAD_RESOLUTION");
1132 if (parse_touchpad_resolution_property(prop, &resx, &resy) == -1) {
1134 "Touchpad resolution property set for '%s', but invalid.\n",
1139 if (evdev_fix_abs_resolution(device,
1140 tp->has_mt ? ABS_MT_POSITION_X : ABS_X,
1141 tp->has_mt ? ABS_MT_POSITION_Y : ABS_Y,
1143 device->abs.fake_resolution = 0;
1147 tp_init(struct tp_dispatch *tp,
1148 struct evdev_device *device)
1153 tp->base.interface = &tp_interface;
1154 tp->device = device;
1156 if (tp_init_slots(tp, device) != 0)
1159 tp_fix_resolution(tp, device);
1161 width = abs(device->abs.absinfo_x->maximum -
1162 device->abs.absinfo_x->minimum);
1163 height = abs(device->abs.absinfo_y->maximum -
1164 device->abs.absinfo_y->minimum);
1165 diagonal = sqrt(width*width + height*height);
1167 tp->hysteresis_margin.x =
1168 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
1169 tp->hysteresis_margin.y =
1170 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
1172 if (tp_init_accel(tp, diagonal) != 0)
1175 if (tp_init_tap(tp) != 0)
1178 if (tp_init_buttons(tp, device) != 0)
1181 if (tp_init_palmdetect(tp, device) != 0)
1184 if (tp_init_sendevents(tp, device) != 0)
1187 if (tp_init_scroll(tp, device) != 0)
1190 if (tp_init_gesture(tp) != 0)
1193 device->seat_caps |= EVDEV_DEVICE_POINTER;
1199 tp_sendevents_get_modes(struct libinput_device *device)
1201 struct evdev_device *evdev = (struct evdev_device*)device;
1202 uint32_t modes = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
1204 if (evdev->tags & EVDEV_TAG_INTERNAL_TOUCHPAD)
1205 modes |= LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
1211 tp_suspend_conditional(struct tp_dispatch *tp,
1212 struct evdev_device *device)
1214 struct libinput_device *dev;
1216 list_for_each(dev, &device->base.seat->devices_list, link) {
1217 struct evdev_device *d = (struct evdev_device*)dev;
1218 if (d->tags & EVDEV_TAG_EXTERNAL_MOUSE) {
1219 tp_suspend(tp, device);
1225 static enum libinput_config_status
1226 tp_sendevents_set_mode(struct libinput_device *device,
1227 enum libinput_config_send_events_mode mode)
1229 struct evdev_device *evdev = (struct evdev_device*)device;
1230 struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
1232 /* DISABLED overrides any DISABLED_ON_ */
1233 if ((mode & LIBINPUT_CONFIG_SEND_EVENTS_DISABLED) &&
1234 (mode & LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE))
1235 mode &= ~LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
1237 if (mode == tp->sendevents.current_mode)
1238 return LIBINPUT_CONFIG_STATUS_SUCCESS;
1241 case LIBINPUT_CONFIG_SEND_EVENTS_ENABLED:
1242 tp_resume(tp, evdev);
1244 case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED:
1245 tp_suspend(tp, evdev);
1247 case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE:
1248 tp_suspend_conditional(tp, evdev);
1251 return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
1254 tp->sendevents.current_mode = mode;
1256 return LIBINPUT_CONFIG_STATUS_SUCCESS;
1259 static enum libinput_config_send_events_mode
1260 tp_sendevents_get_mode(struct libinput_device *device)
1262 struct evdev_device *evdev = (struct evdev_device*)device;
1263 struct tp_dispatch *dispatch = (struct tp_dispatch*)evdev->dispatch;
1265 return dispatch->sendevents.current_mode;
1268 static enum libinput_config_send_events_mode
1269 tp_sendevents_get_default_mode(struct libinput_device *device)
1271 return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
1275 tp_change_to_left_handed(struct evdev_device *device)
1277 struct tp_dispatch *tp = (struct tp_dispatch *)device->dispatch;
1279 if (device->left_handed.want_enabled == device->left_handed.enabled)
1282 if (tp->buttons.state & 0x3) /* BTN_LEFT|BTN_RIGHT */
1285 /* tapping and clickfinger aren't affected by left-handed config,
1286 * so checking physical buttons is enough */
1288 device->left_handed.enabled = device->left_handed.want_enabled;
1291 struct model_lookup_t {
1293 uint16_t product_start;
1294 uint16_t product_end;
1295 enum touchpad_model model;
1298 static struct model_lookup_t model_lookup_table[] = {
1299 { 0x0002, 0x0007, 0x0007, MODEL_SYNAPTICS },
1300 { 0x0002, 0x0008, 0x0008, MODEL_ALPS },
1301 { 0x0002, 0x000e, 0x000e, MODEL_ELANTECH },
1302 { 0x05ac, 0, 0x0222, MODEL_APPLETOUCH },
1303 { 0x05ac, 0x0223, 0x0228, MODEL_UNIBODY_MACBOOK },
1304 { 0x05ac, 0x0229, 0x022b, MODEL_APPLETOUCH },
1305 { 0x05ac, 0x022c, 0xffff, MODEL_UNIBODY_MACBOOK },
1309 static enum touchpad_model
1310 tp_get_model(struct evdev_device *device)
1312 struct model_lookup_t *lookup;
1313 uint16_t vendor = libevdev_get_id_vendor(device->evdev);
1314 uint16_t product = libevdev_get_id_product(device->evdev);
1316 for (lookup = model_lookup_table; lookup->vendor; lookup++) {
1317 if (lookup->vendor == vendor &&
1318 lookup->product_start <= product &&
1319 product <= lookup->product_end)
1320 return lookup->model;
1322 return MODEL_UNKNOWN;
1325 struct evdev_dispatch *
1326 evdev_mt_touchpad_create(struct evdev_device *device)
1328 struct tp_dispatch *tp;
1330 tp = zalloc(sizeof *tp);
1334 tp->model = tp_get_model(device);
1336 if (tp_init(tp, device) != 0) {
1337 tp_destroy(&tp->base);
1341 device->base.config.sendevents = &tp->sendevents.config;
1343 tp->sendevents.current_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
1344 tp->sendevents.config.get_modes = tp_sendevents_get_modes;
1345 tp->sendevents.config.set_mode = tp_sendevents_set_mode;
1346 tp->sendevents.config.get_mode = tp_sendevents_get_mode;
1347 tp->sendevents.config.get_default_mode = tp_sendevents_get_default_mode;
1349 evdev_init_left_handed(device, tp_change_to_left_handed);