From 90ee413a81c30e26a8e9b141a6716dc979607b87 Mon Sep 17 00:00:00 2001 From: zoltanvb <101990835+zoltanvb@users.noreply.github.com> Date: Thu, 7 Nov 2024 00:19:08 +0100 Subject: [PATCH] Pointer confinement support (opt-in) (#17169) New environment set call to enable a bit more sensible handling of absolute pointing devices (pointer and lightgun). With the confinement enabled, pointing devices will not return neither -0x8000 nor (0,0), which was anyway dependent on the input driver, instead they will stay at the extreme edge. --- .../libretro-net-retropad/net_retropad_core.c | 25 +++++++++----- gfx/video_driver.c | 33 +++++++++++++------ libretro-common/include/libretro.h | 28 ++++++++++++++++ runloop.c | 7 ++++ runloop.h | 1 + 5 files changed, 75 insertions(+), 19 deletions(-) diff --git a/cores/libretro-net-retropad/net_retropad_core.c b/cores/libretro-net-retropad/net_retropad_core.c index ccc92ca2c4..a64abf958a 100644 --- a/cores/libretro-net-retropad/net_retropad_core.c +++ b/cores/libretro-net-retropad/net_retropad_core.c @@ -785,6 +785,7 @@ void NETRETROPAD_CORE_PREFIX(retro_set_environment)(retro_environment_t cb) { "net_retropad_screen", "Start screen; Retropad|Keyboard tester|Sensor tester" }, { "net_retropad_hide_analog_mismatch", "Hide mismatching analog button inputs; True|False" }, { "net_retropad_pointer_test", "Pointer test; Off|Mouse|Pointer|Lightgun|Old lightgun" }, + { "net_retropad_pointer_confine", "Pointer confinement; Off|Edge" }, { NULL, NULL }, }; enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565; @@ -806,15 +807,17 @@ void NETRETROPAD_CORE_PREFIX(retro_set_environment)(retro_environment_t cb) static void netretropad_check_variables(void) { - struct retro_variable var, var2, var3, var4, port_var, screen_var, hide_a_var, mouse_var; - var.key = "net_retropad_ip_octet1"; - var2.key = "net_retropad_ip_octet2"; - var3.key = "net_retropad_ip_octet3"; - var4.key = "net_retropad_ip_octet4"; - port_var.key = "net_retropad_port"; - screen_var.key = "net_retropad_screen"; - hide_a_var.key = "net_retropad_hide_analog_mismatch"; - mouse_var.key = "net_retropad_pointer_test"; + unsigned pointer_confinement = RETRO_POINTER_CONFINEMENT_LEGACY; + struct retro_variable var, var2, var3, var4, port_var, screen_var, hide_a_var, mouse_var, confine_var; + var.key = "net_retropad_ip_octet1"; + var2.key = "net_retropad_ip_octet2"; + var3.key = "net_retropad_ip_octet3"; + var4.key = "net_retropad_ip_octet4"; + port_var.key = "net_retropad_port"; + screen_var.key = "net_retropad_screen"; + hide_a_var.key = "net_retropad_hide_analog_mismatch"; + mouse_var.key = "net_retropad_pointer_test"; + confine_var.key = "net_retropad_pointer_confine"; NETRETROPAD_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &var); NETRETROPAD_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &var2); @@ -824,6 +827,7 @@ static void netretropad_check_variables(void) NETRETROPAD_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &screen_var); NETRETROPAD_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &hide_a_var); NETRETROPAD_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &mouse_var); + NETRETROPAD_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &confine_var); snprintf(server, sizeof(server), "%s.%s.%s.%s", var.value, var2.value, var3.value, var4.value); port = atoi(port_var.value); @@ -849,6 +853,9 @@ static void netretropad_check_variables(void) else mouse_type = 0; + if (confine_var.value && strstr(confine_var.value,"Edge")) + pointer_confinement = RETRO_POINTER_CONFINEMENT_EDGE; + NETRETROPAD_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_SET_POINTER_CONFINEMENT, &pointer_confinement); } void NETRETROPAD_CORE_PREFIX(retro_set_audio_sample)(retro_audio_sample_t cb) diff --git a/gfx/video_driver.c b/gfx/video_driver.c index 6cdd6d699e..e399b2325b 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -694,14 +694,15 @@ bool video_driver_translate_coord_viewport( int16_t *res_x, int16_t *res_y, int16_t *res_screen_x, int16_t *res_screen_y) { - int norm_vp_width = (int)vp->width; - int norm_vp_height = (int)vp->height; - int norm_full_vp_width = (int)vp->full_width; - int norm_full_vp_height = (int)vp->full_height; - int scaled_screen_x = -0x8000; /* OOB */ - int scaled_screen_y = -0x8000; /* OOB */ - int scaled_x = -0x8000; /* OOB */ - int scaled_y = -0x8000; /* OOB */ + runloop_state_t *runloop_st = runloop_state_get_ptr(); + int norm_vp_width = (int)vp->width; + int norm_vp_height = (int)vp->height; + int norm_full_vp_width = (int)vp->full_width; + int norm_full_vp_height = (int)vp->full_height; + int scaled_screen_x = -0x8000; /* Legacy OOB */ + int scaled_screen_y = -0x8000; /* Legacy OOB */ + int scaled_x = -0x8000; /* Legacy OOB */ + int scaled_y = -0x8000; /* Legacy OOB */ if ( (norm_vp_width <= 0) || (norm_vp_height <= 0) || (norm_full_vp_width <= 0) @@ -722,12 +723,24 @@ bool video_driver_translate_coord_viewport( if (mouse_x >= 0 && mouse_x <= norm_vp_width) scaled_x = ((2 * mouse_x * 0x7fff) / norm_vp_width) - 0x7fff; - else - scaled_x = -0x8000; /* OOB */ + else if (runloop_st->pointer_confinement == RETRO_POINTER_CONFINEMENT_EDGE) + { + if (mouse_x < 0) + scaled_x = -0x7fff; + else + scaled_x = 0x7fff; + } if (mouse_y >= 0 && mouse_y <= norm_vp_height) scaled_y = ((2 * mouse_y * 0x7fff) / norm_vp_height) - 0x7fff; + else if (runloop_st->pointer_confinement == RETRO_POINTER_CONFINEMENT_EDGE) + { + if (mouse_y < 0) + scaled_y = -0x7fff; + else + scaled_y = 0x7fff; + } *res_x = scaled_x; *res_y = scaled_y; diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index 288512b91f..b633d1ba8a 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -432,6 +432,9 @@ extern "C" { #define RETRO_DEVICE_ID_POINTER_PRESSED 2 #define RETRO_DEVICE_ID_POINTER_COUNT 3 +/* Values for pointer confinement */ +#define RETRO_POINTER_CONFINEMENT_LEGACY 0 +#define RETRO_POINTER_CONFINEMENT_EDGE 1 /** @} */ /* Returned from retro_get_region(). */ @@ -2569,6 +2572,31 @@ enum retro_mod */ #define RETRO_ENVIRONMENT_GET_FILE_BROWSER_START_DIRECTORY 80 +/** + * Controls how the frontend should handle screen edges and off-screen for + * inputs returning screen coordinates (pointer and lightgun). + * + * Default behavior is that (0,0) coordinates are returned if cursor leaves + * the actual viewport, and resides on either the black padding area or + * outside the window (if there is one), but it is somewhat input driver + * dependent. + * + * Modified behavior is that coordinates will always be in the range of + * [-0x7fff,0x7fff], with the edge values meaning that cursor has left the + * viewport in that direction. + * + * @param[in] data const unsigned *. + * Pointer to a single \c unsigned that indicates the confinement method. + * Can point to a value of \c RETRO_POINTER_CONFINEMENT_LEGACY but this + * isn't necessary, pointer confinement support is opt-in. + * The behavior is not changed compared to the previous state if \c data + * is NULL. + * @returns \c true if the environment call is available. + * @see RETRO_DEVICE_POINTER + * @see RETRO_DEVICE_LIGHTGUN + */ +#define RETRO_ENVIRONMENT_SET_POINTER_CONFINEMENT 81 + /**@}*/ /** diff --git a/runloop.c b/runloop.c index 0e4bf6b963..751de67989 100644 --- a/runloop.c +++ b/runloop.c @@ -3586,6 +3586,13 @@ bool runloop_environment_cb(unsigned cmd, void *data) } } break; + + case RETRO_ENVIRONMENT_SET_POINTER_CONFINEMENT: + if (data) + runloop_st->pointer_confinement = *(unsigned*)data; + RARCH_LOG("[Environ]: RETRO_ENVIRONMENT_SET_POINTER_CONFINEMENT: %d\n", runloop_st->pointer_confinement); + break; + default: RARCH_LOG("[Environ]: UNSUPPORTED (#%u).\n", cmd); return false; diff --git a/runloop.h b/runloop.h index 0bc07a8fa5..49d5edd4f4 100644 --- a/runloop.h +++ b/runloop.h @@ -254,6 +254,7 @@ struct runloop unsigned subsystem_current_count; unsigned entry_state_slot; unsigned video_swap_interval_auto; + unsigned pointer_confinement; fastmotion_overrides_t fastmotion_override; /* float alignment */