[Spice-devel] [PATCH spice-gtk v3] Release keyboard grab using keyboard shortcut
Pavel Grunt
pgrunt at redhat.com
Wed Nov 19 04:39:27 PST 2014
This commit adds the ability to release the keyboard grab when
the release keys (ctrl+alt) are pressed and released. It allows
to use keyboard shortcuts (eg alt+tab, alt+f4) on the client.
The keyboard is grabbed again when the release keys are pressed
and released or when the mouse moves.
https://bugs.freedesktop.org/show_bug.cgi?id=85331
---
v3:
- don't grab when the keyboard doesn't have the focus
v2:
- add missing 'release_keys(display)' calls
---
gtk/spice-widget-priv.h | 2 ++
gtk/spice-widget.c | 50 ++++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/gtk/spice-widget-priv.h b/gtk/spice-widget-priv.h
index 9c38e2e..0e1f661 100644
--- a/gtk/spice-widget-priv.h
+++ b/gtk/spice-widget-priv.h
@@ -109,6 +109,8 @@ struct _SpiceDisplayPrivate {
guint key_delayed_id;
SpiceGrabSequence *grabseq; /* the configured key sequence */
gboolean *activeseq; /* the currently pressed keys */
+ gboolean seq_pressed;
+ gboolean keyboard_grab_released;
gint mark;
#ifdef WIN32
HHOOK keyboard_hook;
diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c
index ae11073..550d08d 100644
--- a/gtk/spice-widget.c
+++ b/gtk/spice-widget.c
@@ -719,6 +719,8 @@ static void try_keyboard_grab(SpiceDisplay *display)
return;
if (!d->mouse_have_pointer)
return;
+ if (d->keyboard_grab_released)
+ return;
g_return_if_fail(gtk_widget_is_focus(widget));
@@ -1198,6 +1200,9 @@ static void send_key(SpiceDisplay *display, int scancode, SendKeyType type, gboo
if (d->disable_inputs)
return;
+ if (d->keyboard_grab_released)
+ return;
+
i = scancode / 32;
b = scancode % 32;
m = (1 << b);
@@ -1259,7 +1264,8 @@ static void release_keys(SpiceDisplay *display)
}
}
-static gboolean check_for_grab_key(SpiceDisplay *display, int type, int keyval)
+static gboolean check_for_grab_key(SpiceDisplay *display, int type, int keyval,
+ int check_type, int reset_type)
{
SpiceDisplayPrivate *d = display->priv;
int i;
@@ -1267,13 +1273,13 @@ static gboolean check_for_grab_key(SpiceDisplay *display, int type, int keyval)
if (!d->grabseq->nkeysyms)
return FALSE;
- if (type == GDK_KEY_PRESS) {
- /* Record the new key press */
+ if (type == check_type) {
+ /* Record the new key */
for (i = 0 ; i < d->grabseq->nkeysyms ; i++)
if (d->grabseq->keysyms[i] == keyval)
d->activeseq[i] = TRUE;
- /* Return if any key is not pressed */
+ /* Return if any key is missing */
for (i = 0 ; i < d->grabseq->nkeysyms ; i++)
if (d->activeseq[i] == FALSE)
return FALSE;
@@ -1281,9 +1287,10 @@ static gboolean check_for_grab_key(SpiceDisplay *display, int type, int keyval)
/* resets the whole grab sequence on success */
memset(d->activeseq, 0, sizeof(gboolean) * d->grabseq->nkeysyms);
return TRUE;
- } else if (type == GDK_KEY_RELEASE) {
- /* Any key release resets the whole grab sequence */
+ } else if (type == reset_type) {
+ /* reset key event type resets the whole grab sequence */
memset(d->activeseq, 0, sizeof(gboolean) * d->grabseq->nkeysyms);
+ d->seq_pressed = FALSE;
return FALSE;
} else
g_warn_if_reached();
@@ -1291,6 +1298,16 @@ static gboolean check_for_grab_key(SpiceDisplay *display, int type, int keyval)
return FALSE;
}
+static gboolean check_for_grab_key_pressed(SpiceDisplay *display, int type, int keyval)
+{
+ return check_for_grab_key(display, type, keyval, GDK_KEY_PRESS, GDK_KEY_RELEASE);
+}
+
+static gboolean check_for_grab_key_released(SpiceDisplay *display, int type, int keyval)
+{
+ return check_for_grab_key(display, type, keyval, GDK_KEY_RELEASE, GDK_KEY_PRESS);
+}
+
static void update_display(SpiceDisplay *display)
{
#ifdef G_OS_WIN32
@@ -1321,7 +1338,7 @@ static gboolean key_event(GtkWidget *widget, GdkEventKey *key)
__FUNCTION__, key->type == GDK_KEY_PRESS ? "press" : "release",
key->hardware_keycode, key->state, key->group, key->is_modifier);
- if (check_for_grab_key(display, key->type, key->keyval)) {
+ if (!d->seq_pressed && check_for_grab_key_pressed(display, key->type, key->keyval)) {
g_signal_emit(widget, signals[SPICE_DISPLAY_GRAB_KEY_PRESSED], 0);
if (d->mouse_mode == SPICE_MOUSE_MODE_SERVER) {
@@ -1330,6 +1347,17 @@ static gboolean key_event(GtkWidget *widget, GdkEventKey *key)
else
try_mouse_grab(display);
}
+ d->seq_pressed = TRUE;
+ } else if (d->seq_pressed && check_for_grab_key_released(display, key->type, key->keyval)) {
+ release_keys(display);
+ if (!d->keyboard_grab_released) {
+ d->keyboard_grab_released = TRUE;
+ try_keyboard_ungrab(display);
+ } else {
+ d->keyboard_grab_released = FALSE;
+ try_keyboard_grab(display);
+ }
+ d->seq_pressed = FALSE;
}
if (!d->inputs)
@@ -1562,6 +1590,14 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
if (d->disable_inputs)
return true;
+ d->seq_pressed = FALSE;
+
+ if (d->keyboard_grab_released && d->keyboard_have_focus) {
+ d->keyboard_grab_released = FALSE;
+ release_keys(display);
+ try_keyboard_grab(display);
+ }
+
spicex_transform_input (display, motion->x, motion->y, &x, &y);
switch (d->mouse_mode) {
--
1.9.3
More information about the Spice-devel
mailing list