Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 13 commits into from
Mar 20, 2023
Merged
53 changes: 53 additions & 0 deletions input/common/wayland_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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};
Expand Down
14 changes: 14 additions & 0 deletions input/common/wayland_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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;
vanfanel marked this conversation as resolved.
Show resolved Hide resolved
struct zwp_locked_pointer_v1 *locked_pointer;
struct wl_touch *wl_touch;
struct wl_seat *seat;
struct wl_shm *shm;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
59 changes: 49 additions & 10 deletions input/drivers/wayland_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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))
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 = {
Expand Down