<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Nov 12, 2014 at 10:11 AM, Pavel Grunt <span dir="ltr"><<a href="mailto:pgrunt@redhat.com" target="_blank">pgrunt@redhat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This commit adds the ability to release the keyboard grab when<br>
the release keys (ctrl+alt) are pressed and released. It allows<br>
to use keyboard shortcuts (eg alt+tab, alt+f4) on the client.<br>
<br>
The keyboard is grabbed again when the release keys are pressed<br>
and released or when the mouse moves.<br>
<br></blockquote><div><br>There is an issue to retake the grab with the same shortcut, after pressing alt-tab. It works only if pressed 2 times.<br><br></div><div>It seems to be because the sequence is cancelled in check_for_grab_key(), I haven't investigated further.<br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<a href="https://bugs.freedesktop.org/show_bug.cgi?id=85331" target="_blank">https://bugs.freedesktop.org/show_bug.cgi?id=85331</a><br>
---<br>
v2:<br>
 - add missing 'release_keys(display)' calls<br>
---<br>
 gtk/spice-widget-priv.h |  2 ++<br>
 gtk/spice-widget.c      | 51 ++++++++++++++++++++++++++++++++++++++++++-------<br>
 2 files changed, 46 insertions(+), 7 deletions(-)<br>
<br>
diff --git a/gtk/spice-widget-priv.h b/gtk/spice-widget-priv.h<br>
index 9c38e2e..0e1f661 100644<br>
--- a/gtk/spice-widget-priv.h<br>
+++ b/gtk/spice-widget-priv.h<br>
@@ -109,6 +109,8 @@ struct _SpiceDisplayPrivate {<br>
     guint                   key_delayed_id;<br>
     SpiceGrabSequence         *grabseq; /* the configured key sequence */<br>
     gboolean                *activeseq; /* the currently pressed keys */<br>
+    gboolean                seq_pressed;<br>
+    gboolean                keyboard_grab_released;<br>
     gint                    mark;<br>
 #ifdef WIN32<br>
     HHOOK                   keyboard_hook;<br>
diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c<br>
index ae11073..aca12fe 100644<br>
--- a/gtk/spice-widget.c<br>
+++ b/gtk/spice-widget.c<br>
@@ -719,6 +719,8 @@ static void try_keyboard_grab(SpiceDisplay *display)<br>
         return;<br>
     if (!d->mouse_have_pointer)<br>
         return;<br>
+    if (d->keyboard_grab_released)<br>
+        return;<br>
<br>
     g_return_if_fail(gtk_widget_is_focus(widget));<br>
<br>
@@ -1198,6 +1200,9 @@ static void send_key(SpiceDisplay *display, int scancode, SendKeyType type, gboo<br>
     if (d->disable_inputs)<br>
         return;<br>
<br>
+    if (d->keyboard_grab_released)<br>
+        return;<br>
+<br>
     i = scancode / 32;<br>
     b = scancode % 32;<br>
     m = (1 << b);<br>
@@ -1259,7 +1264,8 @@ static void release_keys(SpiceDisplay *display)<br>
     }<br>
 }<br>
<br>
-static gboolean check_for_grab_key(SpiceDisplay *display, int type, int keyval)<br>
+static gboolean check_for_grab_key(SpiceDisplay *display, int type, int keyval,<br>
+                                   int check_type, int reset_type)<br>
 {<br>
     SpiceDisplayPrivate *d = display->priv;<br>
     int i;<br>
@@ -1267,13 +1273,13 @@ static gboolean check_for_grab_key(SpiceDisplay *display, int type, int keyval)<br>
     if (!d->grabseq->nkeysyms)<br>
         return FALSE;<br>
<br>
-    if (type == GDK_KEY_PRESS) {<br>
-        /* Record the new key press */<br>
+    if (type == check_type) {<br>
+        /* Record the new key */<br>
         for (i = 0 ; i < d->grabseq->nkeysyms ; i++)<br>
             if (d->grabseq->keysyms[i] == keyval)<br>
                 d->activeseq[i] = TRUE;<br>
<br>
-        /* Return if any key is not pressed */<br>
+        /* Return if any key is missing */<br>
         for (i = 0 ; i < d->grabseq->nkeysyms ; i++)<br>
             if (d->activeseq[i] == FALSE)<br>
                 return FALSE;<br>
@@ -1281,9 +1287,10 @@ static gboolean check_for_grab_key(SpiceDisplay *display, int type, int keyval)<br>
         /* resets the whole grab sequence on success */<br>
         memset(d->activeseq, 0, sizeof(gboolean) * d->grabseq->nkeysyms);<br>
         return TRUE;<br>
-    } else if (type == GDK_KEY_RELEASE) {<br>
-        /* Any key release resets the whole grab sequence */<br>
+    } else if (type == reset_type) {<br>
+        /* reset key event type resets the whole grab sequence */<br>
         memset(d->activeseq, 0, sizeof(gboolean) * d->grabseq->nkeysyms);<br>
+        d->seq_pressed = FALSE;<br>
         return FALSE;<br>
     } else<br>
         g_warn_if_reached();<br>
@@ -1291,6 +1298,16 @@ static gboolean check_for_grab_key(SpiceDisplay *display, int type, int keyval)<br>
     return FALSE;<br>
 }<br>
<br>
+static gboolean check_for_grab_key_pressed(SpiceDisplay *display, int type, int keyval)<br>
+{<br>
+    return check_for_grab_key(display, type, keyval, GDK_KEY_PRESS, GDK_KEY_RELEASE);<br>
+}<br>
+<br>
+static gboolean check_for_grab_key_released(SpiceDisplay *display, int type, int keyval)<br>
+{<br>
+    return check_for_grab_key(display, type, keyval, GDK_KEY_RELEASE, GDK_KEY_PRESS);<br>
+}<br>
+<br>
 static void update_display(SpiceDisplay *display)<br>
 {<br>
 #ifdef G_OS_WIN32<br>
@@ -1321,7 +1338,7 @@ static gboolean key_event(GtkWidget *widget, GdkEventKey *key)<br>
             __FUNCTION__, key->type == GDK_KEY_PRESS ? "press" : "release",<br>
             key->hardware_keycode, key->state, key->group, key->is_modifier);<br>
<br>
-    if (check_for_grab_key(display, key->type, key->keyval)) {<br>
+    if (!d->seq_pressed && check_for_grab_key_pressed(display, key->type, key->keyval)) {<br>
         g_signal_emit(widget, signals[SPICE_DISPLAY_GRAB_KEY_PRESSED], 0);<br>
<br>
         if (d->mouse_mode == SPICE_MOUSE_MODE_SERVER) {<br>
@@ -1330,6 +1347,17 @@ static gboolean key_event(GtkWidget *widget, GdkEventKey *key)<br>
             else<br>
                 try_mouse_grab(display);<br>
         }<br>
+        d->seq_pressed = TRUE;<br>
+    } else if (d->seq_pressed && check_for_grab_key_released(display, key->type, key->keyval)) {<br>
+        release_keys(display);<br>
+        if (!d->keyboard_grab_released) {<br>
+            d->keyboard_grab_released = TRUE;<br>
+            try_keyboard_ungrab(display);<br>
+        } else {<br>
+            d->keyboard_grab_released = FALSE;<br>
+            try_keyboard_grab(display);<br>
+        }<br>
+        d->seq_pressed = FALSE;<br>
     }<br>
<br>
     if (!d->inputs)<br>
@@ -1562,6 +1590,15 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)<br>
     if (d->disable_inputs)<br>
         return true;<br>
<br>
+    if (d->seq_pressed)<br>
+        d->seq_pressed = FALSE;<br></blockquote><div><br></div><div>You could set it unconditionaly<br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+    if (d->keyboard_grab_released) {<br>
+        d->keyboard_grab_released = FALSE;<br>
+        release_keys(display);<br>
+        try_keyboard_grab(display);<br>
+    }<br>
+<br>
     spicex_transform_input (display, motion->x, motion->y, &x, &y);<br>
<br>
     switch (d->mouse_mode) {<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.9.3<br>
<br>
_______________________________________________<br>
Spice-devel mailing list<br>
<a href="mailto:Spice-devel@lists.freedesktop.org">Spice-devel@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/spice-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/spice-devel</a><br>
</font></span></blockquote></div><br><br clear="all"></div><div class="gmail_extra">looks good otherwise<br><br></div><div class="gmail_extra">-- <br><div class="gmail_signature">Marc-André Lureau</div>
</div></div>