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

Pointer sanitization: Android, overlay, and other enhancements #17308

Merged
merged 1 commit into from
Dec 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 35 additions & 22 deletions input/drivers/android_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ typedef struct
struct input_pointer
{
int16_t x, y;
int16_t confined_x, confined_y;
int16_t full_x, full_y;
};

Expand Down Expand Up @@ -818,16 +819,20 @@ static INLINE void android_input_poll_event_type_motion(

for (motion_ptr = 0; motion_ptr < pointer_max; motion_ptr++)
{
struct video_viewport vp;
struct video_viewport vp = {0};
float x = AMotionEvent_getX(event, motion_ptr);
float y = AMotionEvent_getY(event, motion_ptr);

vp.x = 0;
vp.y = 0;
vp.width = 0;
vp.height = 0;
vp.full_width = 0;
vp.full_height = 0;
/* On other platforms, pointer query uses the confined wrap function, *
* but some extra functionality is added to Android which needs the *
* true offscreen value -0x8000, so both variants are called. */
video_driver_translate_coord_viewport_confined_wrap(
&vp,
x, y,
&android->pointer[motion_ptr].confined_x,
&android->pointer[motion_ptr].confined_y,
&android->pointer[motion_ptr].full_x,
&android->pointer[motion_ptr].full_y);

video_driver_translate_coord_viewport_wrap(
&vp,
Expand Down Expand Up @@ -1733,10 +1738,8 @@ static int16_t android_input_state(
case RETRO_DEVICE_MOUSE:
case RARCH_DEVICE_MOUSE_SCREEN:
{
/* Same mouse state is reported for all ports. */
int val = 0;
if (port > 0)
break; /* TODO: implement mouse for additional ports/players */

switch (id)
{
case RETRO_DEVICE_ID_MOUSE_LEFT:
Expand Down Expand Up @@ -1774,11 +1777,15 @@ static int16_t android_input_state(
break;
case RETRO_DEVICE_LIGHTGUN:
{
/* Same lightgun state is reported for all ports. */
int val = 0;
if (port > 0)
break; /* TODO: implement lightgun for additional ports/players */
switch (id)
{
case RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X:
return android->pointer[idx].x;
case RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y:
return android->pointer[idx].y;
/* Deprecated relative lightgun. */
case RETRO_DEVICE_ID_LIGHTGUN_X:
val = android->mouse_x_delta;
android->mouse_x_delta = 0;
Expand All @@ -1789,39 +1796,45 @@ static int16_t android_input_state(
android->mouse_y_delta = 0;
/* flush delta after it has been read */
return val;
case RETRO_DEVICE_ID_LIGHTGUN_TRIGGER:
return android->mouse_l || android_check_quick_tap(android);
case RETRO_DEVICE_ID_LIGHTGUN_CURSOR:
return android->mouse_m;
case RETRO_DEVICE_ID_LIGHTGUN_TURBO:
return android->mouse_r;
case RETRO_DEVICE_ID_LIGHTGUN_RELOAD:
return android->mouse_m || android->pointer_count == 3;
case RETRO_DEVICE_ID_LIGHTGUN_SELECT:
return android->mouse_r && android->mouse_l;
case RETRO_DEVICE_ID_LIGHTGUN_START:
return android->mouse_m && android->mouse_r;
case RETRO_DEVICE_ID_LIGHTGUN_PAUSE:
return android->mouse_m && android->mouse_l;
case RETRO_DEVICE_ID_LIGHTGUN_TURBO:
return android->mouse_r || android->pointer_count == 2;
case RETRO_DEVICE_ID_LIGHTGUN_TRIGGER:
return android->mouse_l || android_check_quick_tap(android) || android->pointer_count == 1;
case RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN:
return input_driver_pointer_is_offscreen(android->pointer[idx].x, android->pointer[idx].y);
}
}
break;
case RETRO_DEVICE_POINTER:
case RARCH_DEVICE_POINTER_SCREEN:
/* Same pointer state is reported for all ports. */
switch (id)
{
case RETRO_DEVICE_ID_POINTER_X:
if (device == RARCH_DEVICE_POINTER_SCREEN)
return android->pointer[idx].full_x;
return android->pointer[idx].x;
return android->pointer[idx].confined_x;
case RETRO_DEVICE_ID_POINTER_Y:
if (device == RARCH_DEVICE_POINTER_SCREEN)
return android->pointer[idx].full_y;
return android->pointer[idx].y;
return android->pointer[idx].confined_y;
case RETRO_DEVICE_ID_POINTER_PRESSED:
/* On mobile platforms, touches outside screen / core viewport are not reported. */
if (device == RARCH_DEVICE_POINTER_SCREEN)
return (idx < android->pointer_count) &&
(android->pointer[idx].full_x != -0x8000) &&
(android->pointer[idx].full_y != -0x8000);
return (idx < android->pointer_count) &&
(android->pointer[idx].x != -0x8000) &&
(android->pointer[idx].y != -0x8000);
case RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN:
return input_driver_pointer_is_offscreen(android->pointer[idx].x, android->pointer[idx].y);
case RETRO_DEVICE_ID_POINTER_COUNT:
return android->pointer_count;
case RARCH_DEVICE_ID_POINTER_BACK:
Expand Down
21 changes: 16 additions & 5 deletions input/drivers/udev_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -3685,7 +3685,7 @@ static bool udev_mouse_button_pressed(
}

static int16_t udev_pointer_state(udev_input_t *udev,
unsigned port, unsigned id, bool screen)
unsigned port, unsigned idx, unsigned id, bool screen)
{
udev_input_mouse_t *mouse = udev_get_mouse(udev, port);
int16_t res_x;
Expand All @@ -3701,8 +3701,19 @@ static int16_t udev_pointer_state(udev_input_t *udev,
return res_y;
case RETRO_DEVICE_ID_POINTER_PRESSED:
if (mouse->abs == 1)
return mouse->pp;
return mouse->l;
{
if (idx == 0)
return mouse->pp;
else
return 0;
}
/* Simulate max. 3 touches with mouse buttons*/
else if (idx == 0)
return (mouse->l | mouse->r | mouse->m);
else if (idx == 1)
return (mouse->r | mouse->m);
else if (idx == 2)
return mouse->m;
case RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN:
return input_driver_pointer_is_offscreen(res_x, res_y);
}
Expand Down Expand Up @@ -3828,8 +3839,8 @@ static int16_t udev_input_state(
return udev_input_touch_state(udev, pointer_dev, binds,
keyboard_mapping_blocked, port, device, idx, id);
#endif
if (idx == 0) /* multi-touch unsupported (for now) */
return udev_pointer_state(udev, port, id,
if (idx < 3)
return udev_pointer_state(udev, port, idx, id,
device == RARCH_DEVICE_POINTER_SCREEN);
break;

Expand Down
56 changes: 29 additions & 27 deletions input/drivers/wayland_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,16 @@ static int16_t input_wl_touch_state(input_ctx_wayland_data_t *wl,
{
if (idx <= MAX_TOUCHES)
{
struct video_viewport vp;
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;

vp.x = 0;
vp.y = 0;
vp.width = 0;
vp.height = 0;
vp.full_width = 0;
vp.full_height = 0;
/* Shortcut: mouse button events will be reported on desktop with 0/0 coordinates. *
* Skip these, mouse handling will catch it elsewhere. */
if (wl->touches[idx].x == 0 && wl->touches[idx].y == 0)
return 0;

if (video_driver_translate_coord_viewport_confined_wrap(&vp,
wl->touches[idx].x, wl->touches[idx].y,
Expand All @@ -132,17 +130,14 @@ static int16_t input_wl_touch_state(input_ctx_wayland_data_t *wl,
res_y = res_screen_y;
}

if ((res_x >= -0x7fff) && (res_y >= -0x7fff)) /* Inside? */
switch (id)
{
switch (id)
{
case RETRO_DEVICE_ID_POINTER_X:
return res_x;
case RETRO_DEVICE_ID_POINTER_Y:
return res_y;
case RETRO_DEVICE_ID_POINTER_PRESSED:
return wl->touches[idx].active;
}
case RETRO_DEVICE_ID_POINTER_X:
return res_x;
case RETRO_DEVICE_ID_POINTER_Y:
return res_y;
case RETRO_DEVICE_ID_POINTER_PRESSED:
return wl->touches[idx].active;
}
}
}
Expand Down Expand Up @@ -301,8 +296,18 @@ static int16_t input_wl_state(
}
break;
case RETRO_DEVICE_POINTER:
case RARCH_DEVICE_POINTER_SCREEN:
/* All ports report the same pointer state. See notes at mouse case. */
if (idx == 0)
if (idx < MAX_TOUCHES)
{
int16_t touch_state = input_wl_touch_state(wl, idx, id,
device == RARCH_DEVICE_POINTER_SCREEN);
/* Touch state is only reported if it is meaningful. */
if (touch_state)
return touch_state;
}
/* Fall through to system pointer emulating max. 3 touches. */
if (idx < 3)
{
struct video_viewport vp = {0};
bool screen =
Expand All @@ -329,7 +334,12 @@ static int16_t input_wl_state(
case RETRO_DEVICE_ID_POINTER_Y:
return res_y;
case RETRO_DEVICE_ID_POINTER_PRESSED:
return wl->mouse.left;
if (idx == 0)
return (wl->mouse.left | wl->mouse.right | wl->mouse.middle);
else if (idx == 1)
return (wl->mouse.right | wl->mouse.middle);
else if (idx == 2)
return wl->mouse.middle;
case RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN:
return input_driver_pointer_is_offscreen(res_x, res_y);
default:
Expand All @@ -338,14 +348,6 @@ static int16_t input_wl_state(
}
}
break;
case RARCH_DEVICE_POINTER_SCREEN:
if (port == 0) /* TODO/FIXME: support pointers on additional ports */
{
if (idx < MAX_TOUCHES)
return input_wl_touch_state(wl, idx, id,
device == RARCH_DEVICE_POINTER_SCREEN);
}
break;
case RETRO_DEVICE_LIGHTGUN:
/* All ports report the same lightgun state. See notes at mouse case. */
{
Expand Down
10 changes: 8 additions & 2 deletions input/drivers/x11_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ static int16_t x_input_state(
break;
case RETRO_DEVICE_POINTER:
case RARCH_DEVICE_POINTER_SCREEN:
if (idx == 0)
/* Map up to 3 touches to mouse buttons. */
if (idx < 3)
{
struct video_viewport vp = {0};
bool screen =
Expand All @@ -268,7 +269,12 @@ static int16_t x_input_state(
case RETRO_DEVICE_ID_POINTER_Y:
return res_y;
case RETRO_DEVICE_ID_POINTER_PRESSED:
return x11->mouse_l;
if (idx == 0)
return (x11->mouse_l | x11->mouse_r | x11->mouse_m);
else if (idx == 1)
return (x11->mouse_r | x11->mouse_m);
else if (idx == 2)
return x11->mouse_m;
case RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN:
return input_driver_pointer_is_offscreen(res_x, res_y);
}
Expand Down
54 changes: 14 additions & 40 deletions input/input_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -1207,64 +1207,36 @@ static int16_t input_overlay_lightgun_state(settings_t *settings,

switch(id)
{
/* Pointer positions have been clamped earlier in input drivers, *
* so if we want to pass true offscreen value, it must be detected */
case RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X:
ptr_st->device_mask |= (1 << RETRO_DEVICE_LIGHTGUN);

if ( ptr_st->ptr[0].x != -0x8000
|| settings->bools.input_overlay_lightgun_allow_offscreen)
if ( ( ptr_st->ptr[0].x > -0x7fff && ptr_st->ptr[0].x != 0x7fff)
|| !settings->bools.input_overlay_lightgun_allow_offscreen)
return ptr_st->ptr[0].x;
else if (video_driver_get_viewport_info(&vp))
{
edge = ((2 * vp.x * 0x7fff) / (int)vp.full_width) - 0x7fff;
return ((ptr_st->screen_x > edge) ? 0x7fff : -0x7fff);
}
return -0x8000;
else
return -0x8000;
case RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y:
if ( ptr_st->ptr[0].y != -0x8000
|| settings->bools.input_overlay_lightgun_allow_offscreen)
if ( ( ptr_st->ptr[0].y > -0x7fff && ptr_st->ptr[0].y != 0x7fff)
|| !settings->bools.input_overlay_lightgun_allow_offscreen)
return ptr_st->ptr[0].y;
else if (video_driver_get_viewport_info(&vp))
{
edge = ((2 * vp.y * 0x7fff) / (int)vp.full_height) - 0x7fff;
return ((ptr_st->screen_y > edge) ? 0x7fff : -0x7fff);
}
return -0x8000;
else
return -0x8000;
case RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN:
return ( settings->bools.input_overlay_lightgun_allow_offscreen
&& (ptr_st->ptr[0].x == -0x8000 || ptr_st->ptr[0].y == -0x8000));
return input_driver_pointer_is_offscreen(ptr_st->ptr[0].x, ptr_st->ptr[0].y);
case RETRO_DEVICE_ID_LIGHTGUN_AUX_A:
rarch_id = RARCH_LIGHTGUN_AUX_A;
break;
case RETRO_DEVICE_ID_LIGHTGUN_AUX_B:
rarch_id = RARCH_LIGHTGUN_AUX_B;
break;
case RETRO_DEVICE_ID_LIGHTGUN_AUX_C:
rarch_id = RARCH_LIGHTGUN_AUX_C;
break;
case RETRO_DEVICE_ID_LIGHTGUN_TRIGGER:
rarch_id = RARCH_LIGHTGUN_TRIGGER;
break;
case RETRO_DEVICE_ID_LIGHTGUN_START:
case RETRO_DEVICE_ID_LIGHTGUN_PAUSE:
rarch_id = RARCH_LIGHTGUN_START;
break;
case RETRO_DEVICE_ID_LIGHTGUN_SELECT:
rarch_id = RARCH_LIGHTGUN_SELECT;
break;
case RETRO_DEVICE_ID_LIGHTGUN_RELOAD:
rarch_id = RARCH_LIGHTGUN_RELOAD;
break;
case RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP:
rarch_id = RARCH_LIGHTGUN_DPAD_UP;
break;
case RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN:
rarch_id = RARCH_LIGHTGUN_DPAD_DOWN;
break;
case RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT:
rarch_id = RARCH_LIGHTGUN_DPAD_LEFT;
break;
case RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT:
rarch_id = RARCH_LIGHTGUN_DPAD_RIGHT;
rarch_id = input_driver_lightgun_id_convert(id);
break;
default:
rarch_id = RARCH_BIND_LIST_END;
Expand Down Expand Up @@ -1294,6 +1266,8 @@ static int16_t input_overlay_pointer_state(input_overlay_t *ol,
&& ptr_st->ptr[idx].y != -0x8000;
case RETRO_DEVICE_ID_POINTER_COUNT:
return ptr_st->count;
case RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN:
return input_driver_pointer_is_offscreen(ptr_st->ptr[idx].x, ptr_st->ptr[idx].y);
}

return 0;
Expand Down
Loading