diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 9d8b4baf52..518c85bb0b 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -696,11 +696,17 @@ static void pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_ { SDL_WindowData *window = input->pointer_focus; enum wl_pointer_button_state state = state_w; - uint32_t sdl_button; - bool ignore_click = false; + Uint64 timestamp = Wayland_GetPointerTimestamp(input, time); + + if (SDL_EventEnabled(SDL_EVENT_MOUSE_RAW_BUTTON)) { + SDL_SendRawMouseButton(timestamp, input->pointer_id, !!state, button); + } if (window) { SDL_VideoData *viddata = window->waylandData; + Uint32 sdl_button; + bool ignore_click = false; + switch (button) { case BTN_LEFT: sdl_button = SDL_BUTTON_LEFT; @@ -760,7 +766,7 @@ static void pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_ if (!ignore_click) { SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, time), window->sdlwindow, input->pointer_id, - sdl_button, (state != 0)); + sdl_button, !!state); } } } @@ -777,10 +783,23 @@ static void pointer_handle_axis_common_v1(struct SDL_WaylandInput *input, uint32_t time, uint32_t axis, wl_fixed_t value) { SDL_WindowData *window = input->pointer_focus; - enum wl_pointer_axis a = axis; - float x, y; + const Uint64 timestamp = Wayland_GetPointerTimestamp(input, time); + const enum wl_pointer_axis a = axis; + + if (SDL_EventEnabled(SDL_EVENT_MOUSE_RAW_SCROLL)) { + // wl_fixed_t is a 24.8 signed fixed-point number which needs to be converted by dividing by 256 + const float denom = (float)(WAYLAND_WHEEL_AXIS_UNIT * 256); + + if (a == WL_POINTER_AXIS_VERTICAL_SCROLL) { + SDL_SendRawMouseAxis(timestamp, input->pointer_id, 0, (int)value, 0.f, denom, SDL_EVENT_MOUSE_RAW_SCROLL); + } else { + SDL_SendRawMouseAxis(timestamp, input->pointer_id, (int)value, 0, denom, 0.f, SDL_EVENT_MOUSE_RAW_SCROLL); + } + } if (input->pointer_focus) { + float x, y; + switch (a) { case WL_POINTER_AXIS_VERTICAL_SCROLL: x = 0; @@ -797,14 +816,25 @@ static void pointer_handle_axis_common_v1(struct SDL_WaylandInput *input, x /= WAYLAND_WHEEL_AXIS_UNIT; y /= WAYLAND_WHEEL_AXIS_UNIT; - SDL_SendMouseWheel(Wayland_GetPointerTimestamp(input, time), window->sdlwindow, input->pointer_id, x, y, SDL_MOUSEWHEEL_NORMAL); + SDL_SendMouseWheel(timestamp, window->sdlwindow, input->pointer_id, x, y, SDL_MOUSEWHEEL_NORMAL); } } static void pointer_handle_axis_common(struct SDL_WaylandInput *input, enum SDL_WaylandAxisEvent type, uint32_t axis, wl_fixed_t value) { - enum wl_pointer_axis a = axis; + const enum wl_pointer_axis a = axis; + + if (SDL_EventEnabled(SDL_EVENT_MOUSE_RAW_SCROLL)) { + // wl_fixed_t is a 24.8 signed fixed-point number which needs to be converted by dividing by 256 + const float denom = (float)((type == AXIS_EVENT_VALUE120 ? 120 : WAYLAND_WHEEL_AXIS_UNIT) * 256); + + if (a == WL_POINTER_AXIS_VERTICAL_SCROLL) { + SDL_SendRawMouseAxis(input->pointer_curr_axis_info.timestamp_ns, input->pointer_id, 0, (int)value, 0.f, denom, SDL_EVENT_MOUSE_RAW_SCROLL); + } else { + SDL_SendRawMouseAxis(input->pointer_curr_axis_info.timestamp_ns, input->pointer_id, (int)value, 0, denom, 0.f, SDL_EVENT_MOUSE_RAW_SCROLL); + } + } if (input->pointer_focus) { switch (a) { @@ -992,6 +1022,128 @@ static const struct wl_pointer_listener pointer_listener = { pointer_handle_axis_relative_direction // Version 9 }; +static void relative_pointer_handle_relative_motion(void *data, + struct zwp_relative_pointer_v1 *pointer, + uint32_t time_hi, + uint32_t time_lo, + wl_fixed_t dx_w, + wl_fixed_t dy_w, + wl_fixed_t dx_unaccel_w, + wl_fixed_t dy_unaccel_w) +{ + struct SDL_WaylandInput *input = data; + SDL_VideoData *d = input->display; + SDL_WindowData *window = input->pointer_focus; + + // Relative pointer event times are in microsecond granularity. + const Uint64 timestamp = Wayland_GetEventTimestamp(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo)); + + if (SDL_EventEnabled(SDL_EVENT_MOUSE_RAW_MOTION)) { + // wl_fixed_t is a 24.8 signed fixed-point number which needs to be converted by dividing by 256 + SDL_SendRawMouseAxis(timestamp, input->pointer_id, (int)dx_unaccel_w, (int)dy_unaccel_w, 256.0f, 256.0f, SDL_EVENT_MOUSE_RAW_MOTION); + } + + if (input->pointer_focus && d->relative_mouse_mode) { + double dx; + double dy; + if (!SDL_GetMouse()->enable_relative_system_scale) { + dx = wl_fixed_to_double(dx_unaccel_w); + dy = wl_fixed_to_double(dy_unaccel_w); + } else { + dx = wl_fixed_to_double(dx_w); + dy = wl_fixed_to_double(dy_w); + } + + SDL_SendMouseMotion(timestamp, window->sdlwindow, input->pointer_id, true, (float)dx, (float)dy); + } +} + +static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = { + relative_pointer_handle_relative_motion, +}; + +static void locked_pointer_locked(void *data, + struct zwp_locked_pointer_v1 *locked_pointer) +{ +} + +static void locked_pointer_unlocked(void *data, + struct zwp_locked_pointer_v1 *locked_pointer) +{ +} + +static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = { + locked_pointer_locked, + locked_pointer_unlocked, +}; + +bool Wayland_input_lock_pointer(struct SDL_WaylandInput *input, SDL_Window *window) +{ + SDL_WindowData *w = window->internal; + SDL_VideoData *d = input->display; + + if (!d->pointer_constraints || !input->pointer) { + return false; + } + + if (!w->locked_pointer) { + if (w->confined_pointer) { + // If the pointer is already confined to the surface, the lock will fail with a protocol error. + Wayland_input_unconfine_pointer(input, window); + } + + w->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints, + w->surface, + input->pointer, + NULL, + ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + zwp_locked_pointer_v1_add_listener(w->locked_pointer, + &locked_pointer_listener, + window); + } + + return true; +} + +bool Wayland_input_unlock_pointer(struct SDL_WaylandInput *input, SDL_Window *window) +{ + SDL_WindowData *w = window->internal; + + if (w->locked_pointer) { + zwp_locked_pointer_v1_destroy(w->locked_pointer); + w->locked_pointer = NULL; + } + + // Restore existing pointer confinement. + Wayland_input_confine_pointer(input, window); + + return true; +} + +static void pointer_confine_destroy(SDL_Window *window) +{ + SDL_WindowData *w = window->internal; + if (w->confined_pointer) { + zwp_confined_pointer_v1_destroy(w->confined_pointer); + w->confined_pointer = NULL; + } +} + +static void confined_pointer_confined(void *data, + struct zwp_confined_pointer_v1 *confined_pointer) +{ +} + +static void confined_pointer_unconfined(void *data, + struct zwp_confined_pointer_v1 *confined_pointer) +{ +} + +static const struct zwp_confined_pointer_v1_listener confined_pointer_listener = { + confined_pointer_confined, + confined_pointer_unconfined, +}; + static void touch_handler_down(void *data, struct wl_touch *touch, uint32_t serial, uint32_t timestamp, struct wl_surface *surface, int id, wl_fixed_t fx, wl_fixed_t fy) @@ -1807,6 +1959,13 @@ static void seat_handle_capabilities(void *data, struct wl_seat *seat, wl_pointer_set_user_data(input->pointer, input); wl_pointer_add_listener(input->pointer, &pointer_listener, input); + if (input->display->relative_pointer_manager) { + input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(input->display->relative_pointer_manager, input->pointer); + zwp_relative_pointer_v1_add_listener(input->relative_pointer, + &relative_pointer_listener, + input); + } + input->pointer_id = SDL_GetNextObjectID(); SDL_AddMouse(input->pointer_id, WAYLAND_DEFAULT_POINTER_NAME, true); } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) { @@ -2970,6 +3129,10 @@ void Wayland_display_destroy_input(SDL_VideoData *d) } } + if (input->relative_pointer) { + zwp_relative_pointer_v1_destroy(input->relative_pointer); + } + if (input->cursor_shape) { wp_cursor_shape_device_v1_destroy(input->cursor_shape); } @@ -3030,114 +3193,11 @@ void Wayland_display_destroy_input(SDL_VideoData *d) d->input = NULL; } -static void relative_pointer_handle_relative_motion(void *data, - struct zwp_relative_pointer_v1 *pointer, - uint32_t time_hi, - uint32_t time_lo, - wl_fixed_t dx_w, - wl_fixed_t dy_w, - wl_fixed_t dx_unaccel_w, - wl_fixed_t dy_unaccel_w) -{ - struct SDL_WaylandInput *input = data; - SDL_VideoData *d = input->display; - SDL_WindowData *window = input->pointer_focus; - double dx; - double dy; - - // Relative pointer event times are in microsecond granularity. - const Uint64 timestamp = SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo); - - if (!SDL_GetMouse()->enable_relative_system_scale) { - dx = wl_fixed_to_double(dx_unaccel_w); - dy = wl_fixed_to_double(dy_unaccel_w); - } else { - dx = wl_fixed_to_double(dx_w); - dy = wl_fixed_to_double(dy_w); - } - - if (input->pointer_focus && d->relative_mouse_mode) { - SDL_SendMouseMotion(Wayland_GetEventTimestamp(timestamp), window->sdlwindow, input->pointer_id, true, (float)dx, (float)dy); - } -} - -static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = { - relative_pointer_handle_relative_motion, -}; - -static void locked_pointer_locked(void *data, - struct zwp_locked_pointer_v1 *locked_pointer) -{ -} - -static void locked_pointer_unlocked(void *data, - struct zwp_locked_pointer_v1 *locked_pointer) -{ -} - -static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = { - locked_pointer_locked, - locked_pointer_unlocked, -}; - -bool Wayland_input_lock_pointer(struct SDL_WaylandInput *input, SDL_Window *window) -{ - SDL_WindowData *w = window->internal; - SDL_VideoData *d = input->display; - - if (!d->pointer_constraints || !input->pointer) { - return false; - } - - if (!w->locked_pointer) { - if (w->confined_pointer) { - // If the pointer is already confined to the surface, the lock will fail with a protocol error. - Wayland_input_unconfine_pointer(input, window); - } - - w->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints, - w->surface, - input->pointer, - NULL, - ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); - zwp_locked_pointer_v1_add_listener(w->locked_pointer, - &locked_pointer_listener, - window); - } - - return true; -} - -bool Wayland_input_unlock_pointer(struct SDL_WaylandInput *input, SDL_Window *window) -{ - SDL_WindowData *w = window->internal; - - if (w->locked_pointer) { - zwp_locked_pointer_v1_destroy(w->locked_pointer); - w->locked_pointer = NULL; - } - - // Restore existing pointer confinement. - Wayland_input_confine_pointer(input, window); - - return true; -} - -static void pointer_confine_destroy(SDL_Window *window) -{ - SDL_WindowData *w = window->internal; - if (w->confined_pointer) { - zwp_confined_pointer_v1_destroy(w->confined_pointer); - w->confined_pointer = NULL; - } -} - bool Wayland_input_enable_relative_pointer(struct SDL_WaylandInput *input) { SDL_VideoDevice *vd = SDL_GetVideoDevice(); SDL_VideoData *d = input->display; SDL_Window *window; - struct zwp_relative_pointer_v1 *relative_pointer; if (!d->relative_pointer_manager) { return false; @@ -3158,14 +3218,6 @@ bool Wayland_input_enable_relative_pointer(struct SDL_WaylandInput *input) pointer_confine_destroy(window); } - if (!input->relative_pointer) { - relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(d->relative_pointer_manager, input->pointer); - zwp_relative_pointer_v1_add_listener(relative_pointer, - &relative_pointer_listener, - input); - input->relative_pointer = relative_pointer; - } - for (window = vd->windows; window; window = window->next) { Wayland_input_lock_pointer(input, window); } @@ -3185,11 +3237,6 @@ bool Wayland_input_disable_relative_pointer(struct SDL_WaylandInput *input) Wayland_input_unlock_pointer(input, window); } - if (input->relative_pointer) { - zwp_relative_pointer_v1_destroy(input->relative_pointer); - input->relative_pointer = NULL; - } - d->relative_mouse_mode = 0; for (window = vd->windows; window; window = window->next) { @@ -3199,26 +3246,10 @@ bool Wayland_input_disable_relative_pointer(struct SDL_WaylandInput *input) return true; } -static void confined_pointer_confined(void *data, - struct zwp_confined_pointer_v1 *confined_pointer) -{ -} - -static void confined_pointer_unconfined(void *data, - struct zwp_confined_pointer_v1 *confined_pointer) -{ -} - -static const struct zwp_confined_pointer_v1_listener confined_pointer_listener = { - confined_pointer_confined, - confined_pointer_unconfined, -}; - bool Wayland_input_confine_pointer(struct SDL_WaylandInput *input, SDL_Window *window) { SDL_WindowData *w = window->internal; SDL_VideoData *d = input->display; - struct zwp_confined_pointer_v1 *confined_pointer; struct wl_region *confine_rect; if (!d->pointer_constraints) { @@ -3264,7 +3295,7 @@ bool Wayland_input_confine_pointer(struct SDL_WaylandInput *input, SDL_Window *w scaled_mouse_rect.h); } - confined_pointer = + struct zwp_confined_pointer_v1 *confined_pointer = zwp_pointer_constraints_v1_confine_pointer(d->pointer_constraints, w->surface, input->pointer, diff --git a/src/video/wayland/SDL_waylandevents_c.h b/src/video/wayland/SDL_waylandevents_c.h index c5741a5e20..b67e7e3918 100644 --- a/src/video/wayland/SDL_waylandevents_c.h +++ b/src/video/wayland/SDL_waylandevents_c.h @@ -81,8 +81,8 @@ struct SDL_WaylandInput SDL_WindowData *pointer_focus; SDL_WindowData *keyboard_focus; SDL_CursorData *current_cursor; - Uint32 keyboard_id; - Uint32 pointer_id; + SDL_KeyboardID keyboard_id; + SDL_MouseID pointer_id; uint32_t pointer_enter_serial; // High-resolution event timestamps