From: rongyichang <[email protected]> When using absolute coordinate input devices (e.g. virtio-tablet-device), the SDL display backend implements a "soft grab" where the mouse is automatically grabbed when it enters the window interior and ungrabbed when it hits the window edge. This edge-ungrab behavior causes problems in embedded emulation scenarios:
1. Mouse escapes the SDL window at edges 2. SDL does not deliver BUTTONUP events for the escaped mouse 3. The guest gets stuck in a pressed/touch-down state 4. First click back into the window is silently dropped This issue is confirmed as a known SDL limitation (SDL issue #5301). Add a new -display sdl,grab-on-tablet=on option that makes absolute coordinate devices use the same grab behavior as relative (mouse) devices: user must click to grab, Ctrl+Alt+G to release, and no automatic grab on window enter or edge-based ungrab/regrab. Signed-off-by: Yichang Rong <[email protected]> --- qapi/ui.json | 8 +++++++- qemu-options.hx | 9 +++++++-- ui/sdl2.c | 16 +++++++++++++--- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/qapi/ui.json b/qapi/ui.json index b2c42a7f57..454d9041bf 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1477,10 +1477,16 @@ # @grab-mod: Modifier keys that should be pressed together with the # "G" key to release the mouse grab. # +# @grab-on-tablet: When enabled, the mouse grab is required even for +# tablet (absolute) input devices. This is useful when the guest +# OS uses a tablet device but you still want click-to-grab +# semantics (e.g. NuttX touchscreen emulation). +# # Since: 7.1 ## { 'struct' : 'DisplaySDL', - 'data' : { '*grab-mod' : 'HotKeyMod' } } + 'data' : { '*grab-mod' : 'HotKeyMod', + '*grab-on-tablet' : 'bool' } } ## # @DisplayType: diff --git a/qemu-options.hx b/qemu-options.hx index 96ae41f787..1e1836312c 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2205,8 +2205,8 @@ DEF("display", HAS_ARG, QEMU_OPTION_display, "-display spice-app[,gl=on|off]\n" #endif #if defined(CONFIG_SDL) - "-display sdl[,gl=on|core|es|off][,grab-mod=<mod>][,show-cursor=on|off]\n" - " [,window-close=on|off]\n" + "-display sdl[,gl=on|core|es|off][,grab-mod=<mod>][,grab-on-tablet=on|off]\n" + " [,show-cursor=on|off][,window-close=on|off]\n" #endif #if defined(CONFIG_GTK) "-display gtk[,clipboard=on|off][,full-screen=on|off][,gl=on|off]\n" @@ -2284,6 +2284,11 @@ SRST the mouse grabbing in conjunction with the "g" key. ``<mods>`` can be either ``lshift-lctrl-lalt`` or ``rctrl``. + ``grab-on-tablet=on|off`` : When enabled, the mouse grab is required + even for tablet (absolute) input devices. This is useful when the + guest OS uses a tablet device but you still want click-to-grab + semantics. + ``gl=on|off|core|es`` : Use OpenGL for displaying ``show-cursor=on|off`` : Force showing the mouse cursor diff --git a/ui/sdl2.c b/ui/sdl2.c index 4fcdbd79d3..af94ae8500 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -46,6 +46,7 @@ static SDL_Surface *guest_sprite_surface; static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ static bool alt_grab; static bool ctrl_grab; +static bool grab_on_tablet; static int gui_saved_grab; static int gui_fullscreen; @@ -504,7 +505,8 @@ static void handle_mousemotion(SDL_Event *ev) } SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); - if (qemu_input_is_absolute(scon->dcl.con) || absolute_enabled) { + if ((qemu_input_is_absolute(scon->dcl.con) || absolute_enabled) && + !grab_on_tablet) { max_x = scr_w - 1; max_y = scr_h - 1; if (gui_grab && !gui_fullscreen @@ -545,7 +547,8 @@ static void handle_mousebutton(SDL_Event *ev) x = (int64_t)bev->x * surface_width(scon->surface) / scr_w; y = (int64_t)bev->y * surface_height(scon->surface) / scr_h; - if (!gui_grab && !qemu_input_is_absolute(scon->dcl.con)) { + if (!gui_grab && + (!qemu_input_is_absolute(scon->dcl.con) || grab_on_tablet)) { if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) { /* start grabbing all events */ sdl_grab_start(scon); @@ -614,7 +617,10 @@ static void handle_windowevent(SDL_Event *ev) case SDL_WINDOWEVENT_FOCUS_GAINED: /* fall through */ case SDL_WINDOWEVENT_ENTER: - if (!gui_grab && (qemu_input_is_absolute(scon->dcl.con) || absolute_enabled)) { + if (!gui_grab && + (qemu_input_is_absolute(scon->dcl.con) || + absolute_enabled) && + !grab_on_tablet) { absolute_mouse_grab(scon); } /* If a new console window opened using a hotkey receives the @@ -921,6 +927,10 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) } } + if (o->u.sdl.has_grab_on_tablet) { + grab_on_tablet = o->u.sdl.grab_on_tablet; + } + for (i = 0;; i++) { QemuConsole *con = qemu_console_lookup_by_index(i); if (!con) { -- 2.49.1
