From f600364b8a575e03f140ab18eeabaeffb8f0b392 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 6 Aug 2022 09:19:52 -0400 Subject: [PATCH] wayland: Mark window as MOUSE_CAPTURE while a mouse button is down. Wayland works like SDL's "auto capture" feature already, tracking the mouse globally only while a drag is occuring, and this is the only way to get mouse input outside the window. Setting this flag ourselves lets SDL_CaptureMouse() work in the most common use case without actually implementing CaptureMouse for the backend, including SDL's auto capture feature. Fixes #6010. --- src/video/wayland/SDL_waylandevents.c | 25 ++++++++++++++++++++++++- src/video/wayland/SDL_waylandevents_c.h | 2 ++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 2b547faf6..14a28430c 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -545,7 +545,7 @@ pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial, enum wl_pointer_button_state state = state_w; uint32_t sdl_button; - if (input->pointer_focus) { + if (window) { switch (button) { case BTN_LEFT: sdl_button = SDL_BUTTON_LEFT; @@ -569,6 +569,23 @@ pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial, return; } + /* Wayland won't let you "capture" the mouse, but it will + automatically track the mouse outside the window if you + drag outside of it, until you let go of all buttons (even + if you add or remove presses outside the window, as long + as any button is still down, the capture remains) */ + if (state) { /* update our mask of currently-pressed buttons */ + input->buttons_pressed |= SDL_BUTTON(sdl_button); + } else { + input->buttons_pressed &= ~(SDL_BUTTON(sdl_button)); + } + + if (input->buttons_pressed != 0) { + window->sdlwindow->flags |= SDL_WINDOW_MOUSE_CAPTURE; + } else { + window->sdlwindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE; + } + Wayland_data_device_set_serial(input->data_device, serial); SDL_SendMouseButton(window->sdlwindow, 0, @@ -913,11 +930,17 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) { struct SDL_WaylandInput *input = data; + SDL_WindowData *window; if (!surface || !SDL_WAYLAND_own_surface(surface)) { return; } + window = wl_surface_get_user_data(surface); + if (window) { + window->sdlwindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE; + } + /* Stop key repeat before clearing keyboard focus */ keyboard_repeat_clear(&input->keyboard_repeat); diff --git a/src/video/wayland/SDL_waylandevents_c.h b/src/video/wayland/SDL_waylandevents_c.h index 59dc0c8af..9bcb2c9b1 100644 --- a/src/video/wayland/SDL_waylandevents_c.h +++ b/src/video/wayland/SDL_waylandevents_c.h @@ -88,6 +88,8 @@ struct SDL_WaylandInput { wl_fixed_t sx_w; wl_fixed_t sy_w; + uint32_t buttons_pressed; + double dx_frac; double dy_frac;