[gtk-vnc] Install hook for Windows key code handling
- From: Daniel P. Berrange <dberrange src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk-vnc] Install hook for Windows key code handling
- Date: Fri, 6 Feb 2015 15:27:04 +0000 (UTC)
commit 590c344ad3340dfabb9985c98f418ce2fcae7b44
Author: Daniel P. Berrange <berrange redhat com>
Date: Fri Feb 6 13:39:48 2015 +0000
Install hook for Windows key code handling
To fix handling of AltGr keys on Windows displays, install a
hook for Windows keycode handling. This is copied from code
in SPICE-GTK
https://bugzilla.gnome.org/show_bug.cgi?id=731825
src/vncdisplay.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 101 insertions(+), 2 deletions(-)
---
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index b990f97..5ac9492 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -40,6 +40,11 @@
#include <sys/stat.h>
#include <unistd.h>
+#ifdef G_OS_WIN32
+#include <windows.h>
+#include <gdk/gdkwin32.h>
+#endif
+
#define VNC_DISPLAY_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE((obj), VNC_TYPE_DISPLAY, VncDisplayPrivate))
@@ -83,6 +88,10 @@ struct _VncDisplayPrivate
gboolean vncgrabpending; /* Key sequence detected, waiting for release */
VncGrabSequence *vncgrabseq; /* the configured key sequence */
gboolean *vncactiveseq; /* the currently pressed keys */
+
+#ifdef WIN32
+ HHOOK keyboard_hook;
+#endif
};
G_DEFINE_TYPE(VncDisplay, vnc_display, GTK_TYPE_DRAWING_AREA)
@@ -285,6 +294,44 @@ static GdkCursor *create_null_cursor(void)
return cursor;
}
+#ifdef G_OS_WIN32
+static HWND win32_window = NULL;
+
+static LRESULT CALLBACK keyboard_hook_cb(int code, WPARAM wparam, LPARAM lparam)
+{
+ if (win32_window && code == HC_ACTION && wparam != WM_KEYUP) {
+ KBDLLHOOKSTRUCT *hooked = (KBDLLHOOKSTRUCT*)lparam;
+ DWORD dwmsg = (hooked->flags << 24) | (hooked->scanCode << 16) | 1;
+
+ if (hooked->vkCode == VK_NUMLOCK || hooked->vkCode == VK_RSHIFT) {
+ dwmsg &= ~(1 << 24);
+ SendMessage(win32_window, wparam, hooked->vkCode, dwmsg);
+ }
+ switch (hooked->vkCode) {
+ case VK_CAPITAL:
+ case VK_SCROLL:
+ case VK_NUMLOCK:
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ case VK_RCONTROL:
+ case VK_LMENU:
+ case VK_RMENU:
+ break;
+ case VK_LCONTROL:
+ /* When pressing AltGr, an extra VK_LCONTROL with a special
+ * scancode with bit 9 set is sent. Let's ignore the extra
+ * VK_LCONTROL, as that will make AltGr misbehave. */
+ if (hooked->scanCode & 0x200)
+ return 1;
+ break;
+ default:
+ SendMessage(win32_window, wparam, hooked->vkCode, dwmsg);
+ return 1;
+ }
+ }
+ return CallNextHookEx(NULL, code, wparam, lparam);
+}
+#endif
static void setup_surface_cache(VncDisplay *dpy, cairo_t *crWin, int w, int h)
{
@@ -513,7 +560,15 @@ static void do_keyboard_grab(VncDisplay *obj, gboolean quiet)
{
VncDisplayPrivate *priv = obj->priv;
+#ifdef G_OS_WIN32
+ if (priv->keyboard_hook == NULL)
+ priv->keyboard_hook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_hook_cb,
+ GetModuleHandle(NULL), 0);
+ g_warn_if_fail(priv->keyboard_hook != NULL);
+#endif
+
do_keyboard_grab_all(gtk_widget_get_window(GTK_WIDGET(obj)));
+
priv->in_keyboard_grab = TRUE;
if (!quiet)
g_signal_emit(obj, signals[VNC_KEYBOARD_GRAB], 0);
@@ -525,6 +580,14 @@ static void do_keyboard_ungrab(VncDisplay *obj, gboolean quiet)
VncDisplayPrivate *priv = obj->priv;
do_keyboard_ungrab_all(gtk_widget_get_window(GTK_WIDGET(obj)));
+
+#ifdef G_OS_WIN32
+ if (priv->keyboard_hook != NULL) {
+ UnhookWindowsHookEx(priv->keyboard_hook);
+ priv->keyboard_hook = NULL;
+ }
+#endif
+
priv->in_keyboard_grab = FALSE;
if (!quiet)
g_signal_emit(obj, signals[VNC_KEYBOARD_UNGRAB], 0);
@@ -884,6 +947,19 @@ static gboolean key_event(GtkWidget *widget, GdkEventKey *key)
key->type == GDK_KEY_PRESS ? "press" : "release",
key->hardware_keycode, key->state, key->group, keyval);
+#ifdef G_OS_WIN32
+ /* on windows, we ought to ignore the reserved key event? */
+ if (key->hardware_keycode == 0xff)
+ return FALSE;
+
+ if (!priv->in_keyboard_grab) {
+ if (key->hardware_keycode == VK_LWIN ||
+ key->hardware_keycode == VK_RWIN ||
+ key->hardware_keycode == VK_APPS)
+ return FALSE;
+ }
+#endif
+
keyval = vnc_display_keyval_from_keycode(key->hardware_keycode, keyval);
/*
@@ -972,6 +1048,10 @@ static gboolean enter_event(GtkWidget *widget, GdkEventCrossing *crossing G_GNUC
if (priv->local_pointer)
do_pointer_show(VNC_DISPLAY(widget));
+#ifdef G_OS_WIN32
+ win32_window = GDK_WINDOW_HWND(gtk_widget_get_window(widget));
+#endif
+
return TRUE;
}
@@ -1014,7 +1094,22 @@ static void release_keys(VncDisplay *display)
}
}
-static gboolean focus_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_UNUSED)
+static gboolean focus_in_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_UNUSED)
+{
+ VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv;
+
+ if (priv->conn == NULL || !vnc_connection_is_initialized(priv->conn))
+ return FALSE;
+
+#ifdef G_OS_WIN32
+ win32_window = GDK_WINDOW_HWND(gtk_widget_get_window(widget));
+#endif
+
+ return TRUE;
+}
+
+
+static gboolean focus_out_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_UNUSED)
{
VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv;
@@ -1022,6 +1117,9 @@ static gboolean focus_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_UNUSE
return FALSE;
release_keys(VNC_DISPLAY(widget));
+#ifdef G_OS_WIN32
+ win32_window = NULL;
+#endif
return TRUE;
}
@@ -1852,7 +1950,8 @@ static void vnc_display_class_init(VncDisplayClass *klass)
gtkwidget_class->key_release_event = key_event;
gtkwidget_class->enter_notify_event = enter_event;
gtkwidget_class->leave_notify_event = leave_event;
- gtkwidget_class->focus_out_event = focus_event;
+ gtkwidget_class->focus_in_event = focus_in_event;
+ gtkwidget_class->focus_out_event = focus_out_event;
gtkwidget_class->grab_notify = grab_notify;
gtkwidget_class->realize = realize_event;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]