[gtk-vnc-devel] PATCH: sticky modifier keys



Even with the use of a keyboard grab, there are certain key combinations
that are completely ungrabbable using regular GTK / X libraries. The prime
examples are  Ctrl-Alt-Backspace, and  Ctrl+Alt+Fn.  This isn't a problem
for traditional VNC servers, but when talking to a virtualed guest OS, then
you do need a way to send these combos to the guest OS.

This patch adds the 'sticky modifiers' concept currently used in virt-manager
Basically, if a Ctrl or Alt key is pressed 3 times in a row, then it is
treated as sticky until the next non-modifier key is released. This allows
you to type  'Ctrl Ctrl Ctrl Alt+F1'  to send 'Ctrl+Alt+F1' to the guest.
This is off by default.

Dan.
-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 
changeset:   27:3c2eb84af9ae
user:        "Daniel P. Berrange <berrange redhat com>"
date:        Fri Jul 06 13:39:41 2007 -0400
summary:     Added support for 'sticky' modifier keys

diff -r 06fb3b1e2320 -r 3c2eb84af9ae examples/gvncviewer.c
--- a/examples/gvncviewer.c	Fri Jul 06 11:40:33 2007 -0400
+++ b/examples/gvncviewer.c	Fri Jul 06 13:39:41 2007 -0400
@@ -124,6 +124,7 @@ int main(int argc, char **argv)
 	vnc_display_set_keyboard_grab(VNC_DISPLAY(vnc), TRUE);
 	vnc_display_set_pointer_grab(VNC_DISPLAY(vnc), TRUE);
 	//vnc_display_set_pointer_local(VNC_DISPLAY(vnc), TRUE);
+	vnc_display_set_sticky_modifiers(VNC_DISPLAY(vnc), TRUE);
 	vnc_display_open_name(VNC_DISPLAY(vnc), argv[1], argv[2]);
 
 	gtk_signal_connect(GTK_OBJECT(window), "delete-event",
diff -r 06fb3b1e2320 -r 3c2eb84af9ae examples/gvncviewer.py
--- a/examples/gvncviewer.py	Fri Jul 06 11:40:33 2007 -0400
+++ b/examples/gvncviewer.py	Fri Jul 06 13:39:41 2007 -0400
@@ -70,6 +70,7 @@ v.set_pointer_grab(True)
 v.set_pointer_grab(True)
 v.set_keyboard_grab(True)
 #v.set_pointer_local(True)
+v.set_sticky_modifiers(True)
 
 if len(sys.argv) == 4:
     v.set_credential(gtkvnc.CREDENTIAL_PASSWORD, sys.argv[3])
diff -r 06fb3b1e2320 -r 3c2eb84af9ae src/libgtk-vnc_sym.version
--- a/src/libgtk-vnc_sym.version	Fri Jul 06 11:40:33 2007 -0400
+++ b/src/libgtk-vnc_sym.version	Fri Jul 06 13:39:41 2007 -0400
@@ -18,6 +18,7 @@
     vnc_display_set_pointer_local;
     vnc_display_set_pointer_grab;
     vnc_display_set_keyboard_grab;
+    vnc_display_set_sticky_modifiers;
 
     vnc_display_get_width;
     vnc_display_get_height;
diff -r 06fb3b1e2320 -r 3c2eb84af9ae src/vncdisplay.c
--- a/src/vncdisplay.c	Fri Jul 06 11:40:33 2007 -0400
+++ b/src/vncdisplay.c	Fri Jul 06 13:39:41 2007 -0400
@@ -36,6 +36,9 @@ struct _VncDisplayPrivate
 	struct coroutine coroutine;
 	struct gvnc *gvnc;
 
+	guint last_keyval;
+	guint last_repeat;
+
 	gboolean in_pointer_grab;
 	gboolean in_keyboard_grab;
 
@@ -49,6 +52,7 @@ struct _VncDisplayPrivate
 	gboolean grab_pointer;
 	gboolean grab_keyboard;
 	gboolean local_pointer;
+	gboolean sticky_modifiers;
 };
 
 /* Signals */
@@ -308,16 +312,56 @@ static gboolean key_event(GtkWidget *wid
 	VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv;
 	int down;
 
-	if (priv->gvnc == NULL)
-		return TRUE;
-	
+	if (priv->gvnc == NULL || !gvnc_is_connected(priv->gvnc))
+		return TRUE;
+
+	/* Sticky key down processing */
+	if (key->type == GDK_KEY_PRESS && priv->sticky_modifiers) {
+		if (key->keyval == GDK_Control_L ||
+		    key->keyval == GDK_Control_R ||
+		    key->keyval == GDK_Alt_L ||
+		    key->keyval == GDK_Alt_R) {
+			/* Got a modifier, start counting presses */
+			if (priv->last_keyval == key->keyval) {
+				priv->last_repeat++;
+			} else {
+				priv->last_keyval = key->keyval;
+				priv->last_repeat = 1;
+			}
+		} else if (priv->last_keyval != 0 && priv->last_repeat >= 3) {
+			/* Got a non-modifier & a sticky key was active, so
+			 * send a fake key down event */
+			gvnc_key_event(priv->gvnc, 1, priv->last_keyval);
+		}
+	}
+
+
 	if (key->type == GDK_KEY_PRESS)
 		down = 1;
 	else
 		down = 0;
 
+	/* Send this real event */
 	gvnc_key_event(priv->gvnc, down, key->keyval);
 
+	/* Sticky key up processing */
+	if (key->type == GDK_KEY_RELEASE && priv->sticky_modifiers) {
+		/* If non-modifier need some sticky key processing */
+		if (key->keyval != GDK_Control_L &&
+		    key->keyval != GDK_Control_R &&
+		    key->keyval != GDK_Alt_L &&
+		    key->keyval != GDK_Alt_R) {
+			/* Have a sticky key, might need a fake key up */
+			if (priv->last_keyval != 0 &&
+			    priv->last_repeat >= 3)
+				gvnc_key_event(priv->gvnc, 0, priv->last_keyval);
+
+			/* Clear sticky key if any non-modifier was released */
+			priv->last_keyval = 0;
+		}
+	}
+
+	/* Release pointer grab with Ctrl+Alt */
 	if (key->type == GDK_KEY_PRESS &&
 	    ((key->keyval == GDK_Control_L && (key->state & GDK_MOD1_MASK)) ||
 	     (key->keyval == GDK_Alt_L && (key->state & GDK_CONTROL_MASK)))) {
@@ -840,6 +884,11 @@ void vnc_display_set_keyboard_grab(VncDi
 		do_keyboard_ungrab(obj);
 }
 
+void vnc_display_set_sticky_modifiers(VncDisplay *obj, gboolean enable)
+{
+	obj->priv->sticky_modifiers = enable;
+}
+
 
 GType vnc_display_get_type(void)
 {
diff -r 06fb3b1e2320 -r 3c2eb84af9ae src/vncdisplay.h
--- a/src/vncdisplay.h	Fri Jul 06 11:40:33 2007 -0400
+++ b/src/vncdisplay.h	Fri Jul 06 13:39:41 2007 -0400
@@ -78,6 +78,7 @@ void		vnc_display_set_pointer_local(VncD
 void		vnc_display_set_pointer_local(VncDisplay *obj, gboolean enable);
 void		vnc_display_set_pointer_grab(VncDisplay *obj, gboolean enable);
 void		vnc_display_set_keyboard_grab(VncDisplay *obj, gboolean enable);
+void		vnc_display_set_sticky_modifiers(VncDisplay *obj, gboolean enable);
 
 GdkPixbuf *     vnc_display_get_pixbuf(VncDisplay *obj);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]