input: improve touch handling on pointer presense

No longer inhibits touch event handling when terminal window
has pointer focus.  Instead, inhibit touch event when at least
one pointer button is held down.

This change improves user experience when using foot with both
a mouse and a touchscreen.

Closes #1428.
This commit is contained in:
CismonX 2023-08-19 23:01:53 +08:00
parent 4f3f614457
commit f0f0d02bf7
No known key found for this signature in database
GPG key ID: 3094873E29A482FB
3 changed files with 73 additions and 32 deletions

98
input.c
View file

@ -1751,6 +1751,28 @@ mouse_coord_pixel_to_cell(struct seat *seat, const struct terminal *term,
seat->mouse.row = (y - term->margins.top) / term->cell_height;
}
static bool
touch_is_active(const struct seat *seat)
{
if (seat->wl_touch == NULL) {
return false;
}
switch (seat->touch.state) {
case TOUCH_STATE_IDLE:
case TOUCH_STATE_INHIBITED:
return false;
case TOUCH_STATE_HELD:
case TOUCH_STATE_DRAGGING:
case TOUCH_STATE_SCROLLING:
return true;
}
BUG("Bad touch state: %d", seat->touch.state);
return false;
}
static void
wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, struct wl_surface *surface,
@ -1764,26 +1786,15 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
struct seat *seat = data;
if (seat->wl_touch != NULL) {
switch (seat->touch.state) {
case TOUCH_STATE_IDLE:
mouse_button_state_reset(seat);
seat->touch.state = TOUCH_STATE_INHIBITED;
break;
case TOUCH_STATE_INHIBITED:
break;
case TOUCH_STATE_HELD:
case TOUCH_STATE_DRAGGING:
case TOUCH_STATE_SCROLLING:
return;
}
}
struct wl_window *win = wl_surface_get_user_data(surface);
struct terminal *term = win->term;
seat->mouse_focus = term;
term->active_surface = term_surface_kind(term, surface);
if (touch_is_active(seat))
return;
int x = wl_fixed_to_int(surface_x) * term->scale;
int y = wl_fixed_to_int(surface_y) * term->scale;
@ -1799,9 +1810,6 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
xassert(tll_length(seat->mouse.buttons) == 0);
seat->mouse_focus = term;
term->active_surface = term_surface_kind(term, surface);
wayl_reload_xcursor_theme(seat, term->scale); /* Scale may have changed */
term_xcursor_update_for_seat(term, seat);
@ -1837,10 +1845,19 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
struct seat *seat = data;
if (seat->wl_touch != NULL) {
if (seat->touch.state != TOUCH_STATE_INHIBITED) {
switch (seat->touch.state) {
case TOUCH_STATE_IDLE:
break;
case TOUCH_STATE_INHIBITED:
seat->touch.state = TOUCH_STATE_IDLE;
break;
case TOUCH_STATE_HELD:
case TOUCH_STATE_DRAGGING:
case TOUCH_STATE_SCROLLING:
return;
}
seat->touch.state = TOUCH_STATE_IDLE;
}
struct terminal *old_moused = seat->mouse_focus;
@ -1919,7 +1936,7 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
struct seat *seat = data;
/* Touch-emulated pointer events have wl_pointer == NULL. */
if (wl_pointer != NULL && seat->touch.state != TOUCH_STATE_INHIBITED)
if (wl_pointer != NULL && touch_is_active(seat))
return;
struct wayland *wayl = seat->wayl;
@ -2147,7 +2164,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
struct seat *seat = data;
/* Touch-emulated pointer events have wl_pointer == NULL. */
if (wl_pointer != NULL && seat->touch.state != TOUCH_STATE_INHIBITED)
if (wl_pointer != NULL && touch_is_active(seat))
return;
struct wayland *wayl = seat->wayl;
@ -2162,6 +2179,10 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
bool send_to_client = false;
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
if (seat->wl_touch != NULL && seat->touch.state == TOUCH_STATE_IDLE) {
seat->touch.state = TOUCH_STATE_INHIBITED;
}
/* Time since last click */
struct timespec now, since_last;
clock_gettime(CLOCK_MONOTONIC, &now);
@ -2263,6 +2284,12 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
}
}
if (seat->wl_touch != NULL && seat->touch.state == TOUCH_STATE_INHIBITED) {
if (tll_length(seat->mouse.buttons) == 0) {
seat->touch.state = TOUCH_STATE_IDLE;
}
}
if (!have_button) {
/*
* Seen on Sway with slurp
@ -2610,7 +2637,7 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
{
struct seat *seat = data;
if (seat->touch.state != TOUCH_STATE_INHIBITED)
if (touch_is_active(seat))
return;
if (seat->mouse.have_discrete)
@ -2643,7 +2670,7 @@ wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
{
struct seat *seat = data;
if (seat->touch.state != TOUCH_STATE_INHIBITED)
if (touch_is_active(seat))
return;
seat->mouse.have_discrete = true;
@ -2663,7 +2690,7 @@ wl_pointer_frame(void *data, struct wl_pointer *wl_pointer)
{
struct seat *seat = data;
if (seat->touch.state != TOUCH_STATE_INHIBITED)
if (touch_is_active(seat))
return;
seat->mouse.have_discrete = false;
@ -2681,7 +2708,7 @@ wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
{
struct seat *seat = data;
if (seat->touch.state != TOUCH_STATE_INHIBITED)
if (touch_is_active(seat))
return;
xassert(axis < ALEN(seat->mouse.aggregated));
@ -2738,8 +2765,6 @@ wl_touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial,
struct wl_window *win = wl_surface_get_user_data(surface);
struct terminal *term = win->term;
term->active_surface = term_surface_kind(term, surface);
LOG_DBG("touch_down: touch=%p, x=%d, y=%d", (void *)wl_touch,
wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y));
@ -2754,6 +2779,7 @@ wl_touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial,
seat->touch.serial = serial;
seat->touch.time = time + term->conf->touch.long_press_delay;
seat->touch.surface = surface;
seat->touch.surface_kind = term_surface_kind(term, surface);
seat->touch.id = id;
}
@ -2771,7 +2797,10 @@ wl_touch_up(void *data, struct wl_touch *wl_touch, uint32_t serial,
struct wl_window *win = wl_surface_get_user_data(seat->touch.surface);
struct terminal *term = win->term;
struct terminal *old_term = seat->mouse_focus;
enum term_surface old_active_surface = term->active_surface;
seat->mouse_focus = term;
term->active_surface = seat->touch.surface_kind;
switch (seat->touch.state) {
case TOUCH_STATE_HELD:
@ -2793,7 +2822,8 @@ wl_touch_up(void *data, struct wl_touch *wl_touch, uint32_t serial,
break;
}
seat->mouse_focus = NULL;
seat->mouse_focus = old_term;
term->active_surface = old_active_surface;
}
static void
@ -2810,7 +2840,10 @@ wl_touch_motion(void *data, struct wl_touch *wl_touch, uint32_t time,
struct wl_window *win = wl_surface_get_user_data(seat->touch.surface);
struct terminal *term = win->term;
struct terminal *old_term = seat->mouse_focus;
enum term_surface old_active_surface = term->active_surface;
seat->mouse_focus = term;
term->active_surface = seat->touch.surface_kind;
switch (seat->touch.state) {
case TOUCH_STATE_HELD:
@ -2837,7 +2870,8 @@ wl_touch_motion(void *data, struct wl_touch *wl_touch, uint32_t time,
break;
}
seat->mouse_focus = NULL;
seat->mouse_focus = old_term;
term->active_surface = old_active_surface;
}
static void

View file

@ -345,6 +345,12 @@ seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
if (seat->pointer.theme != NULL)
wl_cursor_theme_destroy(seat->pointer.theme);
if (seat->wl_touch != NULL &&
seat->touch.state == TOUCH_STATE_INHIBITED)
{
seat->touch.state = TOUCH_STATE_IDLE;
}
seat->wl_pointer = NULL;
seat->pointer.surface.surf = NULL;
seat->pointer.theme = NULL;

View file

@ -171,6 +171,7 @@ struct seat {
uint32_t serial;
uint32_t time;
struct wl_surface *surface;
int surface_kind;
int32_t id;
} touch;