Pointer handling sanitization - wayland and libretro.h changes (#17277)

Adapt the sanitized pointer handling, discussed at #17196:

Wayland driver specific changes:
- make sure pointer position is always within [-0x7fff,0x7fff]
  by using the confined wrapper
- enable lightgun to report -0x8000 if pointer is really offscreen
- remove extra "inside" checks
- report same pointer/lightgun coordinates for all ports
- simplify pointer and lightgun handling

Other changes:
- unify "offscreen" condition through input_driver.c
- slight tuning of pointer conversion in video_driver.c
- update libretro.h with explanation and pointer offscreen value
- small fixes on remote retropad test screen
This commit is contained in:
zoltanvb 2024-12-21 22:28:27 +01:00 committed by GitHub
parent a7db10508c
commit 072d949346
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 69 additions and 93 deletions

View File

@ -162,13 +162,13 @@ static struct descriptor mouse = {
};
static struct descriptor pointer = {
.device = RETRO_DEVICE_POINTER/* | 0x10000*/,
.device = RETRO_DEVICE_POINTER,
.port_min = 0,
.port_max = 0,
.index_min = 0,
.index_max = 2,
.id_min = RETRO_DEVICE_ID_POINTER_X,
.id_max = RETRO_DEVICE_ID_POINTER_COUNT
.id_max = RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN
};
static struct descriptor lightgun = {
@ -710,7 +710,7 @@ static void retropad_update_input(void)
}
else if (id == RETRO_DEVICE_ID_MOUSE_Y || id == RETRO_DEVICE_ID_LIGHTGUN_Y)
{
int32_t large = pointer_y + (int16_t)state*273;
int32_t large = pointer_y + (int16_t)state*327;
if (large < -32768)
pointer_y = -32768;
else if (large > 32767)
@ -721,6 +721,7 @@ static void retropad_update_input(void)
}
else if (mouse_type == NETRETROPAD_POINTER || mouse_type == NETRETROPAD_LIGHTGUN)
{
/* NETRETROPAD_CORE_PREFIX(log_cb)(RETRO_LOG_DEBUG, "Pointer state: %d %d %d (%d %d)\n",i,id, (int16_t)state,pointer_x,pointer_y); */
if (id == RETRO_DEVICE_ID_POINTER_X || id == RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X)
pointer_x = (int16_t)state;
else if (id == RETRO_DEVICE_ID_POINTER_Y || id == RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y)
@ -1114,15 +1115,18 @@ void NETRETROPAD_CORE_PREFIX(retro_run)(void)
{
int offset;
offset = DESC_OFFSET(&lightgun, 0, 0, RETRO_DEVICE_ID_POINTER_PRESSED);
offset = DESC_OFFSET(&pointer, 0, 0, RETRO_DEVICE_ID_POINTER_PRESSED);
sensor_item_colors[104] = pointer.value[offset] ? 0xA000 : 0x0000;
offset = DESC_OFFSET(&lightgun, 0, 1, RETRO_DEVICE_ID_POINTER_PRESSED);
offset = DESC_OFFSET(&pointer, 0, 1, RETRO_DEVICE_ID_POINTER_PRESSED);
sensor_item_colors[105] = pointer.value[offset] ? 0xA000 : 0x0000;
offset = DESC_OFFSET(&lightgun, 0, 2, RETRO_DEVICE_ID_POINTER_PRESSED);
offset = DESC_OFFSET(&pointer, 0, 2, RETRO_DEVICE_ID_POINTER_PRESSED);
sensor_item_colors[106] = pointer.value[offset] ? 0xA000 : 0x0000;
offset = DESC_OFFSET(&pointer, 0, 0, RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN);
sensor_item_colors[77] = pointer.value[offset] ? 0xA000 : 0x0000;
}
/* Edge / offscreen indicators */
if (mouse_type == NETRETROPAD_POINTER || mouse_type == NETRETROPAD_LIGHTGUN)

View File

@ -712,19 +712,19 @@ 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 = ((2 * mouse_x * 0x7fff)
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 = ((2 * mouse_y * 0x7fff)
if (mouse_y >= 0 && mouse_y < norm_full_vp_height)
scaled_screen_y = ((mouse_y * 0x10000)
/ norm_full_vp_height) - 0x7fff;
mouse_x -= vp->x;
mouse_y -= vp->y;
if (mouse_x >= 0 && mouse_x <= norm_vp_width)
scaled_x = ((2 * mouse_x * 0x7fff)
if (mouse_x >= 0 && mouse_x < norm_vp_width)
scaled_x = ((mouse_x * 0x10000)
/ norm_vp_width) - 0x7fff;
else if (!report_oob)
{
@ -734,8 +734,8 @@ bool video_driver_translate_coord_viewport(
scaled_x = 0x7fff;
}
if (mouse_y >= 0 && mouse_y <= norm_vp_height)
scaled_y = ((2 * mouse_y * 0x7fff)
if (mouse_y >= 0 && mouse_y < norm_vp_height)
scaled_y = ((mouse_y * 0x10000)
/ norm_vp_height) - 0x7fff;
else if (!report_oob)
{

View File

@ -122,7 +122,7 @@ static int16_t input_wl_touch_state(input_ctx_wayland_data_t *wl,
vp.full_width = 0;
vp.full_height = 0;
if (video_driver_translate_coord_viewport_wrap(&vp,
if (video_driver_translate_coord_viewport_confined_wrap(&vp,
wl->touches[idx].x, wl->touches[idx].y,
&res_x, &res_y, &res_screen_x, &res_screen_y))
{
@ -256,7 +256,8 @@ static int16_t input_wl_state(
return (id && id < RETROK_LAST) && BIT_GET(wl->key_state, rarch_keysym_lut[(enum retro_key)id]);
case RETRO_DEVICE_MOUSE:
case RARCH_DEVICE_MOUSE_SCREEN:
if (port == 0) /* TODO/FIXME: support mouse on additional ports */
/* The system-wide mouse is reported for all ports. *
* Multi-mouse may be implemented using different wayland seats, see issue #16886 */
{
bool state = false;
bool screen = (device == RARCH_DEVICE_MOUSE_SCREEN);
@ -300,26 +301,18 @@ static int16_t input_wl_state(
}
break;
case RETRO_DEVICE_POINTER:
/* TODO/FIXME: support pointers on additional ports */
/* All ports report the same pointer state. See notes at mouse case. */
if (idx == 0)
{
struct video_viewport vp;
struct video_viewport vp = {0};
bool screen =
(device == RARCH_DEVICE_POINTER_SCREEN);
bool inside = false;
int16_t res_x = 0;
int16_t res_y = 0;
int16_t res_screen_x = 0;
int16_t res_screen_y = 0;
vp.x = 0;
vp.y = 0;
vp.width = 0;
vp.height = 0;
vp.full_width = 0;
vp.full_height = 0;
if (video_driver_translate_coord_viewport_wrap(&vp,
if (video_driver_translate_coord_viewport_confined_wrap(&vp,
wl->mouse.x, wl->mouse.y,
&res_x, &res_y, &res_screen_x, &res_screen_y))
{
@ -329,10 +322,6 @@ static int16_t input_wl_state(
res_y = res_screen_y;
}
inside = (res_x >= -0x7fff) && (res_y >= -0x7fff);
if (!inside)
return 0;
switch (id)
{
case RETRO_DEVICE_ID_POINTER_X:
@ -341,13 +330,8 @@ static int16_t input_wl_state(
return res_y;
case RETRO_DEVICE_ID_POINTER_PRESSED:
return wl->mouse.left;
case RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN:
if (screen)
{
res_x = res_screen_x;
res_y = res_screen_y;
}
return (!((res_x >= -0x7fff) && (res_y >= -0x7fff)));
case RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN:
return input_driver_pointer_is_offscreen(res_x, res_y);
default:
break;
}
@ -363,68 +347,38 @@ static int16_t input_wl_state(
}
break;
case RETRO_DEVICE_LIGHTGUN:
if (port == 0) /* TODO/FIXME: support lightguns on additional ports */
/* All ports report the same lightgun state. See notes at mouse case. */
{
const int edge_detect = 32700;
struct video_viewport vp;
bool screen =
(device == RARCH_DEVICE_POINTER_SCREEN);
bool inside = false;
int16_t res_x = 0;
int16_t res_y = 0;
int16_t res_screen_x = 0;
int16_t res_screen_y = 0;
vp.x = 0;
vp.y = 0;
vp.width = 0;
vp.height = 0;
vp.full_width = 0;
vp.full_height = 0;
struct video_viewport vp = {0};
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_translate_coord_viewport_wrap(&vp,
wl->mouse.x, wl->mouse.y,
&res_x, &res_y, &res_screen_x, &res_screen_y))
{
if (screen)
{
res_x = res_screen_x;
res_y = res_screen_y;
}
inside = (res_x >= -0x7fff) && (res_y >= -0x7fff);
if (!inside)
return 0;
switch (id)
{
case RETRO_DEVICE_ID_LIGHTGUN_X: /* TODO: migrate to RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X */
return wl->mouse.delta_x; /* deprecated relative coordinates */
case RETRO_DEVICE_ID_LIGHTGUN_Y: /* TODO: migrate to RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y */
return wl->mouse.delta_y; /* deprecated relative coordinates */
case RETRO_DEVICE_ID_LIGHTGUN_X:
return wl->mouse.delta_x;
case RETRO_DEVICE_ID_LIGHTGUN_Y:
return wl->mouse.delta_y;
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_TRIGGER:
return wl->mouse.left;
case RETRO_DEVICE_ID_LIGHTGUN_RELOAD: /* forced/faked off-screen shot */
case RETRO_DEVICE_ID_LIGHTGUN_RELOAD:
return wl->mouse.middle;
case RETRO_DEVICE_ID_LIGHTGUN_START:
return wl->mouse.right;
case RETRO_DEVICE_ID_LIGHTGUN_SELECT:
return wl->mouse.left && wl->mouse.right;
case RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN:
if (screen)
{
res_x = res_screen_x;
res_y = res_screen_y;
}
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);
case RETRO_DEVICE_ID_LIGHTGUN_AUX_A: /* TODO */
case RETRO_DEVICE_ID_LIGHTGUN_AUX_B: /* TODO */
case RETRO_DEVICE_ID_LIGHTGUN_AUX_C: /* TODO */

View File

@ -644,6 +644,17 @@ static bool input_driver_button_combo_hold(
return false;
}
bool input_driver_pointer_is_offscreen(int16_t x, int16_t y)
{
const int edge_detect = 32700;
if ((x >= -edge_detect) &&
(y >= -edge_detect) &&
(x <= edge_detect) &&
(y <= edge_detect))
return false;
return true;
}
bool input_driver_button_combo(
unsigned mode,
retro_time_t current_time,

View File

@ -922,6 +922,8 @@ char *input_config_get_device_name_ptr(unsigned port);
*/
size_t input_config_get_device_name_size(unsigned port);
bool input_driver_pointer_is_offscreen(int16_t x, int16_t y);
bool input_driver_button_combo(
unsigned mode,
retro_time_t current_time,

View File

@ -4,12 +4,12 @@
* @file libretro.h
* @version 1
* @author libretro
* @copyright Copyright (C) 2010-2023 The RetroArch team
* @copyright Copyright (C) 2010-2024 The RetroArch team
*
* @paragraph LICENSE
* The following license statement only applies to this libretro API header (libretro.h).
*
* Copyright (C) 2010-2023 The RetroArch team
* Copyright (C) 2010-2024 The RetroArch team
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
@ -272,7 +272,10 @@ extern "C" {
* [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen,
* and 0x7fff corresponds to the far right/bottom of the screen.
* The "screen" is here defined as area that is passed to the frontend and
* later displayed on the monitor.
* later displayed on the monitor. If the pointer is outside this screen,
* such as in the black surrounding areas when actual display is larger,
* edge position is reported. An explicit edge detection is also provided,
* that will return 1 if the pointer is near the screen edge or actually outside it.
*
* The frontend is free to scale/resize this screen as it sees fit, however,
* (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the
@ -406,7 +409,8 @@ extern "C" {
/* Id values for LIGHTGUN. */
#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X 13 /*Absolute Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y 14 /*Absolute*/
#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y 14 /*Absolute Position*/
/** Indicates if lightgun points off the screen or near the edge */
#define RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN 15 /*Status Check*/
#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER 2
#define RETRO_DEVICE_ID_LIGHTGUN_RELOAD 16 /*Forced off-screen shot*/
@ -421,17 +425,18 @@ extern "C" {
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT 12
/* deprecated */
#define RETRO_DEVICE_ID_LIGHTGUN_X 0 /*Relative Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_Y 1 /*Relative*/
#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR 3 /*Use Aux:A*/
#define RETRO_DEVICE_ID_LIGHTGUN_TURBO 4 /*Use Aux:B*/
#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5 /*Use Start*/
#define RETRO_DEVICE_ID_LIGHTGUN_Y 1 /*Relative Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR 3 /*Use Aux:A instead*/
#define RETRO_DEVICE_ID_LIGHTGUN_TURBO 4 /*Use Aux:B instead*/
#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5 /*Use Start instead*/
/* Id values for POINTER. */
#define RETRO_DEVICE_ID_POINTER_X 0
#define RETRO_DEVICE_ID_POINTER_Y 1
#define RETRO_DEVICE_ID_POINTER_PRESSED 2
#define RETRO_DEVICE_ID_POINTER_COUNT 3
#define RETRO_DEVICE_ID_POINTER_X 0
#define RETRO_DEVICE_ID_POINTER_Y 1
#define RETRO_DEVICE_ID_POINTER_PRESSED 2
#define RETRO_DEVICE_ID_POINTER_COUNT 3
/** Indicates if pointer is off the screen or near the edge */
#define RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN 15
/** @} */
/* Returned from retro_get_region(). */