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 #define DEFAULT_ACCEL_NUMERATOR 1200.0
33 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
36 tp_hysteresis(int in, int center, int margin)
38 int diff = in - center;
39 if (abs(diff) <= margin)
43 return center + diff - margin;
45 return center + diff + margin;
48 static inline struct tp_motion *
49 tp_motion_history_offset(struct tp_touch *t, int offset)
52 (t->history.index - offset + TOUCHPAD_HISTORY_LENGTH) %
53 TOUCHPAD_HISTORY_LENGTH;
55 return &t->history.samples[offset_index];
59 tp_filter_motion(struct tp_dispatch *tp,
60 double *dx, double *dy, uint64_t time)
62 struct motion_params motion;
64 motion.dx = *dx * tp->accel.x_scale_coeff;
65 motion.dy = *dy * tp->accel.y_scale_coeff;
67 if (motion.dx != 0.0 || motion.dy != 0.0)
68 filter_dispatch(tp->filter, &motion, 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].x = t->x;
83 t->history.samples[motion_index].y = t->y;
84 t->history.index = motion_index;
88 tp_motion_hysteresis(struct tp_dispatch *tp,
94 if (t->history.count == 0) {
95 t->hysteresis.center_x = t->x;
96 t->hysteresis.center_y = t->y;
99 t->hysteresis.center_x,
100 tp->hysteresis.margin_x);
102 t->hysteresis.center_y,
103 tp->hysteresis.margin_y);
104 t->hysteresis.center_x = x;
105 t->hysteresis.center_y = y;
112 tp_motion_history_reset(struct tp_touch *t)
114 t->history.count = 0;
117 static inline struct tp_touch *
118 tp_current_touch(struct tp_dispatch *tp)
120 return &tp->touches[min(tp->slot, tp->ntouches - 1)];
123 static inline struct tp_touch *
124 tp_get_touch(struct tp_dispatch *tp, unsigned int slot)
126 assert(slot < tp->ntouches);
127 return &tp->touches[slot];
131 tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
133 if (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE)
136 tp_motion_history_reset(t);
138 t->state = TOUCH_BEGIN;
139 t->pinned.is_pinned = false;
142 assert(tp->nfingers_down >= 1);
143 tp->queued |= TOUCHPAD_EVENT_MOTION;
147 tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
149 if (t->state == TOUCH_END || t->state == TOUCH_NONE)
153 t->is_pointer = false;
154 t->palm.is_palm = false;
155 t->state = TOUCH_END;
156 t->pinned.is_pinned = false;
158 assert(tp->nfingers_down >= 1);
160 tp->queued |= TOUCHPAD_EVENT_MOTION;
164 tp_estimate_delta(int x0, int x1, int x2, int x3)
166 return (x0 + x1 - x2 - x3) / 4.0;
170 tp_get_delta(struct tp_touch *t, double *dx, double *dy)
172 if (t->history.count < 4) {
178 *dx = tp_estimate_delta(tp_motion_history_offset(t, 0)->x,
179 tp_motion_history_offset(t, 1)->x,
180 tp_motion_history_offset(t, 2)->x,
181 tp_motion_history_offset(t, 3)->x);
182 *dy = tp_estimate_delta(tp_motion_history_offset(t, 0)->y,
183 tp_motion_history_offset(t, 1)->y,
184 tp_motion_history_offset(t, 2)->y,
185 tp_motion_history_offset(t, 3)->y);
189 tp_process_absolute(struct tp_dispatch *tp,
190 const struct input_event *e,
193 struct tp_touch *t = tp_current_touch(tp);
196 case ABS_MT_POSITION_X:
200 tp->queued |= TOUCHPAD_EVENT_MOTION;
202 case ABS_MT_POSITION_Y:
206 tp->queued |= TOUCHPAD_EVENT_MOTION;
211 case ABS_MT_TRACKING_ID:
213 tp_begin_touch(tp, t, time);
215 tp_end_touch(tp, t, time);
220 tp_process_absolute_st(struct tp_dispatch *tp,
221 const struct input_event *e,
224 struct tp_touch *t = tp_current_touch(tp);
231 tp->queued |= TOUCHPAD_EVENT_MOTION;
237 tp->queued |= TOUCHPAD_EVENT_MOTION;
243 tp_process_fake_touch(struct tp_dispatch *tp,
244 const struct input_event *e,
248 unsigned int fake_touches;
249 unsigned int nfake_touches;
250 unsigned int i, start;
253 if (e->code != BTN_TOUCH &&
254 (e->code < BTN_TOOL_DOUBLETAP || e->code > BTN_TOOL_QUADTAP))
257 shift = e->code == BTN_TOUCH ? 0 : (e->code - BTN_TOOL_DOUBLETAP + 1);
260 tp->fake_touches |= 1 << shift;
262 tp->fake_touches &= ~(0x1 << shift);
264 fake_touches = tp->fake_touches;
266 while (fake_touches) {
271 /* For single touch tps we use BTN_TOUCH for begin / end of touch 0 */
272 start = tp->has_mt ? tp->real_touches : 0;
273 for (i = start; i < tp->ntouches; i++) {
274 t = tp_get_touch(tp, i);
275 if (i < nfake_touches)
276 tp_begin_touch(tp, t, time);
278 tp_end_touch(tp, t, time);
281 /* On mt the actual touch info may arrive after BTN_TOOL_FOO */
282 assert(tp->has_mt || tp->nfingers_down == nfake_touches);
286 tp_process_key(struct tp_dispatch *tp,
287 const struct input_event *e,
294 tp_process_button(tp, e, time);
297 case BTN_TOOL_DOUBLETAP:
298 case BTN_TOOL_TRIPLETAP:
299 case BTN_TOOL_QUADTAP:
300 tp_process_fake_touch(tp, e, time);
306 tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t)
308 unsigned int xdist, ydist;
310 if (!t->pinned.is_pinned)
313 xdist = abs(t->x - t->pinned.center_x);
314 ydist = abs(t->y - t->pinned.center_y);
316 if (xdist * xdist + ydist * ydist >=
317 tp->buttons.motion_dist * tp->buttons.motion_dist) {
318 t->pinned.is_pinned = false;
319 tp_set_pointer(tp, t);
324 tp_pin_fingers(struct tp_dispatch *tp)
328 tp_for_each_touch(tp, t) {
329 t->is_pointer = false;
330 t->pinned.is_pinned = true;
331 t->pinned.center_x = t->x;
332 t->pinned.center_y = t->y;
337 tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
339 return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
341 !t->pinned.is_pinned && tp_button_touch_active(tp, t);
345 tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t)
347 struct tp_touch *tmp = NULL;
349 /* Only set the touch as pointer if we don't have one yet */
350 tp_for_each_touch(tp, tmp) {
355 if (tp_touch_active(tp, t))
356 t->is_pointer = true;
360 tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
362 const int PALM_TIMEOUT = 200; /* ms */
363 const int DIRECTIONS = NE|E|SE|SW|W|NW;
365 /* If labelled a touch as palm, we unlabel as palm when
366 we move out of the palm edge zone within the timeout, provided
367 the direction is within 45 degrees of the horizontal.
369 if (t->palm.is_palm) {
370 if (time < t->palm.time + PALM_TIMEOUT &&
371 (t->x > tp->palm.left_edge && t->x < tp->palm.right_edge)) {
372 int dirs = vector_get_direction(t->x - t->palm.x, t->y - t->palm.y);
373 if ((dirs & DIRECTIONS) && !(dirs & ~DIRECTIONS)) {
374 t->palm.is_palm = false;
375 tp_set_pointer(tp, t);
381 /* palm must start in exclusion zone, it's ok to move into
382 the zone without being a palm */
383 if (t->state != TOUCH_BEGIN ||
384 (t->x > tp->palm.left_edge && t->x < tp->palm.right_edge))
387 /* don't detect palm in software button areas, it's
388 likely that legitimate touches start in the area
389 covered by the exclusion zone */
390 if (tp->buttons.is_clickpad &&
391 tp_button_is_inside_softbutton_area(tp, t))
394 t->palm.is_palm = true;
401 tp_process_state(struct tp_dispatch *tp, uint64_t time)
404 struct tp_touch *first = tp_get_touch(tp, 0);
407 for (i = 0; i < tp->ntouches; i++) {
408 t = tp_get_touch(tp, i);
410 /* semi-mt finger postions may "jump" when nfingers changes */
411 if (tp->semi_mt && tp->nfingers_down != tp->old_nfingers_down)
412 tp_motion_history_reset(t);
414 if (i >= tp->real_touches && t->state != TOUCH_NONE) {
418 t->dirty = first->dirty;
424 tp_palm_detect(tp, t, time);
426 tp_motion_hysteresis(tp, t);
427 tp_motion_history_push(t);
429 tp_unpin_finger(tp, t);
432 tp_button_handle_state(tp, time);
435 * We have a physical button down event on a clickpad. To avoid
436 * spurious pointer moves by the clicking finger we pin all fingers.
437 * We unpin fingers when they move more then a certain threshold to
438 * to allow drag and drop.
440 if ((tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) &&
441 tp->buttons.is_clickpad)
446 tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
450 tp_for_each_touch(tp, t) {
454 if (t->state == TOUCH_END)
455 t->state = TOUCH_NONE;
456 else if (t->state == TOUCH_BEGIN)
457 t->state = TOUCH_UPDATE;
462 tp->old_nfingers_down = tp->nfingers_down;
463 tp->buttons.old_state = tp->buttons.state;
465 tp->queued = TOUCHPAD_EVENT_NONE;
469 tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time)
473 double dx = 0, dy =0;
476 tp_for_each_touch(tp, t) {
477 if (tp_touch_active(tp, t) && t->dirty) {
479 tp_get_delta(t, &tmpx, &tmpy);
484 /* Stop spurious MOTION events at the end of scrolling */
485 t->is_pointer = false;
494 tp_filter_motion(tp, &dx, &dy, time);
495 evdev_post_scroll(tp->device, time, dx, dy);
499 tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
502 int nfingers_down = 0;
504 /* Only count active touches for 2 finger scrolling */
505 tp_for_each_touch(tp, t) {
506 if (tp_touch_active(tp, t))
510 if (nfingers_down != 2) {
511 evdev_stop_scroll(tp->device, time);
515 tp_post_twofinger_scroll(tp, time);
520 tp_post_events(struct tp_dispatch *tp, uint64_t time)
522 struct tp_touch *t = tp_current_touch(tp);
526 /* Only post (top) button events while suspended */
527 if (tp->device->suspended) {
528 tp_post_button_events(tp, time);
532 consumed |= tp_tap_handle_state(tp, time);
533 consumed |= tp_post_button_events(tp, time);
536 evdev_stop_scroll(tp->device, time);
540 if (tp_post_scroll_events(tp, time) != 0)
543 if (!t->is_pointer) {
544 tp_for_each_touch(tp, t) {
550 if (!t->is_pointer ||
552 t->history.count < TOUCHPAD_MIN_SAMPLES)
555 tp_get_delta(t, &dx, &dy);
556 tp_filter_motion(tp, &dx, &dy, time);
558 if (dx != 0.0 || dy != 0.0)
559 pointer_notify_motion(&tp->device->base, time, dx, dy);
563 tp_handle_state(struct tp_dispatch *tp,
566 tp_process_state(tp, time);
567 tp_post_events(tp, time);
568 tp_post_process_state(tp, time);
572 tp_process(struct evdev_dispatch *dispatch,
573 struct evdev_device *device,
574 struct input_event *e,
577 struct tp_dispatch *tp =
578 (struct tp_dispatch *)dispatch;
583 tp_process_absolute(tp, e, time);
585 tp_process_absolute_st(tp, e, time);
588 tp_process_key(tp, e, time);
591 tp_handle_state(tp, time);
597 tp_destroy(struct evdev_dispatch *dispatch)
599 struct tp_dispatch *tp =
600 (struct tp_dispatch*)dispatch;
603 tp_destroy_buttons(tp);
605 filter_destroy(tp->filter);
611 tp_clear_state(struct tp_dispatch *tp, struct evdev_device *device)
613 uint64_t now = libinput_now(tp->device->base.seat->libinput);
616 /* Unroll the touchpad state.
617 * Release buttons first. If tp is a clickpad, the button event
618 * must come before the touch up. If it isn't, the order doesn't
621 * Then cancel all timeouts on the taps, triggering the last set
624 * Then lift all touches so the touchpad is in a neutral state.
627 tp_release_all_buttons(tp, now);
628 tp_release_all_taps(tp, now);
630 tp_for_each_touch(tp, t) {
631 tp_end_touch(tp, t, now);
634 tp_handle_state(tp, now);
638 tp_suspend(struct tp_dispatch *tp, struct evdev_device *device)
640 tp_clear_state(tp, device);
642 /* On devices with top softwarebuttons we don't actually suspend the
643 * device, to keep the "trackpoint" buttons working. tp_post_events()
644 * will only send events for the trackpoint while suspended.
646 if (tp->buttons.has_topbuttons) {
647 evdev_notify_suspended_device(device);
648 /* Enlarge topbutton area while suspended */
649 tp_init_softbuttons(tp, device, 1.5);
651 evdev_device_suspend(device);
656 tp_resume(struct tp_dispatch *tp, struct evdev_device *device)
658 if (tp->buttons.has_topbuttons) {
659 /* tap state-machine is offline while suspended, reset state */
660 tp_clear_state(tp, device);
661 /* restore original topbutton area size */
662 tp_init_softbuttons(tp, device, 1.0);
663 evdev_notify_resumed_device(device);
665 evdev_device_resume(device);
670 tp_device_added(struct evdev_device *device,
671 struct evdev_device *added_device)
673 struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch;
675 if (tp->buttons.trackpoint == NULL &&
676 (added_device->tags & EVDEV_TAG_TRACKPOINT)) {
677 /* Don't send any pending releases to the new trackpoint */
678 tp->buttons.active_is_topbutton = false;
679 tp->buttons.trackpoint = added_device;
682 if (tp->sendevents.current_mode !=
683 LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
686 if (added_device->tags & EVDEV_TAG_EXTERNAL_MOUSE)
687 tp_suspend(tp, device);
691 tp_device_removed(struct evdev_device *device,
692 struct evdev_device *removed_device)
694 struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch;
695 struct libinput_device *dev;
697 if (removed_device == tp->buttons.trackpoint) {
698 /* Clear any pending releases for the trackpoint */
699 if (tp->buttons.active && tp->buttons.active_is_topbutton) {
700 tp->buttons.active = 0;
701 tp->buttons.active_is_topbutton = false;
703 tp->buttons.trackpoint = NULL;
706 if (tp->sendevents.current_mode !=
707 LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
710 list_for_each(dev, &device->base.seat->devices_list, link) {
711 struct evdev_device *d = (struct evdev_device*)dev;
712 if (d != removed_device &&
713 (d->tags & EVDEV_TAG_EXTERNAL_MOUSE)) {
718 tp_resume(tp, device);
722 tp_tag_device(struct evdev_device *device,
723 struct udev_device *udev_device)
727 /* simple approach: touchpads on USB or Bluetooth are considered
728 * external, anything else is internal. Exception is Apple -
729 * internal touchpads are connected over USB and it doesn't have
730 * external USB touchpads anyway.
732 bustype = libevdev_get_id_bustype(device->evdev);
733 if (bustype == BUS_USB) {
734 if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_APPLE)
735 device->tags |= EVDEV_TAG_INTERNAL_TOUCHPAD;
736 } else if (bustype != BUS_BLUETOOTH)
737 device->tags |= EVDEV_TAG_INTERNAL_TOUCHPAD;
740 static struct evdev_dispatch_interface tp_interface = {
745 tp_device_removed, /* device_suspended, treat as remove */
746 tp_device_added, /* device_resumed, treat as add */
751 tp_init_touch(struct tp_dispatch *tp,
758 tp_init_slots(struct tp_dispatch *tp,
759 struct evdev_device *device)
761 const struct input_absinfo *absinfo;
766 { BTN_TOOL_QUINTTAP, 5 },
767 { BTN_TOOL_QUADTAP, 4 },
768 { BTN_TOOL_TRIPLETAP, 3 },
769 { BTN_TOOL_DOUBLETAP, 2 },
772 unsigned int i, n_btn_tool_touches = 1;
774 absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_SLOT);
776 tp->real_touches = absinfo->maximum + 1;
777 tp->slot = absinfo->value;
780 tp->real_touches = 1;
785 tp->semi_mt = libevdev_has_property(device->evdev, INPUT_PROP_SEMI_MT);
787 ARRAY_FOR_EACH(max_touches, m) {
788 if (libevdev_has_event_code(device->evdev,
791 n_btn_tool_touches = m->ntouches;
796 tp->ntouches = max(tp->real_touches, n_btn_tool_touches);
797 tp->touches = calloc(tp->ntouches, sizeof(struct tp_touch));
801 for (i = 0; i < tp->ntouches; i++)
802 tp_init_touch(tp, &tp->touches[i]);
808 tp_init_accel(struct tp_dispatch *tp, double diagonal)
810 struct motion_filter *accel;
814 res_x = libevdev_get_abs_resolution(tp->device->evdev,
816 res_y = libevdev_get_abs_resolution(tp->device->evdev,
819 res_x = libevdev_get_abs_resolution(tp->device->evdev,
821 res_y = libevdev_get_abs_resolution(tp->device->evdev,
826 * Not all touchpads report the same amount of units/mm (resolution).
827 * Normalize motion events to a resolution of 15.74 units/mm
828 * (== 400 dpi) as base (unaccelerated) speed. This also evens out any
829 * differences in x and y resolution, so that a circle on the
830 * touchpad does not turn into an elipse on the screen.
832 * We pick 400dpi as thats one of the many default resolutions
833 * for USB mice, so we end up with a similar base speed on the device.
835 if (res_x > 1 && res_y > 1) {
836 tp->accel.x_scale_coeff = (400/25.4) / res_x;
837 tp->accel.y_scale_coeff = (400/25.4) / res_y;
840 * For touchpads where the driver does not provide resolution, fall
841 * back to scaling motion events based on the diagonal size in units.
843 tp->accel.x_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
844 tp->accel.y_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
847 accel = create_pointer_accelator_filter(
848 pointer_accel_profile_linear);
858 tp_init_palmdetect(struct tp_dispatch *tp,
859 struct evdev_device *device)
863 tp->palm.right_edge = INT_MAX;
864 tp->palm.left_edge = INT_MIN;
866 width = abs(device->abs.absinfo_x->maximum -
867 device->abs.absinfo_x->minimum);
869 /* Apple touchpads are always big enough to warrant palm detection */
870 if (evdev_device_get_id_vendor(device) != VENDOR_ID_APPLE) {
871 /* We don't know how big the touchpad is */
872 if (device->abs.absinfo_x->resolution == 1)
875 /* Enable palm detection on touchpads >= 80 mm. Anything smaller
876 probably won't need it, until we find out it does */
877 if (width/device->abs.absinfo_x->resolution < 80)
881 /* palm edges are 5% of the width on each side */
882 tp->palm.right_edge = device->abs.absinfo_x->maximum - width * 0.05;
883 tp->palm.left_edge = device->abs.absinfo_x->minimum + width * 0.05;
889 tp_init(struct tp_dispatch *tp,
890 struct evdev_device *device)
895 tp->base.interface = &tp_interface;
898 if (tp_init_slots(tp, device) != 0)
901 width = abs(device->abs.absinfo_x->maximum -
902 device->abs.absinfo_x->minimum);
903 height = abs(device->abs.absinfo_y->maximum -
904 device->abs.absinfo_y->minimum);
905 diagonal = sqrt(width*width + height*height);
907 tp->hysteresis.margin_x =
908 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
909 tp->hysteresis.margin_y =
910 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
912 if (tp_init_accel(tp, diagonal) != 0)
915 if (tp_init_tap(tp) != 0)
918 if (tp_init_buttons(tp, device) != 0)
921 if (tp_init_palmdetect(tp, device) != 0)
924 device->seat_caps |= EVDEV_DEVICE_POINTER;
930 tp_sendevents_get_modes(struct libinput_device *device)
932 struct evdev_device *evdev = (struct evdev_device*)device;
933 uint32_t modes = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED |
934 LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
936 if (evdev->tags & EVDEV_TAG_INTERNAL_TOUCHPAD)
937 modes |= LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
943 tp_suspend_conditional(struct tp_dispatch *tp,
944 struct evdev_device *device)
946 struct libinput_device *dev;
948 list_for_each(dev, &device->base.seat->devices_list, link) {
949 struct evdev_device *d = (struct evdev_device*)dev;
950 if (d->tags & EVDEV_TAG_EXTERNAL_MOUSE) {
951 tp_suspend(tp, device);
957 static enum libinput_config_status
958 tp_sendevents_set_mode(struct libinput_device *device,
959 enum libinput_config_send_events_mode mode)
961 struct evdev_device *evdev = (struct evdev_device*)device;
962 struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
964 if (mode == tp->sendevents.current_mode)
965 return LIBINPUT_CONFIG_STATUS_SUCCESS;
968 case LIBINPUT_CONFIG_SEND_EVENTS_ENABLED:
969 tp_resume(tp, evdev);
971 case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED:
972 tp_suspend(tp, evdev);
974 case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE:
975 tp_suspend_conditional(tp, evdev);
978 return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
981 tp->sendevents.current_mode = mode;
983 return LIBINPUT_CONFIG_STATUS_SUCCESS;
986 static enum libinput_config_send_events_mode
987 tp_sendevents_get_mode(struct libinput_device *device)
989 struct evdev_device *evdev = (struct evdev_device*)device;
990 struct tp_dispatch *dispatch = (struct tp_dispatch*)evdev->dispatch;
992 return dispatch->sendevents.current_mode;
995 static enum libinput_config_send_events_mode
996 tp_sendevents_get_default_mode(struct libinput_device *device)
998 return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
1001 struct evdev_dispatch *
1002 evdev_mt_touchpad_create(struct evdev_device *device)
1004 struct tp_dispatch *tp;
1006 tp = zalloc(sizeof *tp);
1010 if (tp_init(tp, device) != 0) {
1011 tp_destroy(&tp->base);
1015 device->base.config.sendevents = &tp->sendevents.config;
1017 tp->sendevents.current_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
1018 tp->sendevents.config.get_modes = tp_sendevents_get_modes;
1019 tp->sendevents.config.set_mode = tp_sendevents_set_mode;
1020 tp->sendevents.config.get_mode = tp_sendevents_get_mode;
1021 tp->sendevents.config.get_default_mode = tp_sendevents_get_default_mode;