mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-04 09:20:29 +01:00
touchpad: touches after the last key press can be released
The current code labels a touch as palm if it started within the typing timeouts. To move the pointer even after the timeout expires, a user has to lift the finger which is quite annoying and different to the old synaptics driver behaviour (which had a simple on/off toggle on whether to let events through or not). Be smarter about this: if a touch starts _after_ the last key press event, release it for pointer motion once the timeout expires. Touches started before the last key press remain labelled as palms. This makes it possible to rest the palm on the touchpad while typing without getting interference but also provides a more responsive UI when moving from typing to using the touchpad normally. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Hans de Goede <hdegoede@redhat.com> Tested-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
This commit is contained in:
parent
f85a46b661
commit
0dc058a0c7
5 changed files with 169 additions and 9 deletions
|
|
@ -74,8 +74,9 @@ Notable behaviors of libinput's disable-while-typing feature:
|
|||
- Some keys do not trigger the timeout, specifically some modifier keys
|
||||
(Ctrl, Alt, Shift, and Fn). Actions such as Ctrl + click thus stay
|
||||
responsive.
|
||||
- Touches started while the touchpad is disabled do not control the cursor,
|
||||
it is thus possible to rest the palm on the touchpad while typing.
|
||||
- Touches started while typing do not control the cursor even after typing
|
||||
has stopped, it is thus possible to rest the palm on the touchpad while
|
||||
typing.
|
||||
- Physical buttons work even while the touchpad is disabled. This includes
|
||||
software-emulated buttons.
|
||||
|
||||
|
|
|
|||
|
|
@ -361,6 +361,9 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
|
|||
if (!t->dirty)
|
||||
continue;
|
||||
|
||||
if (t->palm.state != PALM_NONE)
|
||||
continue;
|
||||
|
||||
switch (t->scroll.edge) {
|
||||
case EDGE_NONE:
|
||||
if (t->scroll.direction != -1) {
|
||||
|
|
|
|||
|
|
@ -237,6 +237,7 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
|
|||
t->state = TOUCH_END;
|
||||
t->pinned.is_pinned = false;
|
||||
t->millis = time;
|
||||
t->palm.time = 0;
|
||||
assert(tp->nfingers_down >= 1);
|
||||
tp->nfingers_down--;
|
||||
tp->queued |= TOUCHPAD_EVENT_MOTION;
|
||||
|
|
@ -487,14 +488,28 @@ tp_palm_tap_is_palm(struct tp_dispatch *tp, struct tp_touch *t)
|
|||
static int
|
||||
tp_palm_detect_dwt(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
|
||||
{
|
||||
if (!tp->dwt.keyboard_active)
|
||||
return 0;
|
||||
|
||||
if (t->state == TOUCH_BEGIN) {
|
||||
if (tp->dwt.keyboard_active &&
|
||||
t->state == TOUCH_BEGIN) {
|
||||
t->palm.state = PALM_TYPING;
|
||||
t->palm.time = time;
|
||||
t->palm.first = t->point;
|
||||
return 1;
|
||||
} else if (!tp->dwt.keyboard_active &&
|
||||
t->state == TOUCH_UPDATE &&
|
||||
t->palm.state == PALM_TYPING)
|
||||
{
|
||||
/* If a touch has started before the first or after the last
|
||||
key press, release it on timeout. Benefit: a palm rested
|
||||
while typing on the touchpad will be ignored, but a touch
|
||||
started once we stop typing will be able to control the
|
||||
pointer (alas not tap, etc.).
|
||||
*/
|
||||
if (t->palm.time == 0 ||
|
||||
t->palm.time > tp->dwt.keyboard_last_press_time) {
|
||||
t->palm.state = PALM_NONE;
|
||||
log_debug(tp_libinput_context(tp),
|
||||
"palm: touch released, timeout after typing\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1002,6 +1017,7 @@ tp_keyboard_event(uint64_t time, struct libinput_event *event, void *data)
|
|||
timeout = DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_2;
|
||||
}
|
||||
|
||||
tp->dwt.keyboard_last_press_time = time;
|
||||
libinput_timer_set(&tp->dwt.keyboard_timer,
|
||||
time + timeout);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -287,6 +287,8 @@ struct tp_dispatch {
|
|||
struct libinput_event_listener keyboard_listener;
|
||||
struct libinput_timer keyboard_timer;
|
||||
struct evdev_device *keyboard;
|
||||
|
||||
uint64_t keyboard_last_press_time;
|
||||
} dwt;
|
||||
};
|
||||
|
||||
|
|
|
|||
144
test/touchpad.c
144
test/touchpad.c
|
|
@ -4646,6 +4646,45 @@ START_TEST(touchpad_dwt)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_dwt_enable_touch)
|
||||
{
|
||||
struct litest_device *touchpad = litest_current_device();
|
||||
struct litest_device *keyboard;
|
||||
struct libinput *li = touchpad->libinput;
|
||||
|
||||
if (!has_disable_while_typing(touchpad))
|
||||
return;
|
||||
|
||||
keyboard = litest_add_device(li, LITEST_KEYBOARD);
|
||||
libinput_device_config_tap_set_enabled(touchpad->libinput_device,
|
||||
LIBINPUT_CONFIG_TAP_DISABLED);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_keyboard_key(keyboard, KEY_A, true);
|
||||
litest_keyboard_key(keyboard, KEY_A, false);
|
||||
libinput_dispatch(li);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY);
|
||||
|
||||
/* finger down after last key event, but
|
||||
we're still within timeout - no events */
|
||||
msleep(10);
|
||||
litest_touch_down(touchpad, 0, 50, 50);
|
||||
litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 10, 1);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_timeout_dwt_short();
|
||||
libinput_dispatch(li);
|
||||
|
||||
/* same touch after timeout - motion events*/
|
||||
litest_touch_move_to(touchpad, 0, 70, 50, 50, 50, 10, 1);
|
||||
litest_touch_up(touchpad, 0);
|
||||
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_delete_device(keyboard);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_dwt_touch_hold)
|
||||
{
|
||||
struct litest_device *touchpad = litest_current_device();
|
||||
|
|
@ -4661,7 +4700,7 @@ START_TEST(touchpad_dwt_touch_hold)
|
|||
litest_drain_events(li);
|
||||
|
||||
litest_keyboard_key(keyboard, KEY_A, true);
|
||||
libinput_dispatch(li);
|
||||
msleep(1); /* make sure touch starts after key press */
|
||||
litest_touch_down(touchpad, 0, 50, 50);
|
||||
litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 5, 1);
|
||||
|
||||
|
|
@ -4678,7 +4717,7 @@ START_TEST(touchpad_dwt_touch_hold)
|
|||
libinput_dispatch(li);
|
||||
litest_touch_move_to(touchpad, 0, 30, 50, 50, 50, 5, 1);
|
||||
litest_touch_up(touchpad, 0);
|
||||
litest_assert_empty_queue(li);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_delete_device(keyboard);
|
||||
}
|
||||
|
|
@ -4837,6 +4876,7 @@ START_TEST(touchpad_dwt_tap_drag)
|
|||
|
||||
litest_keyboard_key(keyboard, KEY_A, true);
|
||||
libinput_dispatch(li);
|
||||
msleep(1); /* make sure touch starts after key press */
|
||||
litest_touch_down(touchpad, 0, 50, 50);
|
||||
litest_touch_up(touchpad, 0);
|
||||
litest_touch_down(touchpad, 0, 50, 50);
|
||||
|
|
@ -4849,7 +4889,7 @@ START_TEST(touchpad_dwt_tap_drag)
|
|||
libinput_dispatch(li);
|
||||
litest_touch_move_to(touchpad, 0, 70, 50, 50, 50, 5, 1);
|
||||
litest_touch_up(touchpad, 0);
|
||||
litest_assert_empty_queue(li);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_delete_device(keyboard);
|
||||
}
|
||||
|
|
@ -4887,6 +4927,101 @@ START_TEST(touchpad_dwt_click)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_dwt_edge_scroll)
|
||||
{
|
||||
struct litest_device *touchpad = litest_current_device();
|
||||
struct litest_device *keyboard;
|
||||
struct libinput *li = touchpad->libinput;
|
||||
|
||||
if (!has_disable_while_typing(touchpad))
|
||||
return;
|
||||
|
||||
enable_edge_scroll(touchpad);
|
||||
|
||||
keyboard = litest_add_device(li, LITEST_KEYBOARD);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_keyboard_key(keyboard, KEY_A, true);
|
||||
litest_keyboard_key(keyboard, KEY_A, false);
|
||||
litest_keyboard_key(keyboard, KEY_A, true);
|
||||
litest_keyboard_key(keyboard, KEY_A, false);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY);
|
||||
|
||||
litest_touch_down(touchpad, 0, 99, 20);
|
||||
libinput_dispatch(li);
|
||||
litest_timeout_edgescroll();
|
||||
libinput_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
/* edge scroll timeout is 300ms atm, make sure we don't accidentally
|
||||
exit the DWT timeout */
|
||||
litest_keyboard_key(keyboard, KEY_A, true);
|
||||
litest_keyboard_key(keyboard, KEY_A, false);
|
||||
libinput_dispatch(li);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY);
|
||||
|
||||
litest_touch_move_to(touchpad, 0, 99, 20, 99, 80, 60, 10);
|
||||
libinput_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_touch_move_to(touchpad, 0, 99, 80, 99, 20, 60, 10);
|
||||
litest_touch_up(touchpad, 0);
|
||||
libinput_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_delete_device(keyboard);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_dwt_edge_scroll_interrupt)
|
||||
{
|
||||
struct litest_device *touchpad = litest_current_device();
|
||||
struct litest_device *keyboard;
|
||||
struct libinput *li = touchpad->libinput;
|
||||
struct libinput_event_pointer *stop_event;
|
||||
|
||||
if (!has_disable_while_typing(touchpad))
|
||||
return;
|
||||
|
||||
enable_edge_scroll(touchpad);
|
||||
|
||||
keyboard = litest_add_device(li, LITEST_KEYBOARD);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_down(touchpad, 0, 99, 20);
|
||||
libinput_dispatch(li);
|
||||
litest_timeout_edgescroll();
|
||||
litest_touch_move_to(touchpad, 0, 99, 20, 99, 30, 10, 10);
|
||||
libinput_dispatch(li);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
|
||||
|
||||
litest_keyboard_key(keyboard, KEY_A, true);
|
||||
litest_keyboard_key(keyboard, KEY_A, false);
|
||||
litest_keyboard_key(keyboard, KEY_A, true);
|
||||
litest_keyboard_key(keyboard, KEY_A, false);
|
||||
|
||||
/* scroll stop event */
|
||||
litest_wait_for_event(li);
|
||||
stop_event = litest_is_axis_event(libinput_get_event(li),
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
|
||||
LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
|
||||
libinput_event_destroy(libinput_event_pointer_get_base_event(stop_event));
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY);
|
||||
|
||||
litest_timeout_dwt_long();
|
||||
|
||||
/* Known bad behavior: a touch starting to edge-scroll before dwt
|
||||
* kicks in will stop to scroll but be recognized as normal
|
||||
* pointer-moving touch once the timeout expires. We'll fix that
|
||||
* when we need to.
|
||||
*/
|
||||
litest_touch_move_to(touchpad, 0, 99, 30, 99, 80, 10, 5);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_delete_device(keyboard);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void
|
||||
litest_setup_tests(void)
|
||||
{
|
||||
|
|
@ -5037,6 +5172,7 @@ litest_setup_tests(void)
|
|||
litest_add_ranged("touchpad:state", touchpad_initial_state, LITEST_TOUCHPAD, LITEST_ANY, &axis_range);
|
||||
|
||||
litest_add("touchpad:dwt", touchpad_dwt, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:dwt", touchpad_dwt_enable_touch, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:dwt", touchpad_dwt_touch_hold, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:dwt", touchpad_dwt_key_hold, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:dwt", touchpad_dwt_type, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
|
|
@ -5044,4 +5180,6 @@ litest_setup_tests(void)
|
|||
litest_add("touchpad:dwt", touchpad_dwt_tap, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:dwt", touchpad_dwt_tap_drag, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:dwt", touchpad_dwt_click, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:dwt", touchpad_dwt_edge_scroll, LITEST_TOUCHPAD, LITEST_CLICKPAD);
|
||||
litest_add("touchpad:dwt", touchpad_dwt_edge_scroll_interrupt, LITEST_TOUCHPAD, LITEST_CLICKPAD);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue