sdl2 mouse pointer issue

BALATON Zoltan posted 1 patch 1 month, 2 weeks ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/91023e77-8838-c89f-481f-86174ee830e1@eik.bme.hu
Maintainers: "Marc-André Lureau" <marcandre.lureau@redhat.com>
sdl2 mouse pointer issue
Posted by BALATON Zoltan 1 month, 2 weeks ago
Hello,

There's a long standing bug with -display sdl that host side mouse pointer 
does not follow guest or jumps around or otherwise behaves erratically. 
There are several tickets about this as well but gitlab does not make it 
easy to find them so these are just a few I think might be related, there 
might be more:

https://gitlab.com/qemu-project/qemu/-/work_items/1550
https://gitlab.com/qemu-project/qemu/-/work_items/2960
https://gitlab.com/qemu-project/qemu/-/work_items/2948

I can also reproduce it with

qemu-system-ppc -M pegasos2 -display sdl -device ati-vga -kernel boot.img -cdrom morphos.iso

(boot.img is from the root dir of the morphos iso). Mouse pointer mostly 
works as long as don't move it too fast or you don't switch to full screen 
with Ctrl+Alt+F then it does not work even if you switch back to window. 
This can be avoided using disabling host side cursor with -device 
ati-vga,guest_hwcursor=on.

After not finding any cause in ati-vga I've added some diagnostics to sdl 
backend:

diff --git a/ui/sdl2.c b/ui/sdl2.c
index aaaede56e0..4f625365ab 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -333,6 +333,7 @@ static void sdl_send_mouse_event(struct sdl2_console *scon, int dx, int dy,
         qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_Y,
                              y, 0, surface_height(scon->surface));
     } else {
+fprintf(stderr,"%s(%d,%d,%d,%d,%d), %d %d,%d,",__func__,dx,dy,x,y,state,guest_cursor,guest_x,guest_y);
         if (guest_cursor) {
             x -= guest_x;
             y -= guest_y;
@@ -341,6 +342,7 @@ static void sdl_send_mouse_event(struct sdl2_console *scon, int dx, int dy,
             dx = x;
             dy = y;
         }
+fprintf(stderr," -> %d,%d %d,%d\n",dx,dy,guest_x,guest_y);
         qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_X, dx);
         qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_Y, dy);
     }
@@ -525,6 +527,7 @@ static void handle_mousemotion(SDL_Event *ev)
     dx = (int64_t)ev->motion.xrel * surf_w / scr_w;
     dy = (int64_t)ev->motion.yrel * surf_h / scr_h;
     if (gui_grab || qemu_input_is_absolute(scon->dcl.con) || absolute_enabled) {
+fprintf(stderr, "%s(%d,%d,%d,%d, %d,%d,%d,%d)\n",__func__,surf_w,surf_h,scr_w,scr_h,x,y,dx,dy);
         sdl_send_mouse_event(scon, dx, dy, x, y, ev->motion.state);
     }
 }
@@ -750,6 +753,7 @@ static void sdl_mouse_warp(DisplayChangeListener *dcl,
     } else if (gui_grab) {
         sdl_hide_cursor(scon);
     }
+fprintf(stderr,"%s(%d,%d,%d)\n",__func__,x,y,on);
     guest_cursor = on;
     guest_x = x, guest_y = y;
 }

and got this output just booting the iso without clicking in the window or 
moving the mouse. First this is the guest moving the cursor by writing the 
HW cursor register for position to place the pointer in the middle:

sdl_mouse_warp(1024,576,1)
sdl_mouse_warp(1024,576,1)
sdl_mouse_warp(1024,576,1)
sdl_mouse_warp(1024,576,1)

then just switching to full screen with Crtl+Alt+F without moving the 
mouse in the guest I get these:

handle_mousemotion(2048,1152,2560,1440, 655,368,0,0)
sdl_send_mouse_event(0,0,655,368,0), 1 1024,576, -> -369,-208 655,368
sdl_mouse_warp(286,160,1)
handle_mousemotion(2048,1152,2560,1440, 182,102,0,0)
sdl_send_mouse_event(0,0,182,102,0), 1 286,160, -> -104,-58 182,102
sdl_mouse_warp(78,44,1)
handle_mousemotion(2048,1152,2560,1440, 49,28,0,0)
sdl_send_mouse_event(0,0,49,28,0), 1 78,44, -> -29,-16 49,28
sdl_mouse_warp(20,12,1)
handle_mousemotion(2048,1152,2560,1440, 12,7,0,0)
sdl_send_mouse_event(0,0,12,7,0), 1 20,12, -> -8,-5 12,7
sdl_mouse_warp(4,2,1)
handle_mousemotion(2048,1152,2560,1440, 2,0,0,0)
sdl_send_mouse_event(0,0,2,0,0), 1 4,2, -> -2,-2 2,0
sdl_mouse_warp(2,0,1)
handle_mousemotion(2048,1152,2560,1440, 0,0,0,0)
sdl_send_mouse_event(0,0,0,0,0), 1 2,0, -> -2,0 0,0
sdl_mouse_warp(0,0,1)
handle_mousemotion(2048,1152,2560,1440, 0,0,0,0)
sdl_send_mouse_event(0,0,0,0,0), 1 0,0, -> 0,0 0,0
sdl_mouse_warp(0,0,1)
handle_mousemotion(2048,1152,2560,1440, 0,0,0,0)
sdl_send_mouse_event(0,0,0,0,0), 1 0,0, -> 0,0 0,0
sdl_mouse_warp(0,0,1)

The pointer is moved to the top left without any input from the user and 
cannot leave it any more (less severe cases could cause laggy mouse 
pointer or other issues). Trying to move the mouse afterwards can only 
move vertically.

On the ati-vga side writing CUR_HORZ_VERT_POSN register that the guest 
does to move the HW cursor calls

dpy_mouse_set(s->vga.con, s->regs.cur_hv_pos >> 16,
              s->regs.cur_hv_pos & 0xffff, true);

which ends up in sdl_mouse_warp that sets guest_x,guest_y but then other 
parts of sdl.c also try to also set it differently. That's what I could 
find out but I don't understand how it should work and why it doesn't. It 
looks like there is some confusion about what guest_x and guest_y should 
be. Could somebody give some clue how this could be fixed? Or even better 
fix it as I'm quite lost on this.

Thank you,
BALATON Zoltan