From afc46d8f3ba54c0a3b536d1ce05b3f8b4743cf17 Mon Sep 17 00:00:00 2001
From: "Daniel P. Berrange" <berrange@redhat.com>
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 <berrange@redhat.com>
(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);