From afc46d8f3ba54c0a3b536d1ce05b3f8b4743cf17 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 13 Sep 2013 14:22:17 +0100 Subject: [PATCH] Only trigger grab sequence upon release For https://bugzilla.redhat.com/show_bug.cgi?id=1007877 GTK-VNC uses the keyboard shortcut ctrl+alt to toggle inside/outside the VM (aka release pointer). Now Gnome uses ctrl+alt+arrow_key to switch virtual desktops. So these two shortcuts collide and gtk-vnc will grab the key presses as soon as ctrl+alt is pressed and toogle inside/outside the VM, which makes switching desktops impossible. The solution is to only trigger the grab sequence when the user releases the key. So if they press Ctrl+alt and then release it, we trigger, but if they press Ctrl+alt+left-arrow we don't trigger https://bugzilla.gnome.org/show_bug.cgi?id=685257 Signed-off-by: Daniel P. Berrange (cherry picked from commit af4fc65182f8a51d81fab2d7e46bc4a11a9da452) --- src/vncdisplay.c | 50 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/src/vncdisplay.c b/src/vncdisplay.c index 37de008..51a6b0f 100644 --- a/src/vncdisplay.c +++ b/src/vncdisplay.c @@ -80,6 +80,7 @@ struct _VncDisplayPrivate size_t keycode_maplen; const guint16 *keycode_map; + gboolean vncgrabpending; /* Key sequence detected, waiting for release */ VncGrabSequence *vncgrabseq; /* the configured key sequence */ gboolean *vncactiveseq; /* the currently pressed keys */ }; @@ -784,6 +785,17 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion) } +/* + * Lets say the grab sequence of Ctrl_L + Alt_L + * + * We first need to detect when both Ctrl_L and Alt_L are pressed. + * When this happens we are "primed" to tigger. + * + * If any further key is pressed though, we unprime ourselves + * + * If any key is released while we are primed, then we + * trigger. + */ static gboolean check_for_grab_key(GtkWidget *widget, int type, int keyval) { VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv; @@ -793,23 +805,42 @@ static gboolean check_for_grab_key(GtkWidget *widget, int type, int keyval) return FALSE; if (type == GDK_KEY_RELEASE) { + gboolean active = priv->vncgrabpending; /* Any key release resets the whole grab sequence */ memset(priv->vncactiveseq, 0, sizeof(gboolean)*priv->vncgrabseq->nkeysyms); - - return FALSE; + priv->vncgrabpending = FALSE; + return active; } else { + gboolean setone = FALSE; + /* Record the new key press */ - for (i = 0 ; i < priv->vncgrabseq->nkeysyms ; i++) - if (priv->vncgrabseq->keysyms[i] == keyval) + for (i = 0 ; i < priv->vncgrabseq->nkeysyms ; i++) { + if (priv->vncgrabseq->keysyms[i] == keyval) { priv->vncactiveseq[i] = TRUE; + setone = TRUE; + } + } - /* Return if any key is not pressed */ - for (i = 0 ; i < priv->vncgrabseq->nkeysyms ; i++) - if (priv->vncactiveseq[i] == FALSE) - return FALSE; + if (setone) { + /* Return if any key is not pressed */ + for (i = 0 ; i < priv->vncgrabseq->nkeysyms ; i++) + if (priv->vncactiveseq[i] == FALSE) + return FALSE; - return TRUE; + /* All keys in grab seq are pressed, so prime + * to trigger on release + */ + priv->vncgrabpending = TRUE; + } else { + /* Key not in grab seq, so must reset any pending + * grab keys we have */ + memset(priv->vncactiveseq, 0, + sizeof(gboolean)*priv->vncgrabseq->nkeysyms); + priv->vncgrabpending = FALSE; + } + + return FALSE; } } @@ -2238,6 +2269,7 @@ void vnc_display_set_pointer_grab(VncDisplay *obj, gboolean enable) */ void vnc_display_set_grab_keys(VncDisplay *obj, VncGrabSequence *seq) { + obj->priv->vncgrabpending = FALSE; if (obj->priv->vncgrabseq) { vnc_grab_sequence_free(obj->priv->vncgrabseq); g_free(obj->priv->vncactiveseq);