Commit 7bc9318b authored by Gerd Hoffmann's avatar Gerd Hoffmann
Browse files

vnc: lift modifier keys on client disconnect.



For any modifier key (shift, ctrl, alt) still pressed on disconnect
inject a key-up event into the guest.  The vnc client is gone, it will
not do that, so qemu has to do it instead.

Without this keys will get stuck, making the guest act in weird ways
after reconnecting.  Reproducer: exit vnc client via Alt-F4, guest
continues to see the pressed alt key and will not react to key events
in any useful way until you tap the alt key once to unstuck it.

Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
parent 8cf36489
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ static VncDisplay *vnc_display; /* needed for info vnc */
static DisplayChangeListener *dcl;

static int vnc_cursor_define(VncState *vs);
static void vnc_release_modifiers(VncState *vs);

static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
{
@@ -1051,6 +1052,7 @@ static void vnc_disconnect_finish(VncState *vs)
    vnc_sasl_client_cleanup(vs);
#endif /* CONFIG_VNC_SASL */
    audio_del(vs);
    vnc_release_modifiers(vs);

    QTAILQ_REMOVE(&vs->vd->clients, vs, next);

@@ -1679,6 +1681,29 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
    }
}

static void vnc_release_modifiers(VncState *vs)
{
    static const int keycodes[] = {
        /* shift, control, alt keys, both left & right */
        0x2a, 0x36, 0x1d, 0x9d, 0x38, 0xb8,
    };
    int i, keycode;

    if (!is_graphic_console()) {
        return;
    }
    for (i = 0; i < ARRAY_SIZE(keycodes); i++) {
        keycode = keycodes[i];
        if (!vs->modifiers_state[keycode]) {
            continue;
        }
        if (keycode & SCANCODE_GREY) {
            kbd_put_keycode(SCANCODE_EMUL0);
        }
        kbd_put_keycode(keycode | SCANCODE_UP);
    }
}

static void key_event(VncState *vs, int down, uint32_t sym)
{
    int keycode;