From f0f0d02bf74b1ba4279b25883db7b48619242377 Mon Sep 17 00:00:00 2001 From: CismonX Date: Sat, 19 Aug 2023 23:01:53 +0800 Subject: [PATCH] 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. --- input.c | 98 +++++++++++++++++++++++++++++++++++++------------------ wayland.c | 6 ++++ wayland.h | 1 + 3 files changed, 73 insertions(+), 32 deletions(-) diff --git a/input.c b/input.c index 53d7acf8..c95d3f28 100644 --- a/input.c +++ b/input.c @@ -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 diff --git a/wayland.c b/wayland.c index d558c489..7fcb01c1 100644 --- a/wayland.c +++ b/wayland.c @@ -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; diff --git a/wayland.h b/wayland.h index 6585191f..67aadec2 100644 --- a/wayland.h +++ b/wayland.h @@ -171,6 +171,7 @@ struct seat { uint32_t serial; uint32_t time; struct wl_surface *surface; + int surface_kind; int32_t id; } touch;