diff --git a/doc/device-configuration-via-udev.dox b/doc/device-configuration-via-udev.dox index 4107f943..fc1c0af8 100644 --- a/doc/device-configuration-via-udev.dox +++ b/doc/device-configuration-via-udev.dox @@ -11,7 +11,22 @@ The following udev properties are supported:
LIBINPUT_CALIBRATION_MATRIX
Sets the calibration matrix, see libinput_device_config_calibration_get_default_matrix(). If unset, -defaults to the identity matrix.
+defaults to the identity matrix. + +The udev property is parsed as 6 floating point numbers separated by a +single space each (scanf(3) format "%f %f %f %f %f %f"). +The 6 values represent the first two rows of the calibration matrix as +described in libinput_device_config_calibration_set_matrix(). + +Example values are: +@code + ENV{LIBINPUT_CALIBRATION_MATRIX}="1 0 0 0 1 0" # default + ENV{LIBINPUT_CALIBRATION_MATRIX}="0 -1 1 1 0 0" # 90 degree clockwise + ENV{LIBINPUT_CALIBRATION_MATRIX}="-1 0 1 0 -1 1" # 180 degree clockwise + ENV{LIBINPUT_CALIBRATION_MATRIX}="0 1 0 -1 0 1" # 270 degree clockwise + ENV{LIBINPUT_CALIBRATION_MATRIX}="-1 0 1 1 0 0" # reflect along y axis +@endcode +
LIBINPUT_DEVICE_GROUP
A string identifying the @ref libinput_device_group for this device. Two devices with the same property value are grouped into the same device group, diff --git a/src/Makefile.am b/src/Makefile.am index e807e236..d5cd4f41 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,6 +17,7 @@ libinput_la_SOURCES = \ evdev-mt-touchpad-tap.c \ evdev-mt-touchpad-buttons.c \ evdev-mt-touchpad-edge-scroll.c \ + evdev-mt-touchpad-gestures.c \ filter.c \ filter.h \ filter-private.h \ diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 9dbb5137..12f80234 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -156,7 +156,6 @@ tp_button_set_state(struct tp_dispatch *tp, struct tp_touch *t, break; case BUTTON_STATE_AREA: t->button.curr = BUTTON_EVENT_IN_AREA; - tp_set_pointer(tp, t); break; case BUTTON_STATE_BOTTOM: t->button.curr = event; diff --git a/src/evdev-mt-touchpad-edge-scroll.c b/src/evdev-mt-touchpad-edge-scroll.c index 8d0a13e3..28f29c2f 100644 --- a/src/evdev-mt-touchpad-edge-scroll.c +++ b/src/evdev-mt-touchpad-edge-scroll.c @@ -86,7 +86,6 @@ tp_edge_scroll_set_state(struct tp_dispatch *tp, break; case EDGE_SCROLL_TOUCH_STATE_AREA: t->scroll.edge = EDGE_NONE; - tp_set_pointer(tp, t); break; } } @@ -317,6 +316,9 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time) enum libinput_pointer_axis axis; double dx, dy, *delta; + if (tp->scroll.method != LIBINPUT_CONFIG_SCROLL_EDGE) + return 0; + tp_for_each_touch(tp, t) { if (!t->dirty) continue; diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c new file mode 100644 index 00000000..c1ed1c26 --- /dev/null +++ b/src/evdev-mt-touchpad-gestures.c @@ -0,0 +1,233 @@ +/* + * Copyright © 2015 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "evdev-mt-touchpad.h" + +#define DEFAULT_GESTURE_SWITCH_TIMEOUT 100 /* ms */ + +static void +tp_get_touches_delta(struct tp_dispatch *tp, double *dx, double *dy, bool average) +{ + struct tp_touch *t; + unsigned int i, nchanged = 0; + double tmpx, tmpy; + + *dx = 0.0; + *dy = 0.0; + + for (i = 0; i < tp->real_touches; i++) { + t = &tp->touches[i]; + + if (tp_touch_active(tp, t) && t->dirty) { + nchanged++; + tp_get_delta(t, &tmpx, &tmpy); + + *dx += tmpx; + *dy += tmpy; + } + } + + if (!average || nchanged == 0) + return; + + *dx /= nchanged; + *dy /= nchanged; +} + +static inline void +tp_get_combined_touches_delta(struct tp_dispatch *tp, double *dx, double *dy) +{ + tp_get_touches_delta(tp, dx, dy, false); +} + +static inline void +tp_get_average_touches_delta(struct tp_dispatch *tp, double *dx, double *dy) +{ + tp_get_touches_delta(tp, dx, dy, true); +} + +static void +tp_gesture_start(struct tp_dispatch *tp, uint64_t time) +{ + if (tp->gesture.started) + return; + + switch (tp->gesture.finger_count) { + case 2: + /* NOP */ + break; + } + tp->gesture.started = true; +} + +static void +tp_gesture_post_pointer_motion(struct tp_dispatch *tp, uint64_t time) +{ + double dx = 0.0, dy = 0.0; + double dx_unaccel, dy_unaccel; + + /* When a clickpad is clicked, combine motion of all active touches */ + if (tp->buttons.is_clickpad && tp->buttons.state) + tp_get_combined_touches_delta(tp, &dx, &dy); + else + tp_get_average_touches_delta(tp, &dx, &dy); + + tp_filter_motion(tp, &dx, &dy, &dx_unaccel, &dy_unaccel, time); + + if (dx != 0.0 || dy != 0.0 || dx_unaccel != 0.0 || dy_unaccel != 0.0) { + pointer_notify_motion(&tp->device->base, time, + dx, dy, dx_unaccel, dy_unaccel); + } +} + +static void +tp_gesture_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time) +{ + double dx = 0, dy =0; + + tp_get_average_touches_delta(tp, &dx, &dy); + tp_filter_motion(tp, &dx, &dy, NULL, NULL, time); + + if (dx == 0.0 && dy == 0.0) + return; + + tp_gesture_start(tp, time); + evdev_post_scroll(tp->device, + time, + LIBINPUT_POINTER_AXIS_SOURCE_FINGER, + dx, dy); +} + +void +tp_gesture_post_events(struct tp_dispatch *tp, uint64_t time) +{ + if (tp->gesture.finger_count == 0) + return; + + /* When tap-and-dragging, or a clickpad is clicked force 1fg mode */ + if (tp_tap_dragging(tp) || (tp->buttons.is_clickpad && tp->buttons.state)) { + tp_gesture_stop(tp, time); + tp->gesture.finger_count = 1; + tp->gesture.finger_count_pending = 0; + } + + /* Don't send events when we're unsure in which mode we are */ + if (tp->gesture.finger_count_pending) + return; + + switch (tp->gesture.finger_count) { + case 1: + tp_gesture_post_pointer_motion(tp, time); + break; + case 2: + tp_gesture_post_twofinger_scroll(tp, time); + break; + } +} + +void +tp_gesture_stop_twofinger_scroll(struct tp_dispatch *tp, uint64_t time) +{ + evdev_stop_scroll(tp->device, + time, + LIBINPUT_POINTER_AXIS_SOURCE_FINGER); +} + +void +tp_gesture_stop(struct tp_dispatch *tp, uint64_t time) +{ + if (!tp->gesture.started) + return; + + switch (tp->gesture.finger_count) { + case 2: + tp_gesture_stop_twofinger_scroll(tp, time); + break; + } + tp->gesture.started = false; +} + +static void +tp_gesture_finger_count_switch_timeout(uint64_t now, void *data) +{ + struct tp_dispatch *tp = data; + + if (!tp->gesture.finger_count_pending) + return; + + tp_gesture_stop(tp, now); /* End current gesture */ + tp->gesture.finger_count = tp->gesture.finger_count_pending; + tp->gesture.finger_count_pending = 0; +} + +void +tp_gesture_handle_state(struct tp_dispatch *tp, uint64_t time) +{ + unsigned int active_touches = 0; + struct tp_touch *t; + + tp_for_each_touch(tp, t) + if (tp_touch_active(tp, t)) + active_touches++; + + if (active_touches != tp->gesture.finger_count) { + /* If all fingers are lifted immediately end the gesture */ + if (active_touches == 0) { + tp_gesture_stop(tp, time); + tp->gesture.finger_count = 0; + tp->gesture.finger_count_pending = 0; + /* Immediately switch to new mode to avoid initial latency */ + } else if (!tp->gesture.started) { + tp->gesture.finger_count = active_touches; + tp->gesture.finger_count_pending = 0; + /* Else debounce finger changes */ + } else if (active_touches != tp->gesture.finger_count_pending) { + tp->gesture.finger_count_pending = active_touches; + libinput_timer_set(&tp->gesture.finger_count_switch_timer, + time + DEFAULT_GESTURE_SWITCH_TIMEOUT); + } + } else { + tp->gesture.finger_count_pending = 0; + } +} + +int +tp_init_gesture(struct tp_dispatch *tp) +{ + libinput_timer_init(&tp->gesture.finger_count_switch_timer, + tp->device->base.seat->libinput, + tp_gesture_finger_count_switch_timeout, tp); + return 0; +} + +void +tp_remove_gesture(struct tp_dispatch *tp) +{ + libinput_timer_cancel(&tp->gesture.finger_count_switch_timer); +} diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index e0b0c364..b90d84c5 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -227,7 +227,6 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) } t->dirty = true; - t->is_pointer = false; t->palm.is_palm = false; t->state = TOUCH_END; t->pinned.is_pinned = false; @@ -424,7 +423,6 @@ tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t) if (xdist * xdist + ydist * ydist >= tp->buttons.motion_dist * tp->buttons.motion_dist) { t->pinned.is_pinned = false; - tp_set_pointer(tp, t); return; } @@ -439,14 +437,13 @@ tp_pin_fingers(struct tp_dispatch *tp) struct tp_touch *t; tp_for_each_touch(tp, t) { - t->is_pointer = false; t->pinned.is_pinned = true; t->pinned.center_x = t->x; t->pinned.center_y = t->y; } } -static int +int tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t) { return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) && @@ -456,21 +453,6 @@ tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t) tp_edge_scroll_touch_active(tp, t); } -void -tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t) -{ - struct tp_touch *tmp = NULL; - - /* Only set the touch as pointer if we don't have one yet */ - tp_for_each_touch(tp, tmp) { - if (tmp->is_pointer) - return; - } - - if (tp_touch_active(tp, t)) - t->is_pointer = true; -} - static void tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) { @@ -487,7 +469,6 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) int dirs = vector_get_direction(t->x - t->palm.x, t->y - t->palm.y); if ((dirs & DIRECTIONS) && !(dirs & ~DIRECTIONS)) { t->palm.is_palm = false; - tp_set_pointer(tp, t); } } return; @@ -512,153 +493,6 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) t->palm.y = t->y; } -static void -tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time) -{ - struct tp_touch *t; - int nchanged = 0; - double dx = 0, dy =0; - double tmpx, tmpy; - - tp_for_each_touch(tp, t) { - if (tp_touch_active(tp, t) && t->dirty) { - nchanged++; - tp_get_delta(t, &tmpx, &tmpy); - - dx += tmpx; - dy += tmpy; - } - /* Stop spurious MOTION events at the end of scrolling */ - t->is_pointer = false; - } - - if (nchanged == 0) - return; - - dx /= nchanged; - dy /= nchanged; - - tp_filter_motion(tp, &dx, &dy, NULL, NULL, time); - - evdev_post_scroll(tp->device, - time, - LIBINPUT_POINTER_AXIS_SOURCE_FINGER, - dx, dy); - tp->scroll.twofinger_state = TWOFINGER_SCROLL_STATE_ACTIVE; -} - -static void -tp_twofinger_stop_scroll(struct tp_dispatch *tp, uint64_t time) -{ - struct tp_touch *t, *ptr = NULL; - int nfingers_down = 0; - - evdev_stop_scroll(tp->device, - time, - LIBINPUT_POINTER_AXIS_SOURCE_FINGER); - - /* If we were scrolling and now there's exactly 1 active finger, - switch back to pointer movement */ - if (tp->scroll.twofinger_state == TWOFINGER_SCROLL_STATE_ACTIVE) { - tp_for_each_touch(tp, t) { - if (tp_touch_active(tp, t)) { - nfingers_down++; - if (ptr == NULL) - ptr = t; - } - } - - if (nfingers_down == 1) - tp_set_pointer(tp, ptr); - } - - tp->scroll.twofinger_state = TWOFINGER_SCROLL_STATE_NONE; -} - -static int -tp_twofinger_scroll_post_events(struct tp_dispatch *tp, uint64_t time) -{ - struct tp_touch *t; - int nfingers_down = 0; - - /* No 2fg scrolling during tap-n-drag */ - if (tp_tap_dragging(tp)) - return 0; - - /* No 2fg scrolling while a clickpad is clicked */ - if (tp->buttons.is_clickpad && tp->buttons.state) - return 0; - - /* Only count active touches for 2 finger scrolling */ - tp_for_each_touch(tp, t) { - if (tp_touch_active(tp, t)) - nfingers_down++; - } - - if (nfingers_down == 2) { - tp_post_twofinger_scroll(tp, time); - return 1; - } - - tp_twofinger_stop_scroll(tp, time); - - return 0; -} - -static void -tp_scroll_handle_state(struct tp_dispatch *tp, uint64_t time) -{ - /* Note this must be always called, so that it knows the state of - * touches when the scroll-mode changes. - */ - tp_edge_scroll_handle_state(tp, time); -} - -static int -tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time) -{ - struct libinput *libinput = tp->device->base.seat->libinput; - - switch (tp->scroll.method) { - case LIBINPUT_CONFIG_SCROLL_NO_SCROLL: - break; - case LIBINPUT_CONFIG_SCROLL_2FG: - return tp_twofinger_scroll_post_events(tp, time); - case LIBINPUT_CONFIG_SCROLL_EDGE: - return tp_edge_scroll_post_events(tp, time); - case LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN: - log_bug_libinput(libinput, "Unexpected scroll mode\n"); - break; - } - return 0; -} - -static void -tp_stop_scroll_events(struct tp_dispatch *tp, uint64_t time) -{ - struct libinput *libinput = tp->device->base.seat->libinput; - - switch (tp->scroll.method) { - case LIBINPUT_CONFIG_SCROLL_NO_SCROLL: - break; - case LIBINPUT_CONFIG_SCROLL_2FG: - tp_twofinger_stop_scroll(tp, time); - break; - case LIBINPUT_CONFIG_SCROLL_EDGE: - tp_edge_scroll_stop_events(tp, time); - break; - case LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN: - log_bug_libinput(libinput, "Unexpected scroll mode\n"); - break; - } -} - -static void -tp_remove_scroll(struct tp_dispatch *tp) -{ - tp_remove_edge_scroll(tp); -} - static void tp_unhover_touches(struct tp_dispatch *tp, uint64_t time) { @@ -749,7 +583,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time) } tp_button_handle_state(tp, time); - tp_scroll_handle_state(tp, time); + tp_edge_scroll_handle_state(tp, time); /* * We have a physical button down event on a clickpad. To avoid @@ -760,6 +594,8 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time) if ((tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) && tp->buttons.is_clickpad) tp_pin_fingers(tp); + + tp_gesture_handle_state(tp, time); } static void @@ -790,63 +626,6 @@ tp_post_process_state(struct tp_dispatch *tp, uint64_t time) tp->queued = TOUCHPAD_EVENT_NONE; } -static void -tp_get_pointer_delta(struct tp_dispatch *tp, double *dx, double *dy) -{ - struct tp_touch *t = tp_current_touch(tp); - - if (!t->is_pointer) { - tp_for_each_touch(tp, t) { - if (t->is_pointer) - break; - } - } - - if (!t->is_pointer || !t->dirty) - return; - - tp_get_delta(t, dx, dy); -} - -static void -tp_get_active_touches_delta(struct tp_dispatch *tp, double *dx, double *dy) -{ - struct tp_touch *t; - double tdx, tdy; - unsigned int i; - - for (i = 0; i < tp->real_touches; i++) { - t = tp_get_touch(tp, i); - - if (!tp_touch_active(tp, t) || !t->dirty) - continue; - - tp_get_delta(t, &tdx, &tdy); - *dx += tdx; - *dy += tdy; - } -} - -static void -tp_post_pointer_motion(struct tp_dispatch *tp, uint64_t time) -{ - double dx = 0.0, dy = 0.0; - double dx_unaccel, dy_unaccel; - - /* When a clickpad is clicked, combine motion of all active touches */ - if (tp->buttons.is_clickpad && tp->buttons.state) - tp_get_active_touches_delta(tp, &dx, &dy); - else - tp_get_pointer_delta(tp, &dx, &dy); - - tp_filter_motion(tp, &dx, &dy, &dx_unaccel, &dy_unaccel, time); - - if (dx != 0.0 || dy != 0.0 || dx_unaccel != 0.0 || dy_unaccel != 0.0) { - pointer_notify_motion(&tp->device->base, time, - dx, dy, dx_unaccel, dy_unaccel); - } -} - static void tp_post_events(struct tp_dispatch *tp, uint64_t time) { @@ -862,14 +641,15 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time) filter_motion |= tp_post_button_events(tp, time); if (filter_motion || tp->sendevents.trackpoint_active) { - tp_stop_scroll_events(tp, time); + tp_edge_scroll_stop_events(tp, time); + tp_gesture_stop(tp, time); return; } - if (tp_post_scroll_events(tp, time) != 0) + if (tp_edge_scroll_post_events(tp, time) != 0) return; - tp_post_pointer_motion(tp, time); + tp_gesture_post_events(tp, time); } static void @@ -925,7 +705,8 @@ tp_remove(struct evdev_dispatch *dispatch) tp_remove_tap(tp); tp_remove_buttons(tp); tp_remove_sendevents(tp); - tp_remove_scroll(tp); + tp_remove_edge_scroll(tp); + tp_remove_gesture(tp); } static void @@ -1017,9 +798,8 @@ tp_trackpoint_event(uint64_t time, struct libinput_event *event, void *data) return; if (!tp->sendevents.trackpoint_active) { - evdev_stop_scroll(tp->device, - time, - LIBINPUT_POINTER_AXIS_SOURCE_FINGER); + tp_edge_scroll_stop_events(tp, time); + tp_gesture_stop(tp, time); tp_tap_suspend(tp, time); tp->sendevents.trackpoint_active = true; } @@ -1254,11 +1034,14 @@ tp_scroll_config_scroll_method_set_method(struct libinput_device *device, { struct evdev_device *evdev = (struct evdev_device*)device; struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch; + uint64_t time = libinput_now(device->seat->libinput); if (method == tp->scroll.method) return LIBINPUT_CONFIG_STATUS_SUCCESS; - tp_stop_scroll_events(tp, libinput_now(device->seat->libinput)); + tp_edge_scroll_stop_events(tp, time); + tp_gesture_stop_twofinger_scroll(tp, time); + tp->scroll.method = method; return LIBINPUT_CONFIG_STATUS_SUCCESS; @@ -1395,6 +1178,9 @@ tp_init(struct tp_dispatch *tp, if (tp_init_scroll(tp, device) != 0) return -1; + if (tp_init_gesture(tp) != 0) + return -1; + device->seat_caps |= EVDEV_DEVICE_POINTER; return 0; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index d552c26d..f04cc112 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -117,11 +117,6 @@ enum tp_edge_scroll_touch_state { EDGE_SCROLL_TOUCH_STATE_AREA, }; -enum tp_twofinger_scroll_state { - TWOFINGER_SCROLL_STATE_NONE, - TWOFINGER_SCROLL_STATE_ACTIVE, -}; - struct tp_motion { int32_t x; int32_t y; @@ -132,7 +127,6 @@ struct tp_touch { enum touch_state state; bool has_ended; /* TRACKING_ID == -1 */ bool dirty; - bool is_pointer; /* the pointer-controlling touch */ int32_t x; int32_t y; uint64_t millis; @@ -215,6 +209,13 @@ struct tp_dispatch { double y_scale_coeff; } accel; + struct { + bool started; + unsigned int finger_count; + unsigned int finger_count_pending; + struct libinput_timer finger_count_switch_timer; + } gesture; + struct { bool is_clickpad; /* true for clickpads */ bool has_topbuttons; @@ -252,7 +253,6 @@ struct tp_dispatch { enum libinput_config_scroll_method method; int32_t right_edge; int32_t bottom_edge; - enum tp_twofinger_scroll_state twofinger_state; } scroll; enum touchpad_event queued; @@ -286,15 +286,15 @@ struct tp_dispatch { void tp_get_delta(struct tp_touch *t, double *dx, double *dy); -void -tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t); - void tp_filter_motion(struct tp_dispatch *tp, double *dx, double *dy, double *dx_unaccel, double *dy_unaccel, uint64_t time); +int +tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t); + int tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time); @@ -367,4 +367,22 @@ tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time); int tp_edge_scroll_touch_active(struct tp_dispatch *tp, struct tp_touch *t); +int +tp_init_gesture(struct tp_dispatch *tp); + +void +tp_remove_gesture(struct tp_dispatch *tp); + +void +tp_gesture_stop(struct tp_dispatch *tp, uint64_t time); + +void +tp_gesture_handle_state(struct tp_dispatch *tp, uint64_t time); + +void +tp_gesture_post_events(struct tp_dispatch *tp, uint64_t time); + +void +tp_gesture_stop_twofinger_scroll(struct tp_dispatch *tp, uint64_t time); + #endif diff --git a/src/evdev.c b/src/evdev.c index bbc3dce5..b90ea7c7 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -58,6 +58,7 @@ enum evdev_device_udev_tags { EVDEV_UDEV_TAG_TABLET = (1 << 5), EVDEV_UDEV_TAG_JOYSTICK = (1 << 6), EVDEV_UDEV_TAG_ACCELEROMETER = (1 << 7), + EVDEV_UDEV_TAG_BUTTONSET = (1 << 8), }; struct evdev_udev_tag_match { @@ -73,6 +74,7 @@ static const struct evdev_udev_tag_match evdev_udev_tag_matches[] = { {"ID_INPUT_TOUCHPAD", EVDEV_UDEV_TAG_TOUCHPAD}, {"ID_INPUT_TOUCHSCREEN", EVDEV_UDEV_TAG_TOUCHSCREEN}, {"ID_INPUT_TABLET", EVDEV_UDEV_TAG_TABLET}, + {"ID_INPUT_TABLET_PAD", EVDEV_UDEV_TAG_BUTTONSET}, {"ID_INPUT_JOYSTICK", EVDEV_UDEV_TAG_JOYSTICK}, {"ID_INPUT_ACCELEROMETER", EVDEV_UDEV_TAG_ACCELEROMETER}, @@ -524,6 +526,14 @@ evdev_process_touch(struct evdev_device *device, { switch (e->code) { case ABS_MT_SLOT: + if ((size_t)e->value >= device->mt.slots_len) { + log_bug_libinput(device->base.seat->libinput, + "%s exceeds slots (%d of %d)\n", + device->devname, + e->value, + device->mt.slots_len); + e->value = device->mt.slots_len - 1; + } evdev_flush_pending_event(device, time); device->mt.slot = e->value; break; @@ -1400,7 +1410,7 @@ evdev_configure_device(struct evdev_device *device) } log_info(libinput, - "input device '%s', %s is tagged by udev as:%s%s%s%s%s%s%s\n", + "input device '%s', %s is tagged by udev as:%s%s%s%s%s%s%s%s\n", device->devname, devnode, udev_tags & EVDEV_UDEV_TAG_KEYBOARD ? " Keyboard" : "", udev_tags & EVDEV_UDEV_TAG_MOUSE ? " Mouse" : "", @@ -1408,7 +1418,8 @@ evdev_configure_device(struct evdev_device *device) udev_tags & EVDEV_UDEV_TAG_TOUCHSCREEN ? " Touchscreen" : "", udev_tags & EVDEV_UDEV_TAG_TABLET ? " Tablet" : "", udev_tags & EVDEV_UDEV_TAG_JOYSTICK ? " Joystick" : "", - udev_tags & EVDEV_UDEV_TAG_ACCELEROMETER ? " Accelerometer" : ""); + udev_tags & EVDEV_UDEV_TAG_ACCELEROMETER ? " Accelerometer" : "", + udev_tags & EVDEV_UDEV_TAG_BUTTONSET ? " Buttonset" : ""); /* libwacom *adds* TABLET, TOUCHPAD but leaves JOYSTICK in place, so make sure we only ignore real joystick devices */ @@ -1419,6 +1430,14 @@ evdev_configure_device(struct evdev_device *device) return -1; } + /* libwacom assigns tablet _and_ tablet_pad to the pad devices */ + if (udev_tags & EVDEV_UDEV_TAG_BUTTONSET) { + log_info(libinput, + "input device '%s', %s is a buttonset, ignoring\n", + device->devname, devnode); + return -1; + } + if (libevdev_has_event_type(evdev, EV_ABS)) { if ((absinfo = libevdev_get_abs_info(evdev, ABS_X))) { @@ -1467,10 +1486,9 @@ evdev_configure_device(struct evdev_device *device) if (!device->mtdev) return -1; - num_slots = device->mtdev->caps.slot.maximum; - if (device->mtdev->caps.slot.minimum < 0 || - num_slots <= 0) - return -1; + /* pick 10 slots as default for type A + devices. */ + num_slots = 10; active_slot = device->mtdev->caps.slot.value; } else { num_slots = libevdev_get_num_slots(device->evdev); diff --git a/src/libinput.h b/src/libinput.h index 17be1797..06207fd7 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -48,8 +48,7 @@ enum libinput_log_priority { * @ingroup device * * Capabilities on a device. A device may have one or more capabilities - * at a time, and capabilities may appear or disappear during the - * lifetime of the device. + * at a time, capabilities remain static for the lifetime of the device. */ enum libinput_device_capability { LIBINPUT_DEVICE_CAP_KEYBOARD = 0, @@ -94,7 +93,8 @@ enum libinput_button_state { /** * @ingroup device * - * Axes on a device that are not x or y coordinates. + * Axes on a device with the capability @ref LIBINPUT_DEVICE_CAP_POINTER + * that are not x or y coordinates. * * The two scroll axes @ref LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL and * @ref LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL are engaged separately, @@ -411,9 +411,9 @@ libinput_event_get_context(struct libinput_event *event); /** * @ingroup event * - * Return the device associated with this event, if applicable. For device - * added/removed events this is the device added or removed. For all other - * device events, this is the device that generated the event. + * Return the device associated with this event. For device added/removed + * events this is the device added or removed. For all other device events, + * this is the device that generated the event. * * This device is not refcounted and its lifetime is that of the event. Use * libinput_device_ref() before using the device outside of this scope. @@ -544,10 +544,10 @@ libinput_event_keyboard_get_base_event(struct libinput_event_keyboard *event); * of keys pressed on all devices on the associated seat after the event was * triggered. * - " @note It is an application bug to call this function for events other than + * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_KEYBOARD_KEY. For other events, this function returns 0. * - * @return the seat wide pressed key count for the key of this event + * @return The seat wide pressed key count for the key of this event */ uint32_t libinput_event_keyboard_get_seat_key_count( @@ -584,7 +584,7 @@ libinput_event_pointer_get_time(struct libinput_event_pointer *event); * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_MOTION. * - * @return the relative x movement since the last event + * @return The relative x movement since the last event */ double libinput_event_pointer_get_dx(struct libinput_event_pointer *event); @@ -605,7 +605,7 @@ libinput_event_pointer_get_dx(struct libinput_event_pointer *event); * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_MOTION. * - * @return the relative y movement since the last event + * @return The relative y movement since the last event */ double libinput_event_pointer_get_dy(struct libinput_event_pointer *event); @@ -625,7 +625,7 @@ libinput_event_pointer_get_dy(struct libinput_event_pointer *event); * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_MOTION. * - * @return the unaccelerated relative x movement since the last event + * @return The unaccelerated relative x movement since the last event */ double libinput_event_pointer_get_dx_unaccelerated( @@ -646,7 +646,7 @@ libinput_event_pointer_get_dx_unaccelerated( * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_MOTION. * - * @return the unaccelerated relative y movement since the last event + * @return The unaccelerated relative y movement since the last event */ double libinput_event_pointer_get_dy_unaccelerated( @@ -665,7 +665,7 @@ libinput_event_pointer_get_dy_unaccelerated( * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE. * - * @return the current absolute x coordinate + * @return The current absolute x coordinate */ double libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event); @@ -683,7 +683,7 @@ libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event); * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE. * - * @return the current absolute y coordinate + * @return The current absolute y coordinate */ double libinput_event_pointer_get_absolute_y(struct libinput_event_pointer *event); @@ -703,7 +703,7 @@ libinput_event_pointer_get_absolute_y(struct libinput_event_pointer *event); * * @param event The libinput pointer event * @param width The current output screen width - * @return the current absolute x coordinate transformed to a screen coordinate + * @return The current absolute x coordinate transformed to a screen coordinate */ double libinput_event_pointer_get_absolute_x_transformed( @@ -725,7 +725,7 @@ libinput_event_pointer_get_absolute_x_transformed( * * @param event The libinput pointer event * @param height The current output screen height - * @return the current absolute y coordinate transformed to a screen coordinate + * @return The current absolute y coordinate transformed to a screen coordinate */ double libinput_event_pointer_get_absolute_y_transformed( @@ -742,7 +742,7 @@ libinput_event_pointer_get_absolute_y_transformed( * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_BUTTON. * - * @return the button triggering this event + * @return The button triggering this event */ uint32_t libinput_event_pointer_get_button(struct libinput_event_pointer *event); @@ -757,7 +757,7 @@ libinput_event_pointer_get_button(struct libinput_event_pointer *event); * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_BUTTON. * - * @return the button state triggering this event + * @return The button state triggering this event */ enum libinput_button_state libinput_event_pointer_get_button_state(struct libinput_event_pointer *event); @@ -769,11 +769,11 @@ libinput_event_pointer_get_button_state(struct libinput_event_pointer *event); * total number of buttons pressed on all devices on the associated seat * after the event was triggered. * - " @note It is an application bug to call this function for events other than + * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_BUTTON. For other events, this function * returns 0. * - * @return the seat wide pressed button count for the key of this event + * @return The seat wide pressed button count for the key of this event */ uint32_t libinput_event_pointer_get_seat_button_count( @@ -788,7 +788,7 @@ libinput_event_pointer_get_seat_button_count( * libinput_event_pointer_get_axis_value() returns a value of 0, the event * is a scroll stop event. * - * @return non-zero if this event contains a value for this axis + * @return Non-zero if this event contains a value for this axis */ int libinput_event_pointer_has_axis(struct libinput_event_pointer *event, @@ -814,7 +814,7 @@ libinput_event_pointer_has_axis(struct libinput_event_pointer *event, * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_AXIS. * - * @return the axis value of this event + * @return The axis value of this event * * @see libinput_event_pointer_get_axis_value_discrete */ @@ -855,7 +855,7 @@ libinput_event_pointer_get_axis_value(struct libinput_event_pointer *event, * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_AXIS. * - * @return the source for this axis event + * @return The source for this axis event */ enum libinput_pointer_axis_source libinput_event_pointer_get_axis_source(struct libinput_event_pointer *event); @@ -867,7 +867,7 @@ libinput_event_pointer_get_axis_source(struct libinput_event_pointer *event); * value translates into a discrete step depends on the source. * * If the source is @ref LIBINPUT_POINTER_AXIS_SOURCE_WHEEL, the discrete - * value correspond to the number of physical mouse clicks. + * value correspond to the number of physical mouse wheel clicks. * * If the source is @ref LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS or @ref * LIBINPUT_POINTER_AXIS_SOURCE_FINGER, the discrete value is always 0. @@ -947,7 +947,7 @@ libinput_event_touch_get_seat_slot(struct libinput_event_touch *event); * LIBINPUT_EVENT_TOUCH_DOWN and @ref LIBINPUT_EVENT_TOUCH_MOTION. * * @param event The libinput touch event - * @return the current absolute x coordinate + * @return The current absolute x coordinate */ double libinput_event_touch_get_x(struct libinput_event_touch *event); @@ -965,7 +965,7 @@ libinput_event_touch_get_x(struct libinput_event_touch *event); * @ref LIBINPUT_EVENT_TOUCH_MOTION. * * @param event The libinput touch event - * @return the current absolute y coordinate + * @return The current absolute y coordinate */ double libinput_event_touch_get_y(struct libinput_event_touch *event); @@ -981,7 +981,7 @@ libinput_event_touch_get_y(struct libinput_event_touch *event); * * @param event The libinput touch event * @param width The current output screen width - * @return the current absolute x coordinate transformed to a screen coordinate + * @return The current absolute x coordinate transformed to a screen coordinate */ double libinput_event_touch_get_x_transformed(struct libinput_event_touch *event, @@ -998,7 +998,7 @@ libinput_event_touch_get_x_transformed(struct libinput_event_touch *event, * * @param event The libinput touch event * @param height The current output screen height - * @return the current absolute y coordinate transformed to a screen coordinate + * @return The current absolute y coordinate transformed to a screen coordinate */ double libinput_event_touch_get_y_transformed(struct libinput_event_touch *event, @@ -1390,7 +1390,7 @@ struct libinput_interface { * @param user_data The user_data provided in * libinput_udev_create_context() * - * @return the file descriptor, or a negative errno on failure. + * @return The file descriptor, or a negative errno on failure. */ int (*open_restricted)(const char *path, int flags, void *user_data); /** @@ -1520,7 +1520,7 @@ libinput_path_remove_device(struct libinput_device *device); * libinput keeps a single file descriptor for all events. Call into * libinput_dispatch() if any events become available on this fd. * - * @return the file descriptor used to notify of pending events. + * @return The file descriptor used to notify of pending events. */ int libinput_get_fd(struct libinput *libinput); @@ -1532,7 +1532,11 @@ libinput_get_fd(struct libinput *libinput); * and processes them internally. Use libinput_get_event() to retrieve the * events. * - * Dispatching does not necessarily queue libinput events. + * Dispatching does not necessarily queue libinput events. This function + * should be called immediately once data is available on the file + * descriptor returned by libinput_get_fd(). libinput has a number of + * timing-sensitive features (e.g. tap-to-click), any delay in calling + * libinput_dispatch() may prevent these features from working correctly. * * @param libinput A previously initialized libinput context * @@ -1563,8 +1567,8 @@ libinput_get_event(struct libinput *libinput); * libinput_get_event() returns that event. * * @param libinput A previously initialized libinput context - * @return The event type of the next available event or LIBINPUT_EVENT_NONE - * if no event is availble. + * @return The event type of the next available event or @ref + * LIBINPUT_EVENT_NONE if no event is availble. */ enum libinput_event_type libinput_next_event_type(struct libinput *libinput); @@ -1572,6 +1576,10 @@ libinput_next_event_type(struct libinput *libinput); /** * @ingroup base * + * Set caller-specific data associated with this context. libinput does + * not manage, look at, or modify this data. The caller must ensure the + * data is valid. + * * @param libinput A previously initialized libinput context * @param user_data Caller-specific data passed to the various callback * interfaces. @@ -1583,8 +1591,10 @@ libinput_set_user_data(struct libinput *libinput, /** * @ingroup base * + * Get the caller-specific data associated with this context, if any. + * * @param libinput A previously initialized libinput context - * @return the caller-specific data previously assigned in + * @return The caller-specific data previously assigned in * libinput_create_udev(). */ void * @@ -1644,10 +1654,11 @@ libinput_unref(struct libinput *libinput); /** * @ingroup base * - * Set the global log priority. Messages with priorities equal to or - * higher than the argument will be printed to the current log handler. + * Set the log priority for the libinput context. Messages with priorities + * equal to or higher than the argument will be printed to the context's + * log handler. * - * The default log priority is LIBINPUT_LOG_PRIORITY_ERROR. + * The default log priority is @ref LIBINPUT_LOG_PRIORITY_ERROR. * * @param libinput A previously initialized libinput context * @param priority The minimum priority of log messages to print. @@ -1662,10 +1673,10 @@ libinput_log_set_priority(struct libinput *libinput, /** * @ingroup base * - * Get the global log priority. Messages with priorities equal to or + * Get the context's log priority. Messages with priorities equal to or * higher than the argument will be printed to the current log handler. * - * The default log priority is LIBINPUT_LOG_PRIORITY_ERROR. + * The default log priority is @ref LIBINPUT_LOG_PRIORITY_ERROR. * * @param libinput A previously initialized libinput context * @return The minimum priority of log messages to print. @@ -1698,8 +1709,8 @@ typedef void (*libinput_log_handler)(struct libinput *libinput, /** * @ingroup base * - * Set the global log handler. Messages with priorities equal to or higher - * than the current log priority will be passed to the given + * Set the context's log handler. Messages with priorities equal to or + * higher than the context's log priority will be passed to the given * log handler. * * The default log handler prints to stderr. @@ -1727,7 +1738,7 @@ libinput_log_set_handler(struct libinput *libinput, * @ingroup seat * * Increase the refcount of the seat. A seat will be freed whenever the - * refcount reaches 0. This may happen during dispatch if the + * refcount reaches 0. This may happen during libinput_dispatch() if the * seat was removed from the system. A caller must ensure to reference * the seat correctly to avoid dangling pointers. * @@ -1741,7 +1752,7 @@ libinput_seat_ref(struct libinput_seat *seat); * @ingroup seat * * Decrease the refcount of the seat. A seat will be freed whenever the - * refcount reaches 0. This may happen during dispatch if the + * refcount reaches 0. This may happen during libinput_dispatch() if the * seat was removed from the system. A caller must ensure to reference * the seat correctly to avoid dangling pointers. * @@ -1802,7 +1813,7 @@ libinput_seat_get_context(struct libinput_seat *seat); * be available to the caller. * * @param seat A previously obtained seat - * @return the physical name of this seat + * @return The physical name of this seat */ const char * libinput_seat_get_physical_name(struct libinput_seat *seat); @@ -1814,7 +1825,7 @@ libinput_seat_get_physical_name(struct libinput_seat *seat); * of devices within the compositor. * * @param seat A previously obtained seat - * @return the logical name of this seat + * @return The logical name of this seat */ const char * libinput_seat_get_logical_name(struct libinput_seat *seat); @@ -1827,9 +1838,9 @@ libinput_seat_get_logical_name(struct libinput_seat *seat); * @ingroup device * * Increase the refcount of the input device. An input device will be freed - * whenever the refcount reaches 0. This may happen during dispatch if the - * device was removed from the system. A caller must ensure to reference - * the device correctly to avoid dangling pointers. + * whenever the refcount reaches 0. This may happen during + * libinput_dispatch() if the device was removed from the system. A caller + * must ensure to reference the device correctly to avoid dangling pointers. * * @param device A previously obtained device * @return The passed device @@ -1841,9 +1852,9 @@ libinput_device_ref(struct libinput_device *device); * @ingroup device * * Decrease the refcount of the input device. An input device will be freed - * whenever the refcount reaches 0. This may happen during dispatch if the - * device was removed from the system. A caller must ensure to reference - * the device correctly to avoid dangling pointers. + * whenever the refcount reaches 0. This may happen during libinput_dispatch + * if the device was removed from the system. A caller must ensure to + * reference the device correctly to avoid dangling pointers. * * @param device A previously obtained device * @return NULL if the device was destroyed, otherwise the passed device @@ -2011,7 +2022,7 @@ libinput_device_get_id_vendor(struct libinput_device *device); * beyond the boundaries of this output. An absolute device has its input * coordinates mapped to the extents of this output. * - * @return the name of the output this device is mapped to, or NULL if no + * @return The name of the output this device is mapped to, or NULL if no * output is set */ const char * @@ -2020,7 +2031,8 @@ libinput_device_get_output_name(struct libinput_device *device); /** * @ingroup device * - * Get the seat associated with this input device. + * Get the seat associated with this input device, see @ref seats for + * details. * * A seat can be uniquely identified by the physical and logical seat name. * There will ever be only one seat instance with a given physical and logical @@ -2040,10 +2052,13 @@ libinput_device_get_seat(struct libinput_device *device); * device and adding it to the new seat. * * This command is identical to physically unplugging the device, then - * re-plugging it as member of the new seat, - * @ref LIBINPUT_EVENT_DEVICE_REMOVED and @ref LIBINPUT_EVENT_DEVICE_ADDED - * events are sent accordingly. Those events mark the end of the lifetime - * of this device and the start of a new device. + * re-plugging it as member of the new seat. libinput will generate a + * @ref LIBINPUT_EVENT_DEVICE_REMOVED event and this @ref libinput_device is + * considered removed from the context; it will not generate further events + * and will be freed when the refcount reaches zero. + * A @ref LIBINPUT_EVENT_DEVICE_ADDED event is generated with a new @ref + * libinput_device handle. It is the caller's responsibility to update + * references to the new device accordingly. * * If the logical seat name already exists in the device's physical seat, * the device is added to this seat. Otherwise, a new seat is created. @@ -2064,7 +2079,9 @@ libinput_device_set_seat_logical_name(struct libinput_device *device, * * Return a udev handle to the device that is this libinput device, if any. * The returned handle has a refcount of at least 1, the caller must call - * udev_device_unref() once to release the associated resources. + * udev_device_unref() once to release the associated resources. + * See the [libudev documentation] + * (http://www.freedesktop.org/software/systemd/libudev/) for details. * * Some devices may not have a udev device, or the udev device may be * unobtainable. This function returns NULL if no udev device was available. @@ -2098,7 +2115,7 @@ libinput_device_led_update(struct libinput_device *device, * * Check if the given device has the specified capability * - * @return 1 if the given device has the capability or 0 if not + * @return Non-zero if the given device has the capability or zero otherwise */ int libinput_device_has_capability(struct libinput_device *device, @@ -2127,10 +2144,10 @@ libinput_device_get_size(struct libinput_device *device, * @ingroup device * * Check if a @ref LIBINPUT_DEVICE_CAP_POINTER device has a button with the - * passed in code (see linux/input.h). + * given code (see linux/input.h). * * @param device A current input device - * @param code button code to check for + * @param code Button code to check for, e.g. BTN_LEFT * * @return 1 if the device supports this button code, 0 if it does not, -1 * on error. @@ -2150,9 +2167,10 @@ libinput_device_has_button(struct libinput_device *device, uint32_t code) LIBINP * @ingroup device * * Increase the refcount of the device group. A device group will be freed - * whenever the refcount reaches 0. This may happen during dispatch if all - * devices of this group were removed from the system. A caller must ensure - * to reference the device group correctly to avoid dangling pointers. + * whenever the refcount reaches 0. This may happen during + * libinput_dispatch() if all devices of this group were removed from the + * system. A caller must ensure to reference the device group correctly to + * avoid dangling pointers. * * @param group A previously obtained device group * @return The passed device group @@ -2164,9 +2182,10 @@ libinput_device_group_ref(struct libinput_device_group *group); * @ingroup device * * Decrease the refcount of the device group. A device group will be freed - * whenever the refcount reaches 0. This may happen during dispatch if all - * devices of this group were removed from the system. A caller must ensure - * to reference the device group correctly to avoid dangling pointers. + * whenever the refcount reaches 0. This may happen during + * libinput_dispatch() if all devices of this group were removed from the + * system. A caller must ensure to reference the device group correctly to + * avoid dangling pointers. * * @param group A previously obtained device group * @return NULL if the device group was destroyed, otherwise the passed @@ -2213,7 +2232,7 @@ libinput_device_group_get_user_data(struct libinput_device_group *group); * * Some configuration option may be dependent on or mutually exclusive with * with other options. The behavior in those cases is - * implementation-defined, the caller must ensure that the options are set + * implementation-dependent, the caller must ensure that the options are set * in the right order. */ @@ -2254,7 +2273,8 @@ enum libinput_config_tap_state { /** * @ingroup config * - * Check if the device supports tap-to-click. See + * Check if the device supports tap-to-click and how many fingers can be + * used for tapping. See * libinput_device_config_tap_set_enabled() for more information. * * @param device The device to configure @@ -2300,8 +2320,8 @@ libinput_device_config_tap_set_enabled(struct libinput_device *device, * * @param device The device to configure * - * @return @ref LIBINPUT_CONFIG_TAP_ENABLED if tapping is currently enabled, - * or @ref LIBINPUT_CONFIG_TAP_DISABLED is currently disabled + * @retval LIBINPUT_CONFIG_TAP_ENABLED If tapping is currently enabled + * @retval LIBINPUT_CONFIG_TAP_DISABLED If tapping is currently disabled * * @see libinput_device_config_tap_get_finger_count * @see libinput_device_config_tap_set_enabled @@ -2313,11 +2333,12 @@ libinput_device_config_tap_get_enabled(struct libinput_device *device); /** * @ingroup config * - * Return the default setting for whether tapping is enabled on this device. + * Return the default setting for whether tap-to-click is enabled on this + * device. * * @param device The device to configure - * @return @ref LIBINPUT_CONFIG_TAP_ENABLED if tapping is enabled by default, - * or @ref LIBINPUT_CONFIG_TAP_DISABLED is disabled by default + * @retval LIBINPUT_CONFIG_TAP_ENABLED If tapping is enabled by default + * @retval LIBINPUT_CONFIG_TAP_DISABLED If tapping Is disabled by default * * @see libinput_device_config_tap_get_finger_count * @see libinput_device_config_tap_set_enabled @@ -2332,7 +2353,7 @@ libinput_device_config_tap_get_default_enabled(struct libinput_device *device); * Check if the device can be calibrated via a calibration matrix. * * @param device The device to check - * @return non-zero if the device can be calibrated, zero otherwise. + * @return Non-zero if the device can be calibrated, zero otherwise. * * @see libinput_device_config_calibration_set_matrix * @see libinput_device_config_calibration_get_matrix @@ -2420,21 +2441,7 @@ libinput_device_config_calibration_get_matrix(struct libinput_device *device, * Return the default calibration matrix for this device. On most devices, * this is the identity matrix. If the udev property * LIBINPUT_CALIBRATION_MATRIX is set on the respective udev device, - * that property's value becomes the default matrix. - * - * The udev property is parsed as 6 floating point numbers separated by a - * single space each (scanf(3) format "%f %f %f %f %f %f"). - * The 6 values represent the first two rows of the calibration matrix as - * described in libinput_device_config_calibration_set_matrix(). - * - * Example values are: - * @code - * ENV{LIBINPUT_CALIBRATION_MATRIX}="1 0 0 0 1 0" # default - * ENV{LIBINPUT_CALIBRATION_MATRIX}="0 -1 1 1 0 0" # 90 degree clockwise - * ENV{LIBINPUT_CALIBRATION_MATRIX}="-1 0 1 0 -1 1" # 180 degree clockwise - * ENV{LIBINPUT_CALIBRATION_MATRIX}="0 1 0 -1 0 1" # 270 degree clockwise - * ENV{LIBINPUT_CALIBRATION_MATRIX}="-1 0 1 1 0 0" # reflect along y axis - * @endcode + * that property's value becomes the default matrix, see @ref udev_config. * * @param device The device to configure * @param matrix Set to the array representing the first two rows of a 3x3 matrix as @@ -2652,7 +2659,7 @@ libinput_device_config_accel_get_default_speed(struct libinput_device *device); * * @param device The device to configure * - * @return 0 if natural scrolling is not supported, non-zero if natural + * @return Zero if natural scrolling is not supported, non-zero if natural * scrolling is supported by this device * * @see libinput_device_config_set_natural_scroll_enabled @@ -2670,7 +2677,7 @@ libinput_device_config_scroll_has_natural_scroll(struct libinput_device *device) * @param device The device to configure * @param enable non-zero to enable, zero to disable natural scrolling * - * @return a config status code + * @return A config status code * * @see libinput_device_config_has_natural_scroll * @see libinput_device_config_get_natural_scroll_enabled @@ -2686,7 +2693,7 @@ libinput_device_config_scroll_set_natural_scroll_enabled(struct libinput_device * * @param device The device to configure * - * @return zero if natural scrolling is disabled, non-zero if enabled + * @return Zero if natural scrolling is disabled, non-zero if enabled * * @see libinput_device_config_has_natural_scroll * @see libinput_device_config_set_natural_scroll_enabled @@ -2702,7 +2709,7 @@ libinput_device_config_scroll_get_natural_scroll_enabled(struct libinput_device * * @param device The device to configure * - * @return zero if natural scrolling is disabled by default, non-zero if enabled + * @return Zero if natural scrolling is disabled by default, non-zero if enabled * * @see libinput_device_config_has_natural_scroll * @see libinput_device_config_set_natural_scroll_enabled @@ -2730,9 +2737,7 @@ libinput_device_config_left_handed_is_available(struct libinput_device *device); /** * @ingroup config * - * Set the left-handed configuration of the device. For example, a pointing - * device may reverse it's buttons and send a right button click when the - * left button is pressed, and vice versa. + * Set the left-handed configuration of the device. * * The exact behavior is device-dependent. On a mouse and most pointing * devices, left and right buttons are swapped but the middle button is @@ -2798,7 +2803,7 @@ libinput_device_config_left_handed_get_default(struct libinput_device *device); enum libinput_config_click_method { /** * Do not send software-emulated button events. This has no effect - * on physical button generations. + * on events generated by physical buttons. */ LIBINPUT_CONFIG_CLICK_METHOD_NONE = 0, /** @@ -2898,15 +2903,16 @@ libinput_device_config_click_get_default_method(struct libinput_device *device); enum libinput_config_scroll_method { /** * Never send scroll events instead of pointer motion events. - * Note scroll wheels, etc. will still send scroll events. + * This has no effect on events generated by scroll wheels. */ LIBINPUT_CONFIG_SCROLL_NO_SCROLL = 0, /** - * Send scroll events when 2 fingers are down on the device. + * Send scroll events when two fingers are logically down on the + * device. */ LIBINPUT_CONFIG_SCROLL_2FG = (1 << 0), /** - * Send scroll events when a finger is moved along the bottom or + * Send scroll events when a finger moves along the bottom or * right edge of a device. */ LIBINPUT_CONFIG_SCROLL_EDGE = (1 << 1), @@ -3024,10 +3030,11 @@ libinput_device_config_scroll_get_default_method(struct libinput_device *device) * @param device The device to configure * @param button The button which when pressed switches to sending scroll events * - * @return a config status code - * @retval LIBINPUT_CONFIG_STATUS_SUCCESS on success - * @retval LIBINPUT_CONFIG_STATUS_UNSUPPORTED if @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN is not supported - * @retval LIBINPUT_CONFIG_STATUS_INVALID the given button does not + * @return A config status code + * @retval LIBINPUT_CONFIG_STATUS_SUCCESS On success + * @retval LIBINPUT_CONFIG_STATUS_UNSUPPORTED If @ref + * LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN is not supported + * @retval LIBINPUT_CONFIG_STATUS_INVALID The given button does not * exist on this device * * @see libinput_device_config_scroll_get_methods @@ -3044,11 +3051,11 @@ libinput_device_config_scroll_set_button(struct libinput_device *device, /** * @ingroup config * - * Get the button for the @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN method for - * this device. + * Get the button for the @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN method + * for this device. * - * If @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN scroll method is not supported, - * or no button is set, this function returns 0. + * If @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN scroll method is not + * supported, or no button is set, this function returns 0. * * @note The return value is independent of the currently selected * scroll-method. For button scrolling to activate, a device must have the @@ -3071,14 +3078,15 @@ libinput_device_config_scroll_get_button(struct libinput_device *device); /** * @ingroup config * - * Get the default button for LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN method - * for this device. + * Get the default button for the @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN + * method for this device. * * If @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN scroll method is not supported, * or no default button is set, this function returns 0. * * @param device The device to configure - * @return The default button for LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN method + * @return The default button for the @ref + * LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN method * * @see libinput_device_config_scroll_get_methods * @see libinput_device_config_scroll_set_method diff --git a/test/Makefile.am b/test/Makefile.am index a0c93414..220575f2 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -19,6 +19,7 @@ liblitest_la_SOURCES = \ litest-keyboard.c \ litest-mouse.c \ litest-ms-surface-cover.c \ + litest-protocol-a-touch-screen.c \ litest-qemu-usb-tablet.c \ litest-synaptics.c \ litest-synaptics-hover.c \ diff --git a/test/litest-protocol-a-touch-screen.c b/test/litest-protocol-a-touch-screen.c new file mode 100644 index 00000000..2c930060 --- /dev/null +++ b/test/litest-protocol-a-touch-screen.c @@ -0,0 +1,97 @@ +/* + * Copyright © 2015 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "litest.h" +#include "litest-int.h" + +static void +litest_protocol_a_touch_setup(void) +{ + struct litest_device *d = litest_create_device(LITEST_PROTOCOL_A_SCREEN); + litest_set_current_device(d); +} + +static struct input_event down[] = { + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_MT_REPORT, .value = 0 }, + { .type = EV_KEY, .code = BTN_TOUCH, .value = 1 }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; + +static struct input_event move[] = { + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_MT_REPORT, .value = 0 }, + { .type = EV_KEY, .code = BTN_TOUCH, .value = 1 }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; + +static struct litest_device_interface interface = { + .touch_down_events = down, + .touch_move_events = move, +}; + +static struct input_absinfo absinfo[] = { + { ABS_X, 0, 32767, 0, 0, 0 }, + { ABS_Y, 0, 32767, 0, 0, 0 }, + { ABS_MT_POSITION_X, 0, 32767, 0, 0, 0 }, + { ABS_MT_POSITION_Y, 0, 32767, 0, 0, 0 }, + { ABS_MT_PRESSURE, 0, 1, 0, 0, 0 }, + { .value = -1 }, +}; + +static struct input_id input_id = { + .bustype = 0x18, + .vendor = 0xeef, + .product = 0x20, +}; + +static int events[] = { + EV_KEY, BTN_TOUCH, + INPUT_PROP_MAX, INPUT_PROP_DIRECT, + -1, -1, +}; + +struct litest_test_device litest_protocol_a_screen = { + .type = LITEST_PROTOCOL_A_SCREEN, + .features = LITEST_PROTOCOL_A, + .shortname = "protocol A", + .setup = litest_protocol_a_touch_setup, + .interface = &interface, + + .name = "Protocol A touch screen", + .id = &input_id, + .events = events, + .absinfo = absinfo, +}; diff --git a/test/litest.c b/test/litest.c index 6d4bfdbc..263e9b81 100644 --- a/test/litest.c +++ b/test/litest.c @@ -100,6 +100,7 @@ extern struct litest_test_device litest_xen_virtual_pointer_device; extern struct litest_test_device litest_vmware_virtmouse_device; extern struct litest_test_device litest_synaptics_hover_device; extern struct litest_test_device litest_synaptics_carbon3rd_device; +extern struct litest_test_device litest_protocol_a_screen; struct litest_test_device* devices[] = { &litest_synaptics_clickpad_device, @@ -121,6 +122,7 @@ struct litest_test_device* devices[] = { &litest_vmware_virtmouse_device, &litest_synaptics_hover_device, &litest_synaptics_carbon3rd_device, + &litest_protocol_a_screen, NULL, }; @@ -1507,6 +1509,12 @@ litest_timeout_buttonscroll(void) msleep(300); } +void +litest_timeout_finger_switch(void) +{ + msleep(120); +} + void litest_push_event_frame(struct litest_device *dev) { diff --git a/test/litest.h b/test/litest.h index 40b3910e..4fbffd7a 100644 --- a/test/litest.h +++ b/test/litest.h @@ -51,10 +51,11 @@ enum litest_device_type { LITEST_VMWARE_VIRTMOUSE = -15, LITEST_SYNAPTICS_HOVER_SEMI_MT = -16, LITEST_SYNAPTICS_TRACKPOINT_BUTTONS = -17, - LITEST_WACOM_BAMBOO = -18, - LITEST_WACOM_CINTIQ = -19, - LITEST_WACOM_INTUOS = -20, - LITEST_WACOM_ISDV4 = -21, + LITEST_PROTOCOL_A_SCREEN = -18, + LITEST_WACOM_BAMBOO = -19, + LITEST_WACOM_CINTIQ = -20, + LITEST_WACOM_INTUOS = -21, + LITEST_WACOM_ISDV4 = -22, }; enum litest_device_feature { @@ -74,9 +75,10 @@ enum litest_device_feature { LITEST_POINTINGSTICK = 1 << 11, LITEST_FAKE_MT = 1 << 12, LITEST_ABSOLUTE = 1 << 13, - LITEST_TABLET = 1 << 14, - LITEST_DISTANCE = 1 << 15, - LITEST_TOOL_SERIAL = 1 << 16, + LITEST_PROTOCOL_A = 1 << 14, + LITEST_TABLET = 1 << 15, + LITEST_DISTANCE = 1 << 16, + LITEST_TOOL_SERIAL = 1 << 17, }; struct litest_device { @@ -218,6 +220,7 @@ struct libevdev_uinput * litest_create_uinput_abs_device(const char *name, void litest_timeout_tap(void); void litest_timeout_softbuttons(void); void litest_timeout_buttonscroll(void); +void litest_timeout_finger_switch(void); void litest_push_event_frame(struct litest_device *dev); void litest_pop_event_frame(struct litest_device *dev); diff --git a/test/pointer.c b/test/pointer.c index 24ea7266..23bf0d7c 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -826,7 +826,7 @@ int main (int argc, char **argv) { litest_add("pointer:scroll", pointer_scroll_natural_wheel, LITEST_WHEEL, LITEST_ANY); litest_add_no_device("pointer:seat button count", pointer_seat_button_count); - litest_add("pointer:calibration", pointer_no_calibration, LITEST_ANY, LITEST_TOUCH|LITEST_SINGLE_TOUCH|LITEST_ABSOLUTE); + litest_add("pointer:calibration", pointer_no_calibration, LITEST_ANY, LITEST_TOUCH|LITEST_SINGLE_TOUCH|LITEST_ABSOLUTE|LITEST_PROTOCOL_A); /* tests touchpads too */ litest_add("pointer:left-handed", pointer_left_handed_defaults, LITEST_BUTTON, LITEST_ANY); diff --git a/test/touch.c b/test/touch.c index 29890a41..2d918b2d 100644 --- a/test/touch.c +++ b/test/touch.c @@ -465,6 +465,124 @@ START_TEST(fake_mt_no_touch_events) } END_TEST +START_TEST(touch_protocol_a_init) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_device *device = dev->libinput_device; + + ck_assert_int_ne(libinput_next_event_type(li), + LIBINPUT_EVENT_NONE); + + ck_assert(libinput_device_has_capability(device, + LIBINPUT_DEVICE_CAP_TOUCH)); +} +END_TEST + +START_TEST(touch_protocol_a_touch) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *ev; + struct libinput_event_touch *tev; + double x, y, oldx, oldy; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 5, 95); + + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_DOWN, -1); + + ev = libinput_get_event(li); + tev = libinput_event_get_touch_event(ev); + + oldx = libinput_event_touch_get_x(tev); + oldy = libinput_event_touch_get_y(tev); + + libinput_event_destroy(ev); + + litest_touch_move_to(dev, 0, 10, 90, 90, 10, 20, 1); + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_MOTION, -1); + + while ((ev = libinput_get_event(li))) { + if (libinput_event_get_type(ev) == + LIBINPUT_EVENT_TOUCH_FRAME) { + libinput_event_destroy(ev); + continue; + } + ck_assert_int_eq(libinput_event_get_type(ev), + LIBINPUT_EVENT_TOUCH_MOTION); + + tev = libinput_event_get_touch_event(ev); + x = libinput_event_touch_get_x(tev); + y = libinput_event_touch_get_y(tev); + + ck_assert_int_gt(x, oldx); + ck_assert_int_lt(y, oldy); + + oldx = x; + oldy = y; + + libinput_event_destroy(ev); + } + + litest_touch_up(dev, 0); + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_UP, -1); +} +END_TEST + +START_TEST(touch_protocol_a_2fg_touch) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *ev; + struct libinput_event_touch *tev; + int pos; + + litest_drain_events(li); + + litest_push_event_frame(dev); + litest_touch_down(dev, 0, 5, 95); + litest_touch_down(dev, 0, 95, 5); + litest_pop_event_frame(dev); + + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_DOWN, -1); + + ev = libinput_get_event(li); + libinput_event_destroy(ev); + + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_DOWN, -1); + + ev = libinput_get_event(li); + libinput_event_destroy(ev); + + for (pos = 10; pos < 100; pos += 10) { + litest_push_event_frame(dev); + litest_touch_move_to(dev, 0, pos, 100 - pos, pos, 100 - pos, 1, 1); + litest_touch_move_to(dev, 0, 100 - pos, pos, 100 - pos, pos, 1, 1); + litest_pop_event_frame(dev); + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_MOTION, -1); + ev = libinput_get_event(li); + tev = libinput_event_get_touch_event(ev); + ck_assert_int_eq(libinput_event_touch_get_slot(tev), + 0); + libinput_event_destroy(ev); + + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_MOTION, -1); + ev = libinput_get_event(li); + tev = libinput_event_get_touch_event(ev); + ck_assert_int_eq(libinput_event_touch_get_slot(tev), + 1); + libinput_event_destroy(ev); + } + + litest_event(dev, EV_SYN, SYN_MT_REPORT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_UP, -1); + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_UP, -1); +} +END_TEST + int main(int argc, char **argv) { @@ -484,5 +602,9 @@ main(int argc, char **argv) litest_add("touch:fake-mt", fake_mt_exists, LITEST_FAKE_MT, LITEST_ANY); litest_add("touch:fake-mt", fake_mt_no_touch_events, LITEST_FAKE_MT, LITEST_ANY); + litest_add("touch:protocol a", touch_protocol_a_init, LITEST_PROTOCOL_A, LITEST_ANY); + litest_add("touch:protocol a", touch_protocol_a_touch, LITEST_PROTOCOL_A, LITEST_ANY); + litest_add("touch:protocol a", touch_protocol_a_2fg_touch, LITEST_PROTOCOL_A, LITEST_ANY); + return litest_run(argc, argv); } diff --git a/test/touchpad.c b/test/touchpad.c index 9b3ba812..b70d3732 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -1871,6 +1871,9 @@ START_TEST(touchpad_2fg_scroll_return_to_motion) litest_touch_move_to(dev, 0, 47, 50, 47, 70, 5, 0); litest_touch_move_to(dev, 1, 53, 50, 53, 70, 5, 0); litest_touch_up(dev, 1); + libinput_dispatch(li); + litest_timeout_finger_switch(); + libinput_dispatch(li); litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS); litest_touch_move_to(dev, 0, 47, 70, 47, 50, 10, 0); @@ -1881,6 +1884,9 @@ START_TEST(touchpad_2fg_scroll_return_to_motion) litest_touch_move_to(dev, 0, 47, 50, 47, 70, 5, 0); litest_touch_move_to(dev, 1, 53, 50, 53, 70, 5, 0); litest_touch_up(dev, 0); + libinput_dispatch(li); + litest_timeout_finger_switch(); + libinput_dispatch(li); litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS); /* move with second finger */ diff --git a/test/valgrind.suppressions b/test/valgrind.suppressions index fc9251a7..4ad22ab2 100644 --- a/test/valgrind.suppressions +++ b/test/valgrind.suppressions @@ -7,6 +7,12 @@ fun:litest_run fun:main } +{ + mtdev:conditional_jumps_uninitialized_value + Memcheck:Cond + ... + fun:mtdev_put_event +} { Memcheck:Leak