Fix keystate tracking

This commit is contained in:
Daniel P. Berrange 2008-01-15 21:33:45 +00:00
parent f9150d3177
commit 16aebe50a6
2 changed files with 125 additions and 1 deletions

View File

@ -0,0 +1,119 @@
changeset: 111:95f570fc49e1
user: "Daniel P. Berrange <berrange@redhat.com>"
date: Wed Jan 09 23:54:24 2008 -0500
files: src/vncdisplay.c
description:
Track keystate & send fake events for GTK key-repeat flaw & to reset state on focus out
diff -r 73b4f4043cb5 -r 95f570fc49e1 src/vncdisplay.c
--- a/src/vncdisplay.c Tue Jan 01 14:57:39 2008 -0600
+++ b/src/vncdisplay.c Wed Jan 09 23:54:24 2008 -0500
@@ -43,6 +43,8 @@ struct _VncDisplayPrivate
gboolean in_pointer_grab;
gboolean in_keyboard_grab;
+
+ guint down_keyval[16];
int button_mask;
int last_x;
@@ -392,7 +394,58 @@ static gboolean key_event(GtkWidget *wid
&level,
&consumed);
- gvnc_key_event(priv->gvnc, key->type == GDK_KEY_PRESS ? 1 : 0, keyval);
+ /*
+ * More VNC suckiness with key state & modifiers in particular
+ *
+ * Because VNC has no concept of modifiers, we have to track what keys are
+ * pressed and when the widget looses focus send fake key up events for all
+ * keys current held down. This is because upon gaining focus any keys held
+ * down are no longer likely to be down. This would thus result in keys
+ * being 'stuck on' in the remote server. eg upon Alt-Tab to switch window
+ * focus you'd never see key up for the Alt or Tab keys without this :-(
+ *
+ * This is mostly a problem with modifier keys, but its best to just track
+ * all key presses regardless. There's a limit to how many keys a user can
+ * press at once due to a max of 10 fingers (normally :-), so down_key_vals
+ * is only storing upto 16 for now. Should be plenty...
+ *
+ * Arggggh.
+ */
+ if (key->type == GDK_KEY_PRESS) {
+ int i;
+ for (i = 0 ; i < (int)(sizeof(priv->down_keyval)/sizeof(priv->down_keyval[0])) ; i++) {
+ if (priv->down_keyval[i] == 0) {
+ priv->down_keyval[i] = keyval;
+ /* Send the actual key event we're dealing with */
+ gvnc_key_event(priv->gvnc, 1, keyval);
+ break;
+ } else if (priv->down_keyval[i] == keyval) {
+ /* Got an press when we're already pressed ! Why ... ?
+ *
+ * Well, GTK merges sequential press+release pairs of the same
+ * key so instead of press+release,press+release,press+release
+ * we only get press+press+press+press+press+release. This
+ * really annoys some VNC servers, so we have to un-merge
+ * them into a sensible stream of press+release pairs
+ */
+ /* Fake an up event for the previous down event */
+ gvnc_key_event(priv->gvnc, 0, keyval);
+ /* Now send our actual ldown event */
+ gvnc_key_event(priv->gvnc, 1, keyval);
+ }
+ }
+ } else {
+ int i;
+ for (i = 0 ; i < (int)(sizeof(priv->down_keyval)/sizeof(priv->down_keyval[0])) ; i++) {
+ /* We were pressed, and now we're released, so... */
+ if (priv->down_keyval[i] == keyval) {
+ priv->down_keyval[i] = 0;
+ /* ..send the key releae event we're dealing with */
+ gvnc_key_event(priv->gvnc, 0, keyval);
+ break;
+ }
+ }
+ }
if (key->type == GDK_KEY_PRESS &&
((keyval == GDK_Control_L && (key->state & GDK_MOD1_MASK)) ||
@@ -436,6 +489,28 @@ static gboolean leave_event(GtkWidget *w
if (priv->grab_keyboard)
do_keyboard_ungrab(VNC_DISPLAY(widget), FALSE);
+
+ return TRUE;
+}
+
+
+static gboolean focus_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_UNUSED,
+ gpointer data G_GNUC_UNUSED)
+{
+ VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv;
+ int i;
+
+ if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc))
+ return TRUE;
+
+ for (i = 0 ; i < (int)(sizeof(priv->down_keyval)/sizeof(priv->down_keyval[0])) ; i++) {
+ /* We are currently pressed so... */
+ if (priv->down_keyval[i] != 0) {
+ /* ..send the fake key releae event to match */
+ gvnc_key_event(priv->gvnc, 0, priv->down_keyval[i]);
+ priv->down_keyval[i] = 0;
+ }
+ }
return TRUE;
}
@@ -1128,6 +1203,8 @@ static void vnc_display_init(VncDisplay
G_CALLBACK(enter_event), NULL);
g_signal_connect(obj, "leave-notify-event",
G_CALLBACK(leave_event), NULL);
+ g_signal_connect(obj, "focus-out-event",
+ G_CALLBACK(focus_event), NULL);
GTK_WIDGET_SET_FLAGS(obj, GTK_CAN_FOCUS);

View File

@ -3,10 +3,11 @@
Summary: A GTK widget for VNC clients
Name: gtk-vnc
Version: 0.3.2
Release: 1%{?dist}
Release: 2%{?dist}
License: LGPLv2+
Group: Development/Libraries
Source: http://downloads.sourceforge.net/%{name}/%{name}-%{version}.tar.gz
Patch1: %{name}-%{version}-keystate-tracking.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
URL: http://gtk-vnc.sf.net/
BuildRequires: gtk2-devel pygtk2-devel python-devel gnutls-devel zlib-devel
@ -41,6 +42,7 @@ A module allowing use of the GTK-VNC widget from python
%prep
%setup -q
%patch1 -p1
%build
%configure
@ -80,6 +82,9 @@ rm -fr %{buildroot}
%{_libdir}/python*/site-packages/gtkvnc.so
%changelog
* Mon Jan 14 2008 Daniel P. Berrange <berrange@redhat.com> - 0.3.2-2.fc9
- Track keystate to avoid stuck modifier keys
* Mon Dec 31 2007 Daniel P. Berrange <berrange@redhat.com> - 0.3.2-1.fc9
- Update to 0.3.2 release
- Added dep on zlib-devel