From 82a60a9917e14e182c40bfc269d093d245a3b6f8 Mon Sep 17 00:00:00 2001
From: Laszlo Ersek <lersek@redhat.com>
Date: Wed, 21 Mar 2012 10:43:01 +0100
Subject: [PATCH 4/4] vnc: lift modifier keys on client disconnect

RH-Author: Laszlo Ersek <lersek@redhat.com>
Message-id: <1332326581-7609-1-git-send-email-lersek@redhat.com>
Patchwork-id: 38777
O-Subject: [RHEL-6.3 qemu-kvm PATCH v2 2/2] vnc: lift modifier keys on client disconnect
Bugzilla: 785963
RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com>
RH-Acked-by: Amos Kong <akong@redhat.com>
RH-Acked-by: Alex Williamson <alex.williamson@redhat.com>

From: Gerd Hoffmann <kraxel@redhat.com>

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: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 7bc9318bfb68b2d773449a55d4fa800d0fdb0918)

Conflicts:

	vnc.c

v1->v2: adapted to 0f8cc78d ("vnc: Migrate to using QTAILQ instead of
custom implementation").

Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 vnc.c |   25 +++++++++++++++++++++++++
 1 files changed, 25 insertions(+), 0 deletions(-)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
 vnc.c |   25 +++++++++++++++++++++++++
 1 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/vnc.c b/vnc.c
index 5df8467..15cb39c 100644
--- a/vnc.c
+++ b/vnc.c
@@ -45,6 +45,7 @@
     } \
 }
 
+static void vnc_release_modifiers(VncState *vs);
 
 static VncDisplay *vnc_display; /* needed for info vnc */
 static DisplayChangeListener *dcl;
@@ -1110,6 +1111,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);
 
@@ -1703,6 +1705,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;
-- 
1.7.7.6

