mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-03-21 16:50:42 +01:00
Merge branch '2026-thumb-regression-fixes' into 'main'
Draft: touchpad: restore thumb rejection/suppression Closes #1191 See merge request libinput/libinput!1439
This commit is contained in:
commit
62bf4bb1cd
2 changed files with 176 additions and 3 deletions
|
|
@ -192,6 +192,34 @@ tp_thumb_revive(struct tp_dispatch *tp, struct tp_touch *t)
|
|||
tp_thumb_set_state(tp, t, THUMB_STATE_REVIVED);
|
||||
}
|
||||
|
||||
/* Intelligently reset thumb state... Unlike tp_thumb_lift(), this
|
||||
* pays attention to suppression/revival/jailed states so that a thumb
|
||||
* can't be revived more than once.
|
||||
*/
|
||||
static void
|
||||
tp_thumb_reevaluate(struct tp_dispatch *tp)
|
||||
{
|
||||
switch (tp->thumb.state) {
|
||||
case THUMB_STATE_FINGER:
|
||||
break;
|
||||
case THUMB_STATE_JAILED:
|
||||
case THUMB_STATE_PINCH:
|
||||
tp->thumb.state = THUMB_STATE_FINGER;
|
||||
tp->thumb.index = UINT_MAX;
|
||||
break;
|
||||
case THUMB_STATE_SUPPRESSED: {
|
||||
struct tp_touch *thumb = tp_thumb_get_touch(tp);
|
||||
if (thumb)
|
||||
tp_thumb_revive(tp, thumb);
|
||||
break;
|
||||
}
|
||||
case THUMB_STATE_REVIVED:
|
||||
case THUMB_STATE_REVIVED_JAILED:
|
||||
case THUMB_STATE_DEAD:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tp_thumb_update_touch(struct tp_dispatch *tp, struct tp_touch *t, usec_t time)
|
||||
{
|
||||
|
|
@ -326,7 +354,7 @@ tp_thumb_update_multifinger(struct tp_dispatch *tp)
|
|||
*/
|
||||
|
||||
if (mm.x < SCROLL_MM_X && mm.y < SCROLL_MM_Y) {
|
||||
tp_thumb_lift(tp);
|
||||
tp_thumb_reevaluate(tp);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -341,7 +369,7 @@ tp_thumb_update_multifinger(struct tp_dispatch *tp)
|
|||
usec_t delta = usec_delta(newest->initial_time, oldest->initial_time);
|
||||
if (usec_cmp(delta, THUMB_TIMEOUT) < 0 &&
|
||||
first->point.y < tp->thumb.lower_thumb_line) {
|
||||
tp_thumb_lift(tp);
|
||||
tp_thumb_reevaluate(tp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -357,7 +385,7 @@ tp_thumb_update_multifinger(struct tp_dispatch *tp)
|
|||
else
|
||||
tp_thumb_suppress(tp, first);
|
||||
} else {
|
||||
tp_thumb_lift(tp);
|
||||
tp_thumb_reevaluate(tp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5459,6 +5459,149 @@ START_TEST(touchpad_thumb_no_doublethumb)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_thumb_no_double_revive)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
if (!has_thumb_detect(dev))
|
||||
return LITEST_NOT_APPLICABLE;
|
||||
|
||||
litest_disable_tap(dev->libinput_device);
|
||||
litest_disable_hold_gestures(dev->libinput_device);
|
||||
|
||||
if (litest_has_clickfinger(dev))
|
||||
litest_enable_clickfinger(dev);
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
/* 1. Thumb rests in thumb area, starts as JAILED */
|
||||
litest_touch_down(dev, 0, 50, 99);
|
||||
litest_touch_move_to(dev, 0, 50, 99, 51, 99, 10);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
/* 2. Finger touches far from thumb, makes a small movement
|
||||
* Thumb becomes SUPPRESSED
|
||||
*/
|
||||
msleep(200);
|
||||
litest_dispatch(li);
|
||||
litest_touch_down(dev, 1, 50, 0);
|
||||
litest_dispatch(li);
|
||||
litest_touch_move_to(dev, 1, 50, 0, 51, 1, 10);
|
||||
litest_dispatch(li);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* 3. Lift the finger. Thumb is still on TP
|
||||
*/
|
||||
litest_touch_up(dev, 1);
|
||||
litest_dispatch(li);
|
||||
msleep(200);
|
||||
|
||||
/* 4. Move the thumb significantly so it becomes REVIVED. We should
|
||||
* now see pointer motion events.
|
||||
*/
|
||||
litest_touch_move_to(dev, 0, 51, 99, 80, 70, 20);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
/* 5. A second finger touches & moves far away again.
|
||||
* Thumb should become DEAD.
|
||||
*/
|
||||
msleep(200);
|
||||
litest_dispatch(li);
|
||||
litest_touch_down(dev, 1, 50, 0);
|
||||
litest_dispatch(li);
|
||||
litest_touch_move_to(dev, 1, 50, 0, 80, 1, 8);
|
||||
litest_dispatch(li);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* 6. Lift the second finger */
|
||||
litest_touch_up(dev, 1);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* 7. Move the thumb again. It must now be DEAD!
|
||||
* Should not show any motion
|
||||
*/
|
||||
litest_touch_move_to(dev, 0, 80, 70, 50, 30, 30);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_touch_up(dev, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_thumb_no_revive_after_ghost_touch)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
if (!has_thumb_detect(dev))
|
||||
return LITEST_NOT_APPLICABLE;
|
||||
|
||||
litest_disable_tap(dev->libinput_device);
|
||||
litest_disable_hold_gestures(dev->libinput_device);
|
||||
|
||||
if (litest_has_clickfinger(dev))
|
||||
litest_enable_clickfinger(dev);
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
/* 1. Thumb rests in thumb area at bottom center */
|
||||
litest_touch_down(dev, 0, 45, 97);
|
||||
litest_touch_move_to(dev, 0, 45, 97, 45, 97, 10);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
/* 2. Finger touches far above thumb and scrolls up */
|
||||
msleep(200);
|
||||
litest_dispatch(li);
|
||||
litest_touch_down(dev, 1, 46, 41);
|
||||
litest_dispatch(li);
|
||||
litest_touch_move_to(dev, 1, 46, 41, 49, 14, 15);
|
||||
litest_dispatch(li);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* 3. Lift the scroll finger */
|
||||
litest_touch_up(dev, 1);
|
||||
litest_dispatch(li);
|
||||
msleep(340);
|
||||
|
||||
/* 4. Move the thumb significantly — it should become REVIVED */
|
||||
litest_touch_move_to(dev, 0, 45, 97, 50, 83, 20);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
/* 5. Ghost touch: a single-frame phantom contact very close to
|
||||
* the thumb, as seen in real hardware recording. The ghost
|
||||
* appears while the thumb is actively moving and disappears
|
||||
* within one frame.
|
||||
*/
|
||||
litest_touch_down(dev, 1, 52, 87);
|
||||
litest_dispatch(li);
|
||||
litest_touch_up(dev, 1);
|
||||
litest_dispatch(li);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* 6. Real second finger arrives and scrolls */
|
||||
msleep(234);
|
||||
litest_dispatch(li);
|
||||
litest_touch_down(dev, 1, 53, 44);
|
||||
litest_dispatch(li);
|
||||
litest_touch_move_to(dev, 1, 53, 44, 51, 11, 15);
|
||||
litest_dispatch(li);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* 7. Lift the real second finger */
|
||||
litest_touch_up(dev, 1);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* 8. Move the thumb again. After the ghost touch triggered a
|
||||
* spurious state reset and a real second finger followed,
|
||||
* the thumb must be DEAD and produce no motion.
|
||||
*/
|
||||
litest_touch_move_to(dev, 0, 50, 83, 60, 55, 30);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_touch_up(dev, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_tool_tripletap_touch_count)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -7169,6 +7312,8 @@ TEST_COLLECTION(touchpad)
|
|||
litest_add(touchpad_thumb_area_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
|
||||
litest_add(touchpad_thumb_area_btnarea, LITEST_CLICKPAD, LITEST_ANY);
|
||||
litest_add(touchpad_thumb_no_doublethumb, LITEST_CLICKPAD, LITEST_ANY);
|
||||
litest_add(touchpad_thumb_no_double_revive, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT);
|
||||
litest_add(touchpad_thumb_no_revive_after_ghost_touch, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT);
|
||||
|
||||
litest_add_for_device(touchpad_tool_tripletap_touch_count, LITEST_SYNAPTICS_TOPBUTTONPAD);
|
||||
litest_add_for_device(touchpad_tool_tripletap_touch_count_late, LITEST_SYNAPTICS_TOPBUTTONPAD);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue