[Wayland] Add mouse grab/lock functionality. (#15103)

* [Wayland] Add mouse grab functionality.

Co-authored-by: Colin Kinloch <colin@kinlo.ch>
This commit is contained in:
Manuel Alfayate Corchete 2023-03-20 11:30:04 +01:00 committed by GitHub
parent 8d1e575ea6
commit aaa53da148
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 116 additions and 10 deletions

View File

@ -421,6 +421,34 @@ static void wl_touch_handle_motion(void *data,
}
}
static void handle_relative_motion(void *data,
struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
uint32_t utime_hi, uint32_t utime_lo,
wl_fixed_t dx, wl_fixed_t dy,
wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel)
{
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
wl->input.mouse.delta_x = wl_fixed_to_int(dx);
wl->input.mouse.delta_y = wl_fixed_to_int(dy);
if (wl->locked_pointer)
{
wl->input.mouse.x += wl->input.mouse.delta_x;
wl->input.mouse.y += wl->input.mouse.delta_y;
}
}
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 void wl_touch_handle_frame(void *data, struct wl_touch *wl_touch) { }
static void wl_touch_handle_cancel(void *data, struct wl_touch *wl_touch)
@ -460,6 +488,11 @@ static void wl_seat_handle_capabilities(void *data,
{
wl->wl_pointer = wl_seat_get_pointer(seat);
wl_pointer_add_listener(wl->wl_pointer, &pointer_listener, wl);
wl->wl_relative_pointer =
zwp_relative_pointer_manager_v1_get_relative_pointer(
wl->relative_pointer_manager, wl->wl_pointer);
zwp_relative_pointer_v1_add_listener(wl->wl_relative_pointer,
&relative_pointer_listener, wl);
}
else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wl->wl_pointer)
{
@ -626,6 +659,17 @@ static void wl_registry_handle_global(void *data, struct wl_registry *reg,
interface, zxdg_decoration_manager_v1_interface.name))
wl->deco_manager = (struct zxdg_decoration_manager_v1*)wl_registry_bind(
reg, id, &zxdg_decoration_manager_v1_interface, MIN(version, 1));
else if (string_is_equal(interface, zwp_pointer_constraints_v1_interface.name))
{
wl->pointer_constraints = (struct zwp_pointer_constraints_v1*)
wl_registry_bind(
reg, id, &zwp_pointer_constraints_v1_interface, MIN(version, 1));
wl->locked_pointer = NULL;
}
else if (string_is_equal(interface, zwp_relative_pointer_manager_v1_interface.name))
wl->relative_pointer_manager = (struct zwp_relative_pointer_manager_v1*)
wl_registry_bind(
reg, id, &zwp_relative_pointer_manager_v1_interface, MIN(version, 1));
}
static void wl_registry_handle_global_remove(void *data,
@ -951,6 +995,15 @@ const struct wl_data_offer_listener data_offer_listener = {
wl_data_offer_handle_action
};
const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
.relative_motion = handle_relative_motion,
};
const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
.locked = locked_pointer_locked,
.unlocked = locked_pointer_unlocked,
};
void flush_wayland_fd(void *data)
{
struct pollfd fd = {0};

View File

@ -41,6 +41,12 @@
/* Generated from xdg-decoration-unstable-v1.h */
#include "../../gfx/common/wayland/xdg-decoration-unstable-v1.h"
/* Generated from pointer-constraints-unstable-v1.h */
#include "../../gfx/common/wayland/pointer-constraints-unstable-v1.h"
/* Generated from relative-pointer-unstable-v1.h */
#include "../../gfx/common/wayland/relative-pointer-unstable-v1.h"
#define UDEV_KEY_MAX 0x2ff
#define UDEV_MAX_KEYS (UDEV_KEY_MAX + 7) / 8
@ -138,6 +144,8 @@ typedef struct gfx_ctx_wayland_data
struct xdg_toplevel *xdg_toplevel;
struct wl_keyboard *wl_keyboard;
struct wl_pointer *wl_pointer;
struct zwp_relative_pointer_v1 *wl_relative_pointer;
struct zwp_locked_pointer_v1 *locked_pointer;
struct wl_touch *wl_touch;
struct wl_seat *seat;
struct wl_shm *shm;
@ -157,6 +165,8 @@ typedef struct gfx_ctx_wayland_data
struct zxdg_toplevel_decoration_v1 *deco;
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
struct zwp_idle_inhibitor_v1 *idle_inhibitor;
struct zwp_pointer_constraints_v1 *pointer_constraints;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
output_info_t *current_output;
#ifdef HAVE_VULKAN
gfx_ctx_vulkan_data_t vk;
@ -211,6 +221,10 @@ extern const struct wl_keyboard_listener keyboard_listener;
extern const struct wl_pointer_listener pointer_listener;
extern const struct zwp_relative_pointer_v1_listener relative_pointer_listener;
extern const struct zwp_locked_pointer_v1_listener locked_pointer_listener;
extern const struct wl_touch_listener touch_listener;
extern const struct wl_seat_listener seat_listener;

View File

@ -73,8 +73,6 @@ static void input_wl_poll(void *data)
flush_wayland_fd(wl);
wl->mouse.delta_x = wl->mouse.x - wl->mouse.last_x;
wl->mouse.delta_y = wl->mouse.y - wl->mouse.last_y;
wl->mouse.last_x = wl->mouse.x;
wl->mouse.last_y = wl->mouse.y;
@ -84,6 +82,27 @@ static void input_wl_poll(void *data)
wl->mouse.delta_y = 0;
}
if (wl->gfx->locked_pointer)
{
/* Get effective 'absolute' pointer location
* (last position + delta, bounded by current
* application window dimensions) */
wl->mouse.x += wl->mouse.delta_x;
wl->mouse.y += wl->mouse.delta_y;
/* Clamp X */
if (wl->mouse.x < 0)
wl->mouse.x = 0;
if (wl->mouse.x >= wl->gfx->buffer_width)
wl->mouse.x = (wl->gfx->buffer_width - 1);
/* Clamp Y */
if (wl->mouse.y < 0)
wl->mouse.y = 0;
if (wl->mouse.y >= wl->gfx->buffer_height)
wl->mouse.y = (wl->gfx->buffer_height - 1);
}
for (id = 0; id < MAX_TOUCHES; id++)
{
if (wayland_context_gettouchpos(wl->gfx, id, &touch_x, &touch_y))
@ -154,6 +173,7 @@ static int16_t input_wl_state(
unsigned id)
{
input_ctx_wayland_data_t *wl = (input_ctx_wayland_data_t*)data;
int x, y = 0;
switch (device)
{
@ -267,10 +287,14 @@ static int16_t input_wl_state(
wl->mouse.wd = false;
return state;
case RETRO_DEVICE_ID_MOUSE_X:
return screen ? wl->mouse.x : wl->mouse.delta_x;
case RETRO_DEVICE_ID_MOUSE_Y:
return screen ? wl->mouse.y : wl->mouse.delta_y;
case RETRO_DEVICE_ID_MOUSE_LEFT:
x = screen ? wl->mouse.x : wl->mouse.delta_x;
wl->mouse.delta_x = 0;
return x;
case RETRO_DEVICE_ID_MOUSE_Y:
y = screen ? wl->mouse.y : wl->mouse.delta_y;
wl->mouse.delta_y = 0;
return y;
case RETRO_DEVICE_ID_MOUSE_LEFT:
return wl->mouse.left;
case RETRO_DEVICE_ID_MOUSE_RIGHT:
return wl->mouse.right;
@ -406,10 +430,25 @@ static uint64_t input_wl_get_capabilities(void *data)
static void input_wl_grab_mouse(void *data, bool state)
{
/* This function does nothing but registering it is necessary for allowing
* mouse-grab toggling. */
(void)data;
(void)state;
input_ctx_wayland_data_t *wl = (input_ctx_wayland_data_t*)data;
gfx_ctx_wayland_data_t *gfx = (gfx_ctx_wayland_data_t*)wl->gfx;
if (gfx->pointer_constraints)
{
if (state)
{
gfx->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(gfx->pointer_constraints,
gfx->surface, gfx->wl_pointer, NULL, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
zwp_locked_pointer_v1_add_listener(gfx->locked_pointer,
&locked_pointer_listener, gfx);
}
else if (gfx->locked_pointer)
{
zwp_locked_pointer_v1_destroy(gfx->locked_pointer);
gfx->locked_pointer = NULL;
}
}
}
input_driver_t input_wayland = {