1
0
mirror of https://github.com/libretro/RetroArch synced 2025-02-28 12:40:23 +00:00

Merge pull request from jdgleaver/x11-mouse-grab-fix

(X11) Fix mouse input when mouse is grabbed
This commit is contained in:
Autechre 2021-01-16 16:15:16 +01:00 committed by GitHub
commit 40b3e4c00f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 174 additions and 70 deletions

@ -37,11 +37,15 @@ typedef struct x11_input
Display *display;
Window win;
int mouse_x, mouse_y;
int mouse_last_x, mouse_last_y;
int mouse_x;
int mouse_y;
int mouse_delta_x;
int mouse_delta_y;
bool mouse_grabbed;
char state[32];
bool mouse_l, mouse_r, mouse_m;
bool mouse_l;
bool mouse_r;
bool mouse_m;
} x11_input_t;
/* Public global variable */
@ -222,11 +226,11 @@ static int16_t x_input_state(
case RETRO_DEVICE_ID_MOUSE_X:
if (device == RARCH_DEVICE_MOUSE_SCREEN)
return x11->mouse_x;
return x11->mouse_x - x11->mouse_last_x;
return x11->mouse_delta_x;
case RETRO_DEVICE_ID_MOUSE_Y:
if (device == RARCH_DEVICE_MOUSE_SCREEN)
return x11->mouse_y;
return x11->mouse_y - x11->mouse_last_y;
return x11->mouse_delta_y;
case RETRO_DEVICE_ID_MOUSE_LEFT:
return x11->mouse_l;
case RETRO_DEVICE_ID_MOUSE_RIGHT:
@ -592,9 +596,9 @@ static int16_t x_input_state(
break;
/*deprecated*/
case RETRO_DEVICE_ID_LIGHTGUN_X:
return x11->mouse_x - x11->mouse_last_x;
return x11->mouse_delta_x;
case RETRO_DEVICE_ID_LIGHTGUN_Y:
return x11->mouse_y - x11->mouse_last_y;
return x11->mouse_delta_y;
case RETRO_DEVICE_ID_LIGHTGUN_PAUSE:
{
unsigned new_id = RARCH_LIGHTGUN_START;
@ -637,71 +641,140 @@ static void x_input_free(void *data)
static void x_input_poll(void *data)
{
unsigned mask;
int root_x, root_y, win_x, win_y;
Window root_win, child_win;
Window root_win;
Window child_win;
x11_input_t *x11 = (x11_input_t*)data;
bool video_has_focus = video_driver_has_focus();
int root_x = 0;
int root_y = 0;
int win_x = 0;
int win_y = 0;
unsigned mask = 0;
if (video_has_focus)
XQueryKeymap(x11->display, x11->state);
else
memset(x11->state, 0, sizeof(x11->state));
x11->mouse_last_x = x11->mouse_x;
x11->mouse_last_y = x11->mouse_y;
XQueryPointer(x11->display,
x11->win,
&root_win, &child_win,
&root_x, &root_y,
&win_x, &win_y,
&mask);
if (g_x11_entered)
/* If window loses focus, 'reset' keyboard
* and ignore mouse input */
if (!video_has_focus)
{
x11->mouse_x = win_x;
x11->mouse_y = win_y;
x11->mouse_l = mask & Button1Mask;
x11->mouse_m = mask & Button2Mask;
x11->mouse_r = mask & Button3Mask;
memset(x11->state, 0, sizeof(x11->state));
x11->mouse_delta_x = 0;
x11->mouse_delta_y = 0;
x11->mouse_l = 0;
x11->mouse_m = 0;
x11->mouse_r = 0;
return;
}
/* Major grab kludge required to circumvent
* absolute pointer area limitation
* AND to be able to use mouse in menu
*/
if (x11->mouse_grabbed && video_has_focus)
/* If pointer is not inside the application
* window, ignore mouse input */
if (!g_x11_entered)
{
x11->mouse_delta_x = 0;
x11->mouse_delta_y = 0;
x11->mouse_l = 0;
x11->mouse_m = 0;
x11->mouse_r = 0;
return;
}
/* Process keyboard */
XQueryKeymap(x11->display, x11->state);
/* Process mouse */
if (!XQueryPointer(x11->display,
x11->win,
&root_win, &child_win,
&root_x, &root_y,
&win_x, &win_y,
&mask))
return;
/* > Mouse buttons */
x11->mouse_l = mask & Button1Mask;
x11->mouse_m = mask & Button2Mask;
x11->mouse_r = mask & Button3Mask;
/* > Mouse pointer */
if (!x11->mouse_grabbed)
{
/* Mouse is not grabbed - this corresponds
* to 'conventional' pointer input, using
* absolute screen coordinates */
int mouse_last_x = x11->mouse_x;
int mouse_last_y = x11->mouse_y;
x11->mouse_x = win_x;
x11->mouse_y = win_y;
x11->mouse_delta_x = x11->mouse_x - mouse_last_x;
x11->mouse_delta_y = x11->mouse_y - mouse_last_y;
}
else
{
/* Mouse is grabbed - all pointer movement
* must be considered 'relative' */
XWindowAttributes win_attr;
int centre_x;
int centre_y;
int warp_x = win_x;
int warp_y = win_y;
bool do_warp = false;
/* Get dimensions/centre coordinates of
* application window */
if (!XGetWindowAttributes(x11->display, x11->win, &win_attr))
{
int new_x = win_x, new_y = win_y;
int margin = 0;
float margin_pct = 0.05f;
struct video_viewport vp;
x11->mouse_delta_x = 0;
x11->mouse_delta_y = 0;
return;
}
video_driver_get_viewport_info(&vp);
centre_x = win_attr.width >> 1;
centre_y = win_attr.height >> 1;
margin = ((vp.full_height < vp.full_width) ? vp.full_height : vp.full_width) * margin_pct;
/* Get relative movement delta since last
* poll event */
x11->mouse_delta_x = win_x - centre_x;
x11->mouse_delta_y = win_y - centre_y;
if (win_x + 1 > vp.full_width - margin)
new_x = vp.full_width - margin;
else if (win_x + 1 < margin)
new_x = margin;
/* Get effective 'absolute' pointer location
* (last position + delta, bounded by current
* application window dimensions) */
x11->mouse_x += x11->mouse_delta_x;
x11->mouse_x = (x11->mouse_x < 0) ? 0 : x11->mouse_x;
x11->mouse_x = (x11->mouse_x >= win_attr.width) ? (win_attr.width - 1) : x11->mouse_x;
if (win_y + 1 > vp.full_height - margin)
new_y = vp.full_height - margin;
else if (win_y + 1 < margin)
new_y = margin;
x11->mouse_y += x11->mouse_delta_y;
x11->mouse_y = (x11->mouse_y < 0) ? 0 : x11->mouse_y;
x11->mouse_y = (x11->mouse_y >= win_attr.height) ? (win_attr.height - 1) : x11->mouse_y;
if (new_x != win_x || new_y != win_y)
{
XWarpPointer(x11->display, None, x11->win,
0, 0, 0 ,0,
new_x, new_y);
/* Hack/workaround:
* - X11 gives absolute pointer coordinates
* - Once the pointer reaches a screen edge
* it cannot go any further
* - To achieve 'relative' motion, we therefore
* have to reset the hardware cursor to the
* centre of the screen after polling each
* movement delta, such that it is always
* free to move in all directions during the
* time interval until the next poll event */
if (win_x != centre_x)
{
warp_x = centre_x;
do_warp = true;
}
XSync(x11->display, False);
}
if (win_y != centre_y)
{
warp_y = centre_y;
do_warp = true;
}
x11->mouse_last_x = new_x + x11->mouse_last_x - x11->mouse_x;
x11->mouse_last_y = new_y + x11->mouse_last_y - x11->mouse_y;
if (do_warp)
{
XWarpPointer(x11->display, None,
x11->win, 0, 0, 0, 0,
warp_x, warp_y);
XSync(x11->display, False);
}
}
}

@ -6606,6 +6606,7 @@ static void materialui_frame(void *data, video_frame_info_t *video_info)
unsigned
materialui_color_theme = video_info->materialui_color_theme;
bool video_fullscreen = video_info->fullscreen;
bool mouse_grabbed = video_info->input_driver_grab_mouse_state;
bool menu_mouse_enable = video_info->menu_mouse_enable;
gfx_animation_t *p_anim = anim_get_ptr();
@ -6791,14 +6792,14 @@ static void materialui_frame(void *data, video_frame_info_t *video_info)
/* Draw mouse cursor */
if (mui->mouse_show && (mui->pointer.type != MENU_POINTER_DISABLED))
{
float color_white[16] = {
float color_white[16] = {
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
bool cursor_visible = video_fullscreen
&& menu_mouse_enable;
bool cursor_visible = (video_fullscreen || mouse_grabbed) &&
menu_mouse_enable;
if (cursor_visible)
gfx_display_draw_cursor(

@ -2780,6 +2780,7 @@ static void ozone_frame(void *data, video_frame_info_t *video_info)
float menu_framebuffer_opacity = video_info->menu_framebuffer_opacity;
bool libretro_running = video_info->libretro_running;
bool video_fullscreen = video_info->fullscreen;
bool mouse_grabbed = video_info->input_driver_grab_mouse_state;
bool menu_mouse_enable = video_info->menu_mouse_enable;
bool input_menu_swap_ok_cancel_buttons = video_info->input_menu_swap_ok_cancel_buttons;
bool battery_level_enable = video_info->battery_level_enable;
@ -3032,7 +3033,8 @@ static void ozone_frame(void *data, video_frame_info_t *video_info)
/* Cursor */
if (ozone->show_cursor && (ozone->pointer.type != MENU_POINTER_DISABLED))
{
bool cursor_visible = video_fullscreen && menu_mouse_enable;
bool cursor_visible = (video_fullscreen || mouse_grabbed) &&
menu_mouse_enable;
gfx_display_set_alpha(ozone->pure_white, 1.0f);
if (cursor_visible)

@ -2791,6 +2791,7 @@ static void stripes_frame(void *data, video_frame_info_t *video_info)
float xmb_alpha_factor = video_info->xmb_alpha_factor;
bool xmb_shadows_enable = video_info->xmb_shadows_enable;
bool video_fullscreen = video_info->fullscreen;
bool mouse_grabbed = video_info->input_driver_grab_mouse_state;
bool menu_mouse_enable = video_info->menu_mouse_enable;
const float under_thumb_margin = 0.96;
float scale_factor = 0.0f;
@ -3029,8 +3030,8 @@ static void stripes_frame(void *data, video_frame_info_t *video_info)
if (stripes->mouse_show)
{
menu_input_pointer_t pointer;
bool cursor_visible = video_fullscreen
&& menu_mouse_enable;
bool cursor_visible = (video_fullscreen || mouse_grabbed) &&
menu_mouse_enable;
menu_input_get_pointer_state(&pointer);

@ -4653,6 +4653,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info)
bool timedate_enable = video_info->timedate_enable;
bool battery_level_enable = video_info->battery_level_enable;
bool video_fullscreen = video_info->fullscreen;
bool mouse_grabbed = video_info->input_driver_grab_mouse_state;
bool menu_mouse_enable = video_info->menu_mouse_enable;
unsigned xmb_color_theme = video_info->xmb_color_theme;
bool libretro_running = video_info->libretro_running;
@ -5286,8 +5287,8 @@ static void xmb_frame(void *data, video_frame_info_t *video_info)
/* Cursor image */
if (xmb->mouse_show)
{
bool cursor_visible = video_fullscreen
&& menu_mouse_enable;
bool cursor_visible = (video_fullscreen || mouse_grabbed) &&
menu_mouse_enable;
gfx_display_set_alpha(coord_white, MIN(xmb->alpha, 1.00f));
if (cursor_visible)

@ -14389,8 +14389,10 @@ bool command_event(enum event_command cmd, void *data)
break;
case CMD_EVENT_GRAB_MOUSE_TOGGLE:
{
bool ret = false;
bool ret = false;
bool grab_mouse_state = p_rarch->input_driver_grab_mouse_state;
bool video_fullscreen =
settings->bools.video_fullscreen || p_rarch->rarch_force_fullscreen;
grab_mouse_state = !grab_mouse_state;
@ -14408,7 +14410,7 @@ bool command_event(enum event_command cmd, void *data)
if (grab_mouse_state)
video_driver_hide_mouse();
else
else if (!video_fullscreen)
video_driver_show_mouse();
}
break;
@ -24762,6 +24764,12 @@ bool input_key_pressed(int key, bool keyboard_pressed)
key);
}
bool input_mouse_grabbed(void)
{
struct rarch_state *p_rarch = &rarch_st;
return p_rarch->input_driver_grab_mouse_state;
}
int16_t button_is_pressed(
const input_device_driver_t *joypad,
rarch_joypad_info_t *joypad_info,
@ -29880,7 +29888,15 @@ static bool video_driver_init_internal(bool *video_is_threaded)
if ((enum rotation)settings->uints.screen_orientation != ORIENTATION_NORMAL)
video_display_server_set_screen_orientation((enum rotation)settings->uints.screen_orientation);
if (video.fullscreen)
/* Ensure that we preserve the 'grab mouse'
* state if it was enabled prior to driver
* (re-)initialisation */
if (p_rarch->input_driver_grab_mouse_state)
{
video_driver_hide_mouse();
input_driver_grab_mouse(p_rarch);
}
else if (video.fullscreen)
{
video_driver_hide_mouse();
if (!settings->bools.video_windowed_fullscreen)
@ -31514,6 +31530,8 @@ void video_driver_build_info(video_frame_info_t *video_info)
video_info->runloop_is_slowmotion = p_rarch->runloop_slowmotion;
video_info->input_driver_nonblock_state = p_rarch->input_driver_nonblock_state;
video_info->input_driver_grab_mouse_state = p_rarch->input_driver_grab_mouse_state;
video_info->userdata = VIDEO_DRIVER_GET_PTR_INTERNAL(false);
#ifdef HAVE_THREADS

@ -1182,6 +1182,7 @@ typedef struct video_frame_info
bool widgets_is_rewinding;
bool input_menu_swap_ok_cancel_buttons;
bool input_driver_nonblock_state;
bool input_driver_grab_mouse_state;
bool hard_sync;
bool fps_show;
bool memory_show;
@ -1981,6 +1982,8 @@ void retroarch_init_task_queue(void);
bool input_key_pressed(int key, bool keyboard_pressed);
bool input_mouse_grabbed(void);
const char *joypad_driver_name(unsigned i);
void joypad_driver_reinit(void *data, const char *joypad_driver_name);

@ -656,6 +656,7 @@ static void ui_companion_qt_toggle(void *data, bool force)
settings_t *settings = config_get_ptr();
bool ui_companion_toggle = settings->bools.ui_companion_toggle;
bool video_fullscreen = settings->bools.video_fullscreen;
bool mouse_grabbed = input_mouse_grabbed();
if (ui_companion_toggle || force)
{
@ -664,7 +665,11 @@ static void ui_companion_qt_toggle(void *data, bool force)
win_handle->qtWindow->activateWindow();
win_handle->qtWindow->raise();
if (mouse_grabbed)
command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL);
video_driver_show_mouse();
win_handle->qtWindow->show();
if (video_driver_started_fullscreen())