Skip to content

Commit

Permalink
Pointer sanitization - x11, udev (#17281)
Browse files Browse the repository at this point in the history
Adapt the sanitized pointer handling, discussed at #17196 :

X11 driver specific changes:

    make sure pointer position is always within [-0x7fff,0x7fff] by using the confined wrapper
    remove extra "inside" checks, general simplification
    enable pointer offscreen reporting

Udev driver specific changes:

    remove custom calculation and use common viewport translation
    unify pointer query instead of separate _x and _y
    enable pointer offscreen reporting

Other changes:

    more tuning of pointer conversion in video_driver.c for edges
    lightgun button ID conversion moved to input_driver.c
  • Loading branch information
zoltanvb authored Dec 24, 2024
1 parent f8ffcef commit 6a85844
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 214 deletions.
42 changes: 29 additions & 13 deletions gfx/video_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -711,20 +711,34 @@ bool video_driver_translate_coord_viewport(
|| (norm_full_vp_height <= 0))
return false;

if (mouse_x >= 0 && mouse_x < norm_full_vp_width)
scaled_screen_x = ((mouse_x * 0x10000)
/ norm_full_vp_width) - 0x7fff;

if (mouse_y >= 0 && mouse_y < norm_full_vp_height)
scaled_screen_y = ((mouse_y * 0x10000)
/ norm_full_vp_height) - 0x7fff;
/* The conditions may look a bit unnecessarily complex, *
* but there are following edge cases to consider: *
* - 0 should map to -0x7fff (not -0x8000) *
* - edge (vp_width -1) should map to 0x7fff *
* This should make it possible to hit the edges on all *
* screen resolutions, even when pointer cannot be *
* moved offscreen. */

if (mouse_x > 0 && mouse_x < norm_full_vp_width)
scaled_screen_x = ((mouse_x * 0xffff)
/ (norm_full_vp_width - 1)) - 0x8000;
else if (mouse_x == 0)
scaled_screen_x = -0x7fff;

if (mouse_y > 0 && mouse_y < norm_full_vp_height)
scaled_screen_y = ((mouse_y * 0xffff)
/ (norm_full_vp_height - 1)) - 0x8000;
else if (mouse_y == 0)
scaled_screen_y = -0x7fff;

mouse_x -= vp->x;
mouse_y -= vp->y;

if (mouse_x >= 0 && mouse_x < norm_vp_width)
scaled_x = ((mouse_x * 0x10000)
/ norm_vp_width) - 0x7fff;
if (mouse_x > 0 && mouse_x < norm_vp_width)
scaled_x = ((mouse_x * 0xffff)
/ (norm_vp_width - 1)) - 0x8000;
else if (mouse_x == 0)
scaled_x = -0x7fff;
else if (!report_oob)
{
if (mouse_x < 0)
Expand All @@ -733,9 +747,11 @@ bool video_driver_translate_coord_viewport(
scaled_x = 0x7fff;
}

if (mouse_y >= 0 && mouse_y < norm_vp_height)
scaled_y = ((mouse_y * 0x10000)
/ norm_vp_height) - 0x7fff;
if (mouse_y > 0 && mouse_y < norm_vp_height)
scaled_y = ((mouse_y * 0xffff)
/ (norm_vp_height - 1)) - 0x8000;
else if (mouse_y == 0)
scaled_y = -0x7fff;
else if (!report_oob)
{
if (mouse_y < 0)
Expand Down
172 changes: 49 additions & 123 deletions input/drivers/udev_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -781,96 +781,60 @@ static int16_t udev_mouse_get_y(const udev_input_mouse_t *mouse)
return y + (y < 0 ? -0.5 : 0.5);
}

static int16_t udev_mouse_get_pointer_x(const udev_input_mouse_t *mouse, bool screen)
static bool udev_mouse_get_pointer(const udev_input_mouse_t *mouse,
bool screen, bool confined, int16_t *ret_x, int16_t *ret_y)
{
video_viewport_t vp;
double src_min;
double src_width;
int32_t x;
struct video_viewport vp = {0};
int16_t scaled_x;
int16_t scaled_y;
int16_t res_x = 0;
int16_t res_y = 0;
int16_t res_screen_x = 0;
int16_t res_screen_y = 0;

if (!video_driver_get_viewport_info(&vp))
return 0;
return false;

/* mouse coords are absolute? */
if (mouse->abs)
{
/* mouse coordinates are relative to the screen; convert them
/* mouse coordinates are relative to the full screen; convert them
* to be relative to the viewport */
double scaled_x;
src_min = mouse->x_min;
src_width = mouse->x_max - mouse->x_min + 1;
scaled_x = vp.full_width * (mouse->x_abs - src_min) / src_width;
x = -32767.0 + 65535.0 / vp.width * (scaled_x - vp.x);
scaled_x = mouse->x_abs - mouse->x_min;
scaled_y = mouse->y_abs - mouse->y_min;
}
else /* mouse coords are viewport relative */
{
if (screen)
{
src_min = 0.0;
src_width = vp.full_width;
}
else
{
src_min = vp.x;
src_width = vp.width;
}
x = -32767.0 + 65535.0 / src_width * (mouse->x_abs - src_min);
scaled_x = mouse->x_abs;
scaled_y = mouse->y_abs;
}

x += (x < 0 ? -0.5 : 0.5);

if (x < -0x7fff)
return -0x7fff;
else if (x > 0x7fff)
return 0x7fff;

return x;
}

static int16_t udev_mouse_get_pointer_y(const udev_input_mouse_t *mouse, bool screen)
{
video_viewport_t vp;
double src_min;
double src_height;
int32_t y;

if (!video_driver_get_viewport_info(&vp))
return 0;

/* Mouse coords are absolute? */
if (mouse->abs)
if (confined && video_driver_translate_coord_viewport_confined_wrap(
&vp, scaled_x, scaled_y,
&res_x, &res_y, &res_screen_x, &res_screen_y))
{
double scaled_y;
/* mouse coordinates are relative to the screen; convert them
* to be relative to the viewport */
src_min = mouse->y_min;
src_height = mouse->y_max - mouse->y_min + 1;
scaled_y = vp.full_height * (mouse->y_abs - src_min) / src_height;
y = -32767.0 + 65535.0 / vp.height * (scaled_y - vp.y);
}
else /* mouse coords are viewport relative */
else if (!confined && video_driver_translate_coord_viewport_wrap(
&vp, scaled_x, scaled_y,
&res_x, &res_y, &res_screen_x, &res_screen_y))
{
if (screen)
{
src_min = 0.0;
src_height = vp.full_height;
}
else
{
src_min = vp.y;
src_height = vp.height;
}
y = -32767.0 + 65535.0 / src_height * (mouse->y_abs - src_min);
}

y += (y < 0 ? -0.5 : 0.5);

if (y < -0x7fff)
return -0x7fff;
else if (y > 0x7fff)
return 0x7fff;

return y;
else
{
return false;
}

if (screen)
{
*ret_x = res_screen_x;
*ret_y = res_screen_y;
}
else
{
*ret_x = res_x;
*ret_y = res_y;
}
return true;
}

static void udev_handle_mouse(void *data,
Expand Down Expand Up @@ -3616,27 +3580,20 @@ static int16_t udev_lightgun_aiming_state(
udev_input_t *udev, unsigned port, unsigned id )
{

const int edge_detect = 32700;
udev_input_mouse_t *mouse = udev_get_mouse(udev, port);
int16_t res_x;
int16_t res_y;

if (mouse)
if (mouse && udev_mouse_get_pointer(mouse, false, false, &res_x, &res_y))
{
bool inside = false;
int16_t res_x = udev_mouse_get_pointer_x(mouse, false);
int16_t res_y = udev_mouse_get_pointer_y(mouse, false);

switch ( id )
{
case RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X:
return res_x;
case RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y:
return res_y;
case RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN:
inside = (res_x >= -edge_detect)
&& (res_y >= -edge_detect)
&& (res_x <= edge_detect)
&& (res_y <= edge_detect);
return !inside;
return input_driver_pointer_is_offscreen(res_x, res_y);
default:
break;
}
Expand Down Expand Up @@ -3731,60 +3688,29 @@ static int16_t udev_pointer_state(udev_input_t *udev,
unsigned port, unsigned id, bool screen)
{
udev_input_mouse_t *mouse = udev_get_mouse(udev, port);
int16_t res_x;
int16_t res_y;

if (mouse)
if (mouse && udev_mouse_get_pointer(mouse, screen, true, &res_x, &res_y))
{
switch (id)
{
case RETRO_DEVICE_ID_POINTER_X:
return udev_mouse_get_pointer_x(mouse, screen);
return res_x;
case RETRO_DEVICE_ID_POINTER_Y:
return udev_mouse_get_pointer_y(mouse, screen);
return res_y;
case RETRO_DEVICE_ID_POINTER_PRESSED:
if (mouse->abs == 1)
return mouse->pp;
return mouse->l;
case RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN:
return input_driver_pointer_is_offscreen(res_x, res_y);
}
}

return 0;
}

static unsigned udev_retro_id_to_rarch(unsigned id)
{
switch (id)
{
case RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT:
return RARCH_LIGHTGUN_DPAD_RIGHT;
case RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT:
return RARCH_LIGHTGUN_DPAD_LEFT;
case RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP:
return RARCH_LIGHTGUN_DPAD_UP;
case RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN:
return RARCH_LIGHTGUN_DPAD_DOWN;
case RETRO_DEVICE_ID_LIGHTGUN_SELECT:
return RARCH_LIGHTGUN_SELECT;
case RETRO_DEVICE_ID_LIGHTGUN_PAUSE:
return RARCH_LIGHTGUN_START;
case RETRO_DEVICE_ID_LIGHTGUN_RELOAD:
return RARCH_LIGHTGUN_RELOAD;
case RETRO_DEVICE_ID_LIGHTGUN_TRIGGER:
return RARCH_LIGHTGUN_TRIGGER;
case RETRO_DEVICE_ID_LIGHTGUN_AUX_A:
return RARCH_LIGHTGUN_AUX_A;
case RETRO_DEVICE_ID_LIGHTGUN_AUX_B:
return RARCH_LIGHTGUN_AUX_B;
case RETRO_DEVICE_ID_LIGHTGUN_AUX_C:
return RARCH_LIGHTGUN_AUX_C;
case RETRO_DEVICE_ID_LIGHTGUN_START:
return RARCH_LIGHTGUN_START;
default:
break;
}

return 0;
}

static int16_t udev_input_state(
void *data,
const input_device_driver_t *joypad,
Expand Down Expand Up @@ -3935,7 +3861,7 @@ static int16_t udev_input_state(
case RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT:
case RETRO_DEVICE_ID_LIGHTGUN_PAUSE: /* deprecated */
{
unsigned new_id = udev_retro_id_to_rarch(id);
unsigned new_id = input_driver_lightgun_id_convert(id);
const uint64_t bind_joykey = input_config_binds[port][new_id].joykey;
const uint64_t bind_joyaxis = input_config_binds[port][new_id].joyaxis;
const uint64_t autobind_joykey = input_autoconf_binds[port][new_id].joykey;
Expand Down
Loading

0 comments on commit 6a85844

Please sign in to comment.