diff -Nru libinput-1.10.1/debian/changelog libinput-1.10.3/debian/changelog --- libinput-1.10.1/debian/changelog 2018-02-28 16:20:21.000000000 +0000 +++ libinput-1.10.3/debian/changelog 2018-03-18 13:39:44.000000000 +0000 @@ -1,3 +1,25 @@ +libinput (1.10.3-2) unstable; urgency=medium + + [ Jeremy Bicha ] + * control: Update VCS urls. + * control: Add more packages to libinput-dev Depends as a workaround for + buggy meson/pkg-config. (Closes: #893067) + + -- Timo Aaltonen Sun, 18 Mar 2018 15:39:44 +0200 + +libinput (1.10.3-1) unstable; urgency=medium + + * New upstream release. (Closes: #892714) + + -- Timo Aaltonen Wed, 14 Mar 2018 11:04:22 +0200 + +libinput (1.10.2-1) unstable; urgency=medium + + * New upstream release. + - touchpad fixes (LP: #1751190) + + -- Timo Aaltonen Wed, 07 Mar 2018 17:51:58 +0200 + libinput (1.10.1-1) unstable; urgency=medium * New upstream release. diff -Nru libinput-1.10.1/debian/control libinput-1.10.3/debian/control --- libinput-1.10.1/debian/control 2018-02-28 16:16:52.000000000 +0000 +++ libinput-1.10.3/debian/control 2018-03-18 13:38:29.000000000 +0000 @@ -12,8 +12,8 @@ libevdev-dev (>= 0.4), libwacom-dev (>= 0.20), Standards-Version: 4.1.1 -Vcs-Git: https://anonscm.debian.org/git/pkg-xorg/lib/libinput.git -Vcs-Browser: https://anonscm.debian.org/cgit/pkg-xorg/lib/libinput.git +Vcs-Git: https://salsa.debian.org/xorg-team/lib/libinput.git +Vcs-Browser: https://salsa.debian.org/xorg-team/lib/libinput Homepage: http://www.freedesktop.org/wiki/Software/libinput/ Package: libinput10 @@ -69,7 +69,10 @@ Multi-Arch: same Depends: libinput10 (= ${binary:Version}), + libmtdev-dev (>= 1.1.0), libudev-dev, + libevdev-dev (>= 0.4), + libwacom-dev (>= 0.20), ${shlibs:Depends}, ${misc:Depends}, Description: input device management and event handling library - development files diff -Nru libinput-1.10.1/meson.build libinput-1.10.3/meson.build --- libinput-1.10.1/meson.build 2018-02-28 00:19:45.000000000 +0000 +++ libinput-1.10.3/meson.build 2018-03-14 05:34:05.000000000 +0000 @@ -1,5 +1,5 @@ project('libinput', 'c', 'cpp', - version : '1.10.1', + version : '1.10.3', license : 'MIT/Expat', default_options : [ 'c_std=gnu99', 'warning_level=2' ], meson_version : '>= 0.40.0') @@ -523,7 +523,7 @@ config_h.set10('HAVE_LIBUNWIND', dep_libunwind.found()) # for inhibit support during test run - dep_libsystemd = dependency('libsystemd', required : false) + dep_libsystemd = dependency('libsystemd', version : '>= 221', required : false) config_h.set10('HAVE_LIBSYSTEMD', dep_libsystemd.found()) lib_litest_sources = [ diff -Nru libinput-1.10.1/src/evdev-fallback.c libinput-1.10.3/src/evdev-fallback.c --- libinput-1.10.1/src/evdev-fallback.c 2018-02-28 00:19:45.000000000 +0000 +++ libinput-1.10.3/src/evdev-fallback.c 2018-03-14 05:34:05.000000000 +0000 @@ -127,12 +127,9 @@ if (!dispatch->mt.want_hysteresis) return false; - point.x = evdev_hysteresis(slot->point.x, - slot->hysteresis_center.x, - dispatch->mt.hysteresis_margin.x); - point.y = evdev_hysteresis(slot->point.y, - slot->hysteresis_center.y, - dispatch->mt.hysteresis_margin.y); + point = evdev_hysteresis(&slot->point, + &slot->hysteresis_center, + &dispatch->mt.hysteresis_margin); slot->hysteresis_center = slot->point; if (point.x == slot->point.x && point.y == slot->point.y) diff -Nru libinput-1.10.1/src/evdev.h libinput-1.10.3/src/evdev.h --- libinput-1.10.1/src/evdev.h 2018-02-28 00:19:45.000000000 +0000 +++ libinput-1.10.3/src/evdev.h 2018-03-14 05:34:05.000000000 +0000 @@ -600,11 +600,11 @@ * Apply a hysteresis filtering to the coordinate in, based on the current * hysteresis center and the margin. If 'in' is within 'margin' of center, * return the center (and thus filter the motion). If 'in' is outside, - * return a point on the edge of the new margin. So for a point x in the - * space outside c + margin we return r: - * +---+ +---+ + * return a point on the edge of the new margin (which is an ellipse, usually + * a circle). So for a point x in the space outside c + margin we return r: + * ,---. ,---. * | c | x → | r x - * +---+ +---+ + * `---' `---' * * The effect of this is that initial small motions are filtered. Once we * move into one direction we lag the real coordinates by 'margin' but any @@ -617,41 +617,71 @@ * Otherwise, the center has a dead zone of size margin around it and the * first reachable point is the margin edge. * - * Hysteresis is handled separately per axis (and the window is thus - * rectangular, not circular). It is unkown if that's an issue, but the - * calculation to do circular hysteresis are nontrivial, especially since - * many touchpads have uneven x/y resolutions. - * - * Given coordinates, 0, 1, 2, ... this is what we return for a margin of 3 - * and a center of 0: - * - * Input: 1 2 3 4 5 6 5 4 3 2 1 0 -1 - * Coord: 0 0 0 1 2 3 3 3 3 3 3 3 2 - * Center: 0 0 0 1 2 3 3 3 3 3 3 3 2 - * - * Problem: viewed from a stationary finger that starts moving, the - * hysteresis margin is M in both directions. Once we start moving - * continuously though, the margin is 0 in the movement direction and 2*M to - * change direction. That makes the finger less responsive to directional - * changes than to the original movement. - * * @param in The input coordinate * @param center Current center of the hysteresis * @param margin Hysteresis width (on each side) * * @return The new center of the hysteresis */ -static inline int -evdev_hysteresis(int in, int center, int margin) +static inline struct device_coords +evdev_hysteresis(const struct device_coords *in, + const struct device_coords *center, + const struct device_coords *margin) { - int diff = in - center; - if (abs(diff) <= margin) - return center; - - if (diff > 0) - return in - margin; - else - return in + margin; + int dx = in->x - center->x; + int dy = in->y - center->y; + int dx2 = dx * dx; + int dy2 = dy * dy; + int a = margin->x; + int b = margin->y; + double normalized_finger_distance, finger_distance, margin_distance; + double lag_x, lag_y; + struct device_coords result; + + if (!a || !b) + return *in; + + /* + * Basic equation for an ellipse of radii a,b: + * x²/a² + y²/b² = 1 + * But we start by making a scaled ellipse passing through the + * relative finger location (dx,dy). So the scale of this ellipse is + * the ratio of finger_distance to margin_distance: + * dx²/a² + dy²/b² = normalized_finger_distance² + */ + normalized_finger_distance = sqrt((double)dx2 / (a * a) + + (double)dy2 / (b * b)); + + /* Which means anything less than 1 is within the elliptical margin */ + if (normalized_finger_distance < 1.0) + return *center; + + finger_distance = sqrt(dx2 + dy2); + margin_distance = finger_distance / normalized_finger_distance; + + /* + * Now calculate the x,y coordinates on the edge of the margin ellipse + * where it intersects the finger vector. Shortcut: We achieve this by + * finding the point with the same gradient as dy/dx. + */ + if (dx) { + double gradient = (double)dy / dx; + lag_x = margin_distance / sqrt(gradient * gradient + 1); + lag_y = sqrt((margin_distance + lag_x) * + (margin_distance - lag_x)); + } else { /* Infinite gradient */ + lag_x = 0.0; + lag_y = margin_distance; + } + + /* + * 'result' is the centre of an ellipse (radii a,b) which has been + * dragged by the finger moving inside it to 'in'. The finger is now + * touching the margin ellipse at some point: (±lag_x,±lag_y) + */ + result.x = (dx >= 0) ? in->x - lag_x : in->x + lag_x; + result.y = (dy >= 0) ? in->y - lag_y : in->y + lag_y; + return result; } static inline struct libinput * diff -Nru libinput-1.10.1/src/evdev-mt-touchpad.c libinput-1.10.3/src/evdev-mt-touchpad.c --- libinput-1.10.1/src/evdev-mt-touchpad.c 2018-02-28 00:19:45.000000000 +0000 +++ libinput-1.10.3/src/evdev-mt-touchpad.c 2018-03-14 05:34:05.000000000 +0000 @@ -92,6 +92,10 @@ double distance; double speed; + /* Don't do this on single-touch or semi-mt devices */ + if (!tp->has_mt || tp->semi_mt) + return; + /* This doesn't kick in until we have at least 4 events in the * motion history. As a side-effect, this automatically handles the * 2fg scroll where a finger is down and moving fast before the @@ -131,46 +135,75 @@ t->history.index = motion_index; } +/* Idea: if we got a tuple of *very* quick moves like {Left, Right, + * Left}, or {Right, Left, Right}, it means touchpad jitters since no + * human can move like that within thresholds. + * + * We encode left moves as zeroes, and right as ones. We also drop + * the array to all zeroes when contraints are not satisfied. Then we + * search for the pattern {1,0,1}. It can't match {Left, Right, Left}, + * but it does match {Left, Right, Left, Right}, so it's okay. + * + * This only looks at x changes, y changes are ignored. + */ static inline void -tp_maybe_disable_hysteresis(struct tp_dispatch *tp, uint64_t time) +tp_detect_wobbling(struct tp_dispatch *tp, + struct tp_touch *t, + uint64_t time) { - /* If the finger is down for 80ms without seeing motion events, - the firmware filters and we don't need a software hysteresis */ - if (tp->nfingers_down >= 1 && - time - tp->hysteresis.last_motion_time > ms2us(80)) { - tp->hysteresis.enabled = false; - evdev_log_debug(tp->device, "hysteresis disabled\n"); + int dx, dy; + uint64_t dtime; + + if (!(tp->queued & TOUCHPAD_EVENT_MOTION) || tp->hysteresis.enabled) return; + + if (t->last_point.x == 0) { /* first invocation */ + dx = 0; + dy = 0; + } else { + dx = t->last_point.x - t->point.x; + dy = t->last_point.y - t->point.y; } - if (tp->queued & TOUCHPAD_EVENT_MOTION) - tp->hysteresis.last_motion_time = time; + dtime = time - tp->hysteresis.last_motion_time; + + tp->hysteresis.last_motion_time = time; + t->last_point = t->point; + + if (dx == 0 && dy != 0) /* ignore y-only changes */ + return; + + if (dtime > ms2us(40)) { + t->hysteresis.x_motion_history = 0; + return; + } + + t->hysteresis.x_motion_history >>= 1; + if (dx > 0) { /* right move */ + static const char r_l_r = 0x5; /* {Right, Left, Right} */ + + + t->hysteresis.x_motion_history |= (1 << 2); + if (t->hysteresis.x_motion_history == r_l_r) { + tp->hysteresis.enabled = true; + evdev_log_debug(tp->device, "hysteresis enabled\n"); + } + } } static inline void tp_motion_hysteresis(struct tp_dispatch *tp, struct tp_touch *t) { - int x = t->point.x, - y = t->point.y; - if (!tp->hysteresis.enabled) return; - if (t->history.count == 0) { - t->hysteresis_center = t->point; - } else { - x = evdev_hysteresis(x, - t->hysteresis_center.x, - tp->hysteresis.margin.x); - y = evdev_hysteresis(y, - t->hysteresis_center.y, - tp->hysteresis.margin.y); - t->hysteresis_center.x = x; - t->hysteresis_center.y = y; - t->point.x = x; - t->point.y = y; - } + if (t->history.count > 0) + t->point = evdev_hysteresis(&t->point, + &t->hysteresis.center, + &tp->hysteresis.margin); + + t->hysteresis.center = t->point; } static inline void @@ -276,6 +309,7 @@ t->time = time; t->speed.last_speed = 0; t->speed.exceeded_count = 0; + t->hysteresis.x_motion_history = 0; tp->queued |= TOUCHPAD_EVENT_MOTION; } @@ -297,22 +331,68 @@ } /** - * End a touch, even if the touch sequence is still active. + * Schedule a touch to be ended, based on either the events or some + * attributes of the touch (size, pressure). In some cases we need to + * resurrect a touch that has ended, so this doesn't actually end the touch + * yet. All the TOUCH_MAYBE_END touches get properly ended once the device + * state has been processed once and we know how many zombie touches we + * need. */ static inline void -tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) +tp_maybe_end_touch(struct tp_dispatch *tp, + struct tp_touch *t, + uint64_t time) { switch (t->state) { - case TOUCH_HOVERING: - t->state = TOUCH_NONE; - /* fallthough */ case TOUCH_NONE: + case TOUCH_MAYBE_END: + return; case TOUCH_END: + evdev_log_bug_libinput(tp->device, + "touch already in TOUCH_END\n"); return; + case TOUCH_HOVERING: case TOUCH_BEGIN: case TOUCH_UPDATE: break; + } + + if (t->state != TOUCH_HOVERING) { + assert(tp->nfingers_down >= 1); + tp->nfingers_down--; + t->state = TOUCH_MAYBE_END; + } else { + t->state = TOUCH_NONE; + } + + t->dirty = true; +} +/** + * Inverse to tp_maybe_end_touch(), restores a touch back to its previous + * state. + */ +static inline void +tp_recover_ended_touch(struct tp_dispatch *tp, + struct tp_touch *t) +{ + t->dirty = true; + t->state = TOUCH_UPDATE; + tp->nfingers_down++; +} + +/** + * End a touch, even if the touch sequence is still active. + * Use tp_maybe_end_touch() instead. + */ +static inline void +tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) +{ + if (t->state != TOUCH_MAYBE_END) { + evdev_log_bug_libinput(tp->device, + "touch should be MAYBE_END, is %d\n", + t->state); + return; } t->dirty = true; @@ -321,8 +401,6 @@ t->pinned.is_pinned = false; t->time = time; t->palm.time = 0; - assert(tp->nfingers_down >= 1); - tp->nfingers_down--; tp->queued |= TOUCHPAD_EVENT_MOTION; } @@ -333,7 +411,7 @@ tp_end_sequence(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) { t->has_ended = true; - tp_end_touch(tp, t, time); + tp_maybe_end_touch(tp, t, time); } static void @@ -480,13 +558,11 @@ for (i = 0; i < tp->num_slots; i++) { struct tp_touch *t = tp_get_touch(tp, i); - if (t->state != TOUCH_END) + if (t->state != TOUCH_MAYBE_END) continue; /* new touch, move it through begin to update immediately */ - tp_new_touch(tp, t, time); - tp_begin_touch(tp, t, time); - t->state = TOUCH_UPDATE; + tp_recover_ended_touch(tp, t); } } @@ -1070,11 +1146,13 @@ tp_motion_history_reset(t); tp_begin_touch(tp, t, time); } - } else { + /* don't unhover for pressure if we have too many + * fake fingers down, see comment below */ + } else if (nfake_touches <= tp->num_slots) { if (t->pressure < tp->pressure.low) { evdev_log_debug(tp->device, "pressure: end touch\n"); - tp_end_touch(tp, t, time); + tp_maybe_end_touch(tp, t, time); } } } @@ -1111,10 +1189,11 @@ t = tp_get_touch(tp, i); if (t->state == TOUCH_HOVERING || - t->state == TOUCH_NONE) + t->state == TOUCH_NONE || + t->state == TOUCH_MAYBE_END) continue; - tp_end_touch(tp, t, time); + tp_maybe_end_touch(tp, t, time); if (real_fingers_down > 0 && tp->nfingers_down == nfake_touches) @@ -1156,7 +1235,7 @@ if (t->major < low || t->minor < low) { evdev_log_debug(tp->device, "touch-size: end touch\n"); - tp_end_touch(tp, t, time); + tp_maybe_end_touch(tp, t, time); } } } @@ -1210,7 +1289,7 @@ t->state == TOUCH_NONE) continue; - tp_end_touch(tp, t, time); + tp_maybe_end_touch(tp, t, time); if (tp_fake_finger_is_touching(tp) && tp->nfingers_down == nfake_touches) @@ -1378,6 +1457,21 @@ } static void +tp_pre_process_state(struct tp_dispatch *tp, uint64_t time) +{ + struct tp_touch *t; + + tp_process_fake_touches(tp, time); + tp_unhover_touches(tp, time); + + tp_for_each_touch(tp, t) { + if (t->state == TOUCH_MAYBE_END) + tp_end_touch(tp, t, time); + } + +} + +static void tp_process_state(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *t; @@ -1386,8 +1480,6 @@ bool have_new_touch = false; unsigned int speed_exceeded_count = 0; - tp_process_fake_touches(tp, time); - tp_unhover_touches(tp, time); tp_position_fake_touches(tp); want_motion_reset = tp_need_motion_history_reset(tp); @@ -1422,7 +1514,7 @@ tp_thumb_detect(tp, t, time); tp_palm_detect(tp, t, time); - + tp_detect_wobbling(tp, t, time); tp_motion_hysteresis(tp, t); tp_motion_history_push(t); @@ -1546,9 +1638,7 @@ tp_handle_state(struct tp_dispatch *tp, uint64_t time) { - if (tp->hysteresis.enabled) - tp_maybe_disable_hysteresis(tp, time); - + tp_pre_process_state(tp, time); tp_process_state(tp, time); tp_post_events(tp, time); tp_post_process_state(tp, time); @@ -2938,7 +3028,7 @@ res_y = tp->device->abs.absinfo_y->resolution; tp->hysteresis.margin.x = res_x/2; tp->hysteresis.margin.y = res_y/2; - tp->hysteresis.enabled = true; + tp->hysteresis.enabled = false; } static void @@ -2997,7 +3087,9 @@ tp->pressure.low = lo; evdev_log_debug(device, - "using pressure-based touch detection\n"); + "using pressure-based touch detection (%d:%d)\n", + lo, + hi); } static bool diff -Nru libinput-1.10.1/src/evdev-mt-touchpad-edge-scroll.c libinput-1.10.3/src/evdev-mt-touchpad-edge-scroll.c --- libinput-1.10.1/src/evdev-mt-touchpad-edge-scroll.c 2018-02-28 00:19:45.000000000 +0000 +++ libinput-1.10.3/src/evdev-mt-touchpad-edge-scroll.c 2018-03-14 05:34:05.000000000 +0000 @@ -362,6 +362,13 @@ case TOUCH_UPDATE: tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_MOTION); break; + case TOUCH_MAYBE_END: + /* This shouldn't happen we transfer to TOUCH_END + * before processing state */ + evdev_log_debug(tp->device, + "touch unexpected state %d\n", + t->state); + /* fallthrough */ case TOUCH_END: tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_RELEASE); break; diff -Nru libinput-1.10.1/src/evdev-mt-touchpad.h libinput-1.10.3/src/evdev-mt-touchpad.h --- libinput-1.10.1/src/evdev-mt-touchpad.h 2018-02-28 00:19:45.000000000 +0000 +++ libinput-1.10.3/src/evdev-mt-touchpad.h 2018-03-14 05:34:05.000000000 +0000 @@ -46,10 +46,11 @@ enum touch_state { TOUCH_NONE = 0, - TOUCH_HOVERING, - TOUCH_BEGIN, - TOUCH_UPDATE, - TOUCH_END + TOUCH_HOVERING = 1, + TOUCH_BEGIN = 2, + TOUCH_UPDATE = 3, + TOUCH_MAYBE_END = 4, + TOUCH_END = 5, }; enum touch_palm_state { @@ -147,6 +148,7 @@ bool has_ended; /* TRACKING_ID == -1 */ bool dirty; struct device_coords point; + struct device_coords last_point; uint64_t time; int pressure; bool is_tool_palm; /* MT_TOOL_PALM */ @@ -173,7 +175,10 @@ unsigned int count; } history; - struct device_coords hysteresis_center; + struct { + struct device_coords center; + uint8_t x_motion_history; + } hysteresis; /* A pinned touchpoint is the one that pressed the physical button * on a clickpad. After the release, it won't move until the center diff -Nru libinput-1.10.1/test/test-touchpad.c libinput-1.10.3/test/test-touchpad.c --- libinput-1.10.1/test/test-touchpad.c 2018-02-28 00:19:45.000000000 +0000 +++ libinput-1.10.3/test/test-touchpad.c 2018-03-14 05:34:05.000000000 +0000 @@ -5423,6 +5423,72 @@ } END_TEST +START_TEST(touchpad_pressure_btntool) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct axis_replacement axes[] = { + { ABS_MT_PRESSURE, 5 }, + { ABS_PRESSURE, 5 }, + { -1, 0 } + }; + + /* we only have tripletap, can't test 4 slots because nothing will + * happen */ + if (libevdev_get_num_slots(dev->evdev) != 2) + return; + + if (!touchpad_has_pressure(dev)) + return; + + litest_enable_tap(dev->libinput_device); + litest_drain_events(li); + + /* Two light touches down, doesn't count */ + litest_touch_down_extended(dev, 0, 40, 50, axes); + litest_touch_down_extended(dev, 1, 45, 50, axes); + libinput_dispatch(li); + litest_assert_empty_queue(li); + + /* Tripletap but since no finger is logically down, it doesn't count */ + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0); + litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_assert_empty_queue(li); + + /* back to two fingers */ + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1); + litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + + /* make one finger real */ + litest_touch_move_to(dev, 0, 40, 50, 41, 52, 10, 10); + litest_drain_events(li); + + /* tripletap should now be 3 fingers tap */ + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0); + litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1); + litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + + litest_timeout_tap(); + libinput_dispatch(li); + + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_RELEASED); +} +END_TEST + static inline bool touchpad_has_touch_size(struct litest_device *dev) { @@ -5805,7 +5871,8 @@ litest_add("touchpad:pressure", touchpad_pressure_2fg_st, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); litest_add("touchpad:pressure", touchpad_pressure_tap, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:pressure", touchpad_pressure_tap_2fg, LITEST_TOUCHPAD, LITEST_ANY); - litest_add("touchpad:pressure", touchpad_pressure_tap_2fg_1fg_light, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:pressure", touchpad_pressure_tap_2fg_1fg_light, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:pressure", touchpad_pressure_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("touchpad:touch-size", touchpad_touch_size, LITEST_APPLE_CLICKPAD, LITEST_ANY); litest_add("touchpad:touch-size", touchpad_touch_size_2fg, LITEST_APPLE_CLICKPAD, LITEST_ANY); diff -Nru libinput-1.10.1/test/test-touchpad-tap.c libinput-1.10.3/test/test-touchpad-tap.c --- libinput-1.10.1/test/test-touchpad-tap.c 2018-02-28 00:19:45.000000000 +0000 +++ libinput-1.10.3/test/test-touchpad-tap.c 2018-03-14 05:34:05.000000000 +0000 @@ -1591,13 +1591,19 @@ } END_TEST -START_TEST(touchpad_3fg_tap_hover_btntool) +START_TEST(touchpad_3fg_tap_pressure_btntool) { struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; - if (libevdev_get_abs_maximum(dev->evdev, - ABS_MT_SLOT) >= 2) + if (libevdev_get_abs_maximum(dev->evdev, ABS_MT_SLOT) >= 2) + return; + + /* libinput doesn't export when it uses pressure detection, so we + * need to reconstruct this here. Specifically, semi-mt devices are + * non-mt in libinput, so if they have ABS_PRESSURE, they'll use it. + */ + if (!libevdev_has_event_code(dev->evdev, EV_ABS, ABS_MT_PRESSURE)) return; litest_enable_tap(dev->libinput_device); @@ -1616,6 +1622,65 @@ /* drop below the pressure threshold in the same frame as starting a */ litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 3); litest_event(dev, EV_ABS, ABS_PRESSURE, 3); + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0); + litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + + litest_push_event_frame(dev); + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1); + litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0); + litest_pop_event_frame(dev); + + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + libinput_dispatch(li); + litest_timeout_tap(); + libinput_dispatch(li); + + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_RELEASED); +} +END_TEST + +START_TEST(touchpad_3fg_tap_hover_btntool) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + if (libevdev_get_abs_maximum(dev->evdev, ABS_MT_SLOT) >= 2) + return; + + /* libinput doesn't export when it uses pressure detection, so we + * need to reconstruct this here. Specifically, semi-mt devices are + * non-mt in libinput, so if they have ABS_PRESSURE, they'll use it. + */ + if (libevdev_has_event_code(dev->evdev, EV_ABS, ABS_MT_PRESSURE)) + return; + + if (libevdev_has_property(dev->evdev, INPUT_PROP_SEMI_MT) && + libevdev_has_event_code(dev->evdev, EV_ABS, ABS_PRESSURE)) + return; + + litest_enable_tap(dev->libinput_device); + litest_enable_edge_scroll(dev); + + litest_drain_events(li); + + litest_touch_down(dev, 0, 50, 50); + litest_touch_down(dev, 1, 70, 50); + libinput_dispatch(li); + + litest_touch_move_to(dev, 0, 50, 50, 50, 70, 10, 0); + litest_touch_move_to(dev, 1, 70, 50, 50, 70, 10, 0); + litest_drain_events(li); + + /* drop below the pressure threshold in the same frame as starting a + * third touch */ litest_event(dev, EV_KEY, BTN_TOUCH, 0); litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0); litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1); @@ -3316,6 +3381,7 @@ litest_add("tap-3fg:3fg", touchpad_3fg_tap_tap_again, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("tap-3fg:3fg", touchpad_3fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("tap-3fg:3fg", touchpad_3fg_tap_hover_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("tap-3fg:3fg", touchpad_3fg_tap_pressure_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add_for_device("tap-3fg:3fg", touchpad_3fg_tap_btntool_pointerjump, LITEST_SYNAPTICS_TOPBUTTONPAD); litest_add("tap-4fg:4fg", touchpad_4fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); litest_add("tap-4fg:4fg", touchpad_4fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); diff -Nru libinput-1.10.1/udev/90-libinput-model-quirks.hwdb libinput-1.10.3/udev/90-libinput-model-quirks.hwdb --- libinput-1.10.1/udev/90-libinput-model-quirks.hwdb 2018-02-28 00:19:45.000000000 +0000 +++ libinput-1.10.3/udev/90-libinput-model-quirks.hwdb 2018-03-14 05:34:05.000000000 +0000 @@ -59,8 +59,10 @@ libinput:mouse:input:b0005v05ACp030D* LIBINPUT_MODEL_APPLE_MAGICMOUSE=1 +# Magic Trackpad libinput:touchpad:input:b0005v05ACp030E* LIBINPUT_ATTR_SIZE_HINT=130x110 + LIBINPUT_ATTR_TOUCH_SIZE_RANGE=60:40 libinput:touchpad:input:b0003v05ACp021A* LIBINPUT_MODEL_APPLE_TOUCHPAD_ONEBUTTON=1