mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-25 05:50:05 +01:00
touchpad: handle serial synaptics slot confusion on TRIPLETAP
Synatics touchpads only have 2 slots, but support TRIPLETAP and above. When the third finger touches, the kernel may end the second slot and re-start it with the coordinates of the third touch in the next frame. The event sequence is something like: ABS_MT_SLOT 0 ABS_MT_POSITION_X 4000 ABS_MT_POSITION_Y 4000 ABS_MT_PRESSURE 78 ABS_MT_SLOT 1 ABS_MT_TRACKING_ID -1 ABS_X 4000 ABS_Y 4000 ABS_PRESSURE 78 BTN_TOOL_DOUBLETAP 0 BTN_TOOL_TRIPLETAP 1 --- SYN_REPORT (0) ---------- ABS_MT_SLOT 0 ABS_MT_POSITION_X 4000 ABS_MT_POSITION_Y 4000 ABS_MT_PRESSURE 78 ABS_MT_SLOT 1 ABS_MT_TRACKING_ID 55 ABS_MT_POSITION_X 2000 ABS_MT_POSITION_Y 2000 ABS_MT_PRESSURE 72 ABS_X 4000 ABS_Y 4000 ABS_PRESSURE 78 --- SYN_REPORT (0) ---------- libinput usually ignores any BTN_TOOL_* <= num_slots since we expect that the slot values are valid. Make an exception for the serial synaptics touchpads. If a touch has ended when the fake touch goes above active-slots (but still within num-slots), move that touch back to UPDATE. This ensures the right number of nfingers_down. When the touch restarts again in the next frame, tp_begin_touch() will skip over re-initializing it because it's already in UPDATE anyway. Note that at this point this only handles the transition _to_ TRIPLETAP, not from TRIPLETAP to DOUBLETAP. Need to wait for this to be seen in the wild first. https://bugs.freedesktop.org/show_bug.cgi?id=91352 Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Hallelujah-expressed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Reviewed-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
parent
ab016fd8ed
commit
d4ceb671b9
2 changed files with 154 additions and 0 deletions
|
|
@ -341,6 +341,40 @@ tp_process_absolute_st(struct tp_dispatch *tp,
|
|||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
tp_restore_synaptics_touches(struct tp_dispatch *tp,
|
||||
uint64_t time)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int nfake_touches;
|
||||
|
||||
nfake_touches = tp_fake_finger_count(tp);
|
||||
if (nfake_touches < 3)
|
||||
return;
|
||||
|
||||
if (tp->nfingers_down >= nfake_touches ||
|
||||
tp->nfingers_down == tp->num_slots)
|
||||
return;
|
||||
|
||||
/* Synaptics devices may end touch 2 on BTN_TOOL_TRIPLETAP
|
||||
* and start it again on the next frame with different coordinates
|
||||
* (#91352). We search the touches we have, if there is one that has
|
||||
* just ended despite us being on tripletap, we move it back to
|
||||
* update.
|
||||
*/
|
||||
for (i = 0; i < tp->num_slots; i++) {
|
||||
struct tp_touch *t = tp_get_touch(tp, i);
|
||||
|
||||
if (t->state != TOUCH_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;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_process_fake_touches(struct tp_dispatch *tp,
|
||||
uint64_t time)
|
||||
|
|
@ -353,6 +387,10 @@ tp_process_fake_touches(struct tp_dispatch *tp,
|
|||
if (nfake_touches == FAKE_FINGER_OVERFLOW)
|
||||
return;
|
||||
|
||||
if (tp->device->model_flags &
|
||||
EVDEV_MODEL_SYNAPTICS_SERIAL_TOUCHPAD)
|
||||
tp_restore_synaptics_touches(tp, time);
|
||||
|
||||
start = tp->has_mt ? tp->num_slots : 0;
|
||||
for (i = start; i < tp->ntouches; i++) {
|
||||
t = tp_get_touch(tp, i);
|
||||
|
|
|
|||
116
test/touchpad.c
116
test/touchpad.c
|
|
@ -4279,6 +4279,120 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg_tap)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_tool_tripletap_touch_count)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_pointer *ptrev;
|
||||
|
||||
/* Synaptics touchpads sometimes end one touch point while
|
||||
* simultaneously setting BTN_TOOL_TRIPLETAP.
|
||||
* https://bugs.freedesktop.org/show_bug.cgi?id=91352
|
||||
*/
|
||||
litest_drain_events(li);
|
||||
enable_clickfinger(dev);
|
||||
|
||||
/* touch 1 down */
|
||||
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
|
||||
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, 1);
|
||||
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 1200);
|
||||
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 3200);
|
||||
litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 78);
|
||||
litest_event(dev, EV_ABS, ABS_X, 1200);
|
||||
litest_event(dev, EV_ABS, ABS_Y, 3200);
|
||||
litest_event(dev, EV_ABS, ABS_PRESSURE, 78);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1);
|
||||
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
msleep(2);
|
||||
|
||||
/* touch 2 down */
|
||||
litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
|
||||
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, 1);
|
||||
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 2200);
|
||||
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 3200);
|
||||
litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 73);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
msleep(2);
|
||||
|
||||
/* touch 3 down, coordinate jump + ends slot 1 */
|
||||
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
|
||||
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 4000);
|
||||
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 4000);
|
||||
litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 78);
|
||||
litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
|
||||
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
|
||||
litest_event(dev, EV_ABS, ABS_X, 4000);
|
||||
litest_event(dev, EV_ABS, ABS_Y, 4000);
|
||||
litest_event(dev, EV_ABS, ABS_PRESSURE, 78);
|
||||
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);
|
||||
msleep(2);
|
||||
|
||||
/* slot 2 reactivated:
|
||||
* Note, slot is activated close enough that we don't accidentally
|
||||
* trigger the clickfinger distance check, remains to be seen if
|
||||
* that is true for real-world interaction.
|
||||
*/
|
||||
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
|
||||
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 4000);
|
||||
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 4000);
|
||||
litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 78);
|
||||
litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
|
||||
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, 3);
|
||||
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 3500);
|
||||
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 3500);
|
||||
litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 73);
|
||||
litest_event(dev, EV_ABS, ABS_X, 4000);
|
||||
litest_event(dev, EV_ABS, ABS_Y, 4000);
|
||||
litest_event(dev, EV_ABS, ABS_PRESSURE, 78);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
msleep(2);
|
||||
|
||||
/* now a click should trigger middle click */
|
||||
litest_event(dev, EV_KEY, BTN_LEFT, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
litest_event(dev, EV_KEY, BTN_LEFT, 0);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_wait_for_event(li);
|
||||
event = libinput_get_event(li);
|
||||
ptrev = litest_is_button_event(event,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
libinput_event_destroy(event);
|
||||
event = libinput_get_event(li);
|
||||
ptrev = litest_is_button_event(event,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
/* silence gcc set-but-not-used warning, litest_is_button_event
|
||||
* checks what we care about */
|
||||
event = libinput_event_pointer_get_base_event(ptrev);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
/* release everything */
|
||||
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
|
||||
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
|
||||
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
|
||||
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0);
|
||||
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void
|
||||
litest_setup_tests(void)
|
||||
{
|
||||
|
|
@ -4413,4 +4527,6 @@ litest_setup_tests(void)
|
|||
litest_add("touchpad:thumb", touchpad_thumb_tap_hold, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
|
||||
litest_add_for_device("touchpad:bugs", touchpad_tool_tripletap_touch_count, LITEST_SYNAPTICS_TOPBUTTONPAD);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue