diff --git a/command.c b/command.c index ce82275d77..0dfd7cde36 100644 --- a/command.c +++ b/command.c @@ -204,6 +204,7 @@ static const struct cmd_map map[] = { { "OVERLAY_NEXT", RARCH_OVERLAY_NEXT }, { "DISK_EJECT_TOGGLE", RARCH_DISK_EJECT_TOGGLE }, { "DISK_NEXT", RARCH_DISK_NEXT }, + { "GRAB_MOUSE_TOGGLE", RARCH_GRAB_MOUSE_TOGGLE }, { "MENU_TOGGLE", RARCH_MENU_TOGGLE }, }; diff --git a/config.def.h b/config.def.h index 0724ab5556..50f11a7e7b 100644 --- a/config.def.h +++ b/config.def.h @@ -556,8 +556,8 @@ static const bool input_autodetect_enable = true; #define RETRO_LBL_OVERLAY_NEXT "Next Overlay" #define RETRO_LBL_DISK_EJECT_TOGGLE "Disk Eject Toggle" #define RETRO_LBL_DISK_NEXT "Disk Swap Next" +#define RETRO_LBL_GRAB_MOUSE_TOGGLE "Grab mouse toggle" #define RETRO_LBL_MENU_TOGGLE "Menu toggle" -#define RETRO_LBL_MENU_QUICKMENU_TOGGLE "Menu quickmenu toggle" // Player 1 static const struct retro_keybind retro_keybinds_1[] = { @@ -628,6 +628,7 @@ static const struct retro_keybind retro_keybinds_1[] = { { true, RARCH_OVERLAY_NEXT, RETRO_LBL_OVERLAY_NEXT, RETROK_UNKNOWN, NO_BTN, 0, AXIS_NONE }, { true, RARCH_DISK_EJECT_TOGGLE, RETRO_LBL_DISK_EJECT_TOGGLE, RETROK_UNKNOWN, NO_BTN, 0, AXIS_NONE }, { true, RARCH_DISK_NEXT, RETRO_LBL_DISK_NEXT, RETROK_UNKNOWN, NO_BTN, 0, AXIS_NONE }, + { true, RARCH_GRAB_MOUSE_TOGGLE, RETRO_LBL_GRAB_MOUSE_TOGGLE, RETROK_F11, NO_BTN, 0, AXIS_NONE }, #ifdef HAVE_RGUI { true, RARCH_MENU_TOGGLE, RETRO_LBL_MENU_TOGGLE, RETROK_F1, NO_BTN, 0, AXIS_NONE }, #endif diff --git a/driver.h b/driver.h index ff7228b874..8d1dea8429 100644 --- a/driver.h +++ b/driver.h @@ -107,6 +107,7 @@ enum // RetroArch specific bind IDs. RARCH_OVERLAY_NEXT, RARCH_DISK_EJECT_TOGGLE, RARCH_DISK_NEXT, + RARCH_GRAB_MOUSE_TOGGLE, RARCH_MENU_TOGGLE, RARCH_MENU_QUICKMENU_TOGGLE, @@ -298,6 +299,8 @@ typedef struct input_driver void (*free)(void *data); void (*set_keybinds)(void *data, unsigned device, unsigned port, unsigned id, unsigned keybind_action); const char *ident; + + void (*grab_mouse)(void *data, bool state); } input_driver_t; struct rarch_viewport; @@ -332,6 +335,9 @@ typedef struct video_poke_interface void (*set_rgui_texture)(void *data, const void *frame); #endif void (*set_osd_msg)(void *data, const char *msg, void *userdata); + + void (*show_mouse)(void *data, bool state); + void (*grab_mouse_toggle)(void *data); } video_poke_interface_t; typedef struct video_driver diff --git a/gfx/gl.c b/gfx/gl.c index 3082727197..1c1f0f0feb 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -2369,6 +2369,13 @@ static void gl_set_osd_msg(void *data, const char *msg, void *userdata) gl->font_ctx->render_msg(gl, msg, params); } +static void gl_show_mouse(void *data, bool state) +{ + gl_t *gl = (gl_t*)data; + if (gl->ctx_driver->show_mouse) + gl->ctx_driver->show_mouse(state); +} + static const video_poke_interface_t gl_poke_interface = { gl_set_blend, gl_set_filtering, @@ -2382,6 +2389,8 @@ static const video_poke_interface_t gl_poke_interface = { gl_set_rgui_texture, #endif gl_set_osd_msg, + + gl_show_mouse, }; static void gl_get_poke_interface(void *data, const video_poke_interface_t **iface) diff --git a/input/input_common.c b/input/input_common.c index 062b330b9f..b8a87352d0 100644 --- a/input/input_common.c +++ b/input/input_common.c @@ -551,6 +551,7 @@ static const struct str_to_bind_map str_to_bind[] = { { "overlay_next", RARCH_OVERLAY_NEXT }, { "disk_eject_toggle", RARCH_DISK_EJECT_TOGGLE }, { "disk_next", RARCH_DISK_NEXT }, + { "grab_mouse_toggle", RARCH_GRAB_MOUSE_TOGGLE }, { "menu_toggle", RARCH_MENU_TOGGLE }, }; diff --git a/input/x11_input.c b/input/x11_input.c index 0ebc50b01c..7994f72373 100644 --- a/input/x11_input.c +++ b/input/x11_input.c @@ -37,6 +37,8 @@ typedef struct x11_input bool mouse_l, mouse_r, mouse_m; int mouse_x, mouse_y; int mouse_last_x, mouse_last_y; + + bool grab_mouse; } x11_input_t; static void *x_input_init(void) @@ -229,6 +231,20 @@ static void x_input_poll_mouse(x11_input_t *x11) x11->mouse_l = mask & Button1Mask; x11->mouse_m = mask & Button2Mask; x11->mouse_r = mask & Button3Mask; + + // Somewhat hacky, but seem to do the job. + if (x11->grab_mouse) + { + struct rarch_viewport vp = {0}; + video_viewport_info_func(&vp); + unsigned mid_w = vp.full_width >> 1; + unsigned mid_h = vp.full_height >> 1; + XWarpPointer(x11->display, None, + x11->win, 0, 0, 0, 0, + mid_w, mid_h); + x11->mouse_last_x = mid_w; + x11->mouse_last_y = mid_h; + } } static void x_input_poll(void *data) @@ -244,6 +260,12 @@ static void x_input_poll(void *data) input_joypad_poll(x11->joypad); } +static void x_grab_mouse(void *data, bool state) +{ + x11_input_t *x11 = (x11_input_t*)data; + x11->grab_mouse = state; +} + const input_driver_t input_x = { x_input_init, x_input_poll, @@ -251,6 +273,7 @@ const input_driver_t input_x = { x_bind_button_pressed, x_input_free, NULL, - "x" + "x", + x_grab_mouse, }; diff --git a/libretro-test/libretro-test.c b/libretro-test/libretro-test.c index fccfe2252d..c2fb5645bd 100644 --- a/libretro-test/libretro-test.c +++ b/libretro-test/libretro-test.c @@ -94,6 +94,8 @@ void retro_set_video_refresh(retro_video_refresh_t cb) static unsigned x_coord; static unsigned y_coord; static unsigned phase; +static int mouse_rel_x; +static int mouse_rel_y; void retro_reset(void) { @@ -135,6 +137,17 @@ static void update_input(void) if (mouse_r) fprintf(stderr, "Mouse R pressed.\n"); + mouse_rel_x += mouse_x; + mouse_rel_y += mouse_y; + if (mouse_rel_x >= 310) + mouse_rel_x = 309; + else if (mouse_rel_x < 10) + mouse_rel_x = 10; + if (mouse_rel_y >= 230) + mouse_rel_y = 229; + else if (mouse_rel_y < 10) + mouse_rel_y = 10; + bool pointer_pressed = input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED); int16_t pointer_x = input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X); int16_t pointer_y = input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y); @@ -166,6 +179,10 @@ static void render_checkered(void) } } + for (unsigned y = mouse_rel_y - 5; y <= mouse_rel_y + 5; y++) + for (unsigned x = mouse_rel_x - 5; x <= mouse_rel_x + 5; x++) + frame_buf[y * 320 + x] = 0x1f; + video_cb(frame_buf, 320, 240, 320 << 1); } diff --git a/retroarch.c b/retroarch.c index a2cd8ffa8a..ccbb333a27 100644 --- a/retroarch.c +++ b/retroarch.c @@ -2577,6 +2577,29 @@ static void check_overlay(void) } #endif +#ifndef RARCH_CONSOLE +static void check_grab_mouse_toggle(void) +{ + static bool old_pressed; + bool pressed = input_key_pressed_func(RARCH_GRAB_MOUSE_TOGGLE) && + driver.input->grab_mouse; + + static bool grab_mouse_state; + + if (pressed && !old_pressed) + { + grab_mouse_state = !grab_mouse_state; + RARCH_LOG("Grab mouse state: %s.\n", grab_mouse_state ? "yes" : "no"); + driver.input->grab_mouse(driver.input_data, grab_mouse_state); + + if (driver.video_poke && driver.video_poke->show_mouse) + driver.video_poke->show_mouse(driver.video_data, !grab_mouse_state); + } + + old_pressed = pressed; +} +#endif + static void do_state_checks(void) { check_block_hotkey(); @@ -2591,6 +2614,10 @@ static void do_state_checks(void) check_turbo(); +#ifndef RARCH_CONSOLE + check_grab_mouse_toggle(); +#endif + #ifdef HAVE_OVERLAY check_overlay(); #endif diff --git a/retroarch.cfg b/retroarch.cfg index 966254d48d..01ad064e8c 100644 --- a/retroarch.cfg +++ b/retroarch.cfg @@ -398,6 +398,11 @@ # Toggles RGUI menu. # input_menu_toggle = f1 +# Toggles mouse grab. When mouse is grabbed, RetroArch hides the mouse, +# and keeps the mouse pointer inside the window to allow relative mouse games +# to work better. +# input_grab_mouse_toggle = f11 + #### Misc # Enable rewinding. This will take a performance hit when playing, so it is disabled by default. diff --git a/settings.c b/settings.c index a8b0b52fad..fbcc419354 100644 --- a/settings.c +++ b/settings.c @@ -840,6 +840,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][RARCH_BIND_LIST_END_NULL] = DECLARE_BIND(overlay_next, RARCH_OVERLAY_NEXT), DECLARE_BIND(disk_eject_toggle, RARCH_DISK_EJECT_TOGGLE), DECLARE_BIND(disk_next, RARCH_DISK_NEXT), + DECLARE_BIND(grab_mouse_toggle, RARCH_GRAB_MOUSE_TOGGLE), #ifdef HAVE_RGUI DECLARE_BIND(menu_toggle, RARCH_MENU_TOGGLE), #endif diff --git a/tools/retroarch-joyconfig.c b/tools/retroarch-joyconfig.c index 0f5fd3bc34..ec7910443c 100644 --- a/tools/retroarch-joyconfig.c +++ b/tools/retroarch-joyconfig.c @@ -125,6 +125,7 @@ static struct bind binds[] = { MISC_BIND("Next overlay", overlay_next), MISC_BIND("Disk eject toggle", disk_eject_toggle), MISC_BIND("Disk next cycle", disk_next), + MISC_BIND("Grab mouse toggle", grab_mouse_toggle), MISC_BIND("Menu toggle", menu_toggle), };