[gtk-vnc-devel] [PATCH] Raw scancode VNC extension



I wanted to get this patch in the last release but the key-repeat stuff Dan added didn't work with it. Right now, I'm bypassing it but I'd like to properly fix it for the next release.

This extension is exactly as described before with one important difference, we have a space for keys that are not part of the standard PC keyboard. I've committed this patch to get it out of my queue but I expect it needs some more work.

Regards,

Anthony Liguori
# HG changeset patch
# User Anthony Liguori <anthony codemonkey ws>
# Date 1201983848 21600
# Node ID 2d87caab4637907fd58f133f96d2b9d0bd905ce6
# Parent  a3bcd91c40e8d217e2c751341ff3f9619b5f5d02
Support VNC Scancode extension.

diff -r a3bcd91c40e8 -r 2d87caab4637 src/Makefile.am
--- a/src/Makefile.am	Sat Feb 02 14:14:09 2008 -0600
+++ b/src/Makefile.am	Sat Feb 02 14:24:08 2008 -0600
@@ -13,7 +13,7 @@ libgtk_vnc_1_0_la_LDFLAGS = -Wl,--versio
                             -version-info 0:1:0
 
 gtk_vnc_includedir = $(includedir)/gtk-vnc-1.0/
-gtk_vnc_include_HEADERS = vncdisplay.h gvnc.h
+gtk_vnc_include_HEADERS = vncdisplay.h
 
 libgtk_vnc_1_0_la_SOURCES = blt.h blt1.h \
 	coroutine.h \
@@ -21,6 +21,7 @@ libgtk_vnc_1_0_la_SOURCES = blt.h blt1.h
 	gvnc.h gvnc.c \
 	vncdisplay.h vncdisplay.c \
         vncmarshal.h vncmarshal.c \
+	x_keymap.h x_keymap.c vnc_keycodes.h \
 	utils.h
 
 if WITH_UCONTEXT
diff -r a3bcd91c40e8 -r 2d87caab4637 src/gvnc.c
--- a/src/gvnc.c	Sat Feb 02 14:14:09 2008 -0600
+++ b/src/gvnc.c	Sat Feb 02 14:24:08 2008 -0600
@@ -31,11 +31,17 @@
 #include "coroutine.h"
 #include "d3des.h"
 
+#include "x_keymap.h"
+
 #include "utils.h"
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
 
 #include <zlib.h>
+
+#include <gdk/gdkkeysyms.h>
+
+#include "vnc_keycodes.h"
 
 struct wait_queue
 {
@@ -158,6 +164,8 @@ struct gvnc
 
 	uint8_t zrle_pi;
 	int zrle_pi_bits;
+
+	gboolean has_ext_key_event;
 };
 
 #define nibhi(a) (((a) >> 4) & 0x0F)
@@ -815,6 +823,7 @@ gboolean gvnc_set_encodings(struct gvnc 
 	uint8_t pad[1] = {0};
 	int i;
 
+	gvnc->has_ext_key_event = FALSE;
 	gvnc_write_u8(gvnc, 2);
 	gvnc_write(gvnc, pad, 1);
 	gvnc_write_u16(gvnc, n_encoding);
@@ -879,14 +888,29 @@ static void gvnc_buffered_flush(struct g
 	g_io_wakeup(&gvnc->wait);
 }
 
-gboolean gvnc_key_event(struct gvnc *gvnc, uint8_t down_flag, uint32_t key)
+gboolean gvnc_key_event(struct gvnc *gvnc, uint8_t down_flag,
+			uint32_t key, uint16_t scancode)
 {
 	uint8_t pad[2] = {0};
 
-	gvnc_buffered_write_u8(gvnc, 4);
-	gvnc_buffered_write_u8(gvnc, down_flag);
-	gvnc_buffered_write(gvnc, pad, 2);
-	gvnc_buffered_write_u32(gvnc, key);
+	if (gvnc->has_ext_key_event) {
+		if (key == GDK_Pause)
+			scancode = VKC_PAUSE;
+		else
+			scancode = x_keycode_to_pc_keycode(scancode);
+
+		gvnc_buffered_write_u8(gvnc, 255);
+		gvnc_buffered_write_u8(gvnc, 0);
+		gvnc_buffered_write_u16(gvnc, down_flag);
+		gvnc_buffered_write_u32(gvnc, key);
+		gvnc_buffered_write_u32(gvnc, scancode);
+	} else {
+		gvnc_buffered_write_u8(gvnc, 4);
+		gvnc_buffered_write_u8(gvnc, down_flag);
+		gvnc_buffered_write(gvnc, pad, 2);
+		gvnc_buffered_write_u32(gvnc, key);
+	}
+
 	gvnc_buffered_flush(gvnc);
 	return !gvnc_has_error(gvnc);
 }
@@ -1884,6 +1908,9 @@ static void gvnc_framebuffer_update(stru
 	case GVNC_ENCODING_XCURSOR:
 		gvnc_xcursor(gvnc, x, y, width, height);
 		break;
+	case GVNC_ENCODING_EXT_KEY_EVENT:
+		gvnc->has_ext_key_event = TRUE;
+		break;
 	default:
 		GVNC_DEBUG("Received an unknown encoding type: %d\n", etype);
 		gvnc->has_error = TRUE;
@@ -3021,6 +3048,11 @@ int gvnc_get_height(struct gvnc *gvnc)
 	return gvnc->height;
 }
 
+gboolean gvnc_using_raw_keycodes(struct gvnc *gvnc)
+{
+	return gvnc->has_ext_key_event;
+}
+
 /*
  * Local variables:
  *  c-indent-level: 8
diff -r a3bcd91c40e8 -r 2d87caab4637 src/gvnc.h
--- a/src/gvnc.h	Sat Feb 02 14:14:09 2008 -0600
+++ b/src/gvnc.h	Sat Feb 02 14:24:08 2008 -0600
@@ -89,6 +89,7 @@ typedef enum {
 	GVNC_ENCODING_XCURSOR = -240,
 
 	GVNC_ENCODING_POINTER_CHANGE = -257,
+	GVNC_ENCODING_EXT_KEY_EVENT = -258,
 } gvnc_encoding;
 
 typedef enum {
@@ -149,7 +150,8 @@ gboolean gvnc_pointer_event(struct gvnc 
 gboolean gvnc_pointer_event(struct gvnc *gvnc, uint8_t button_mask,
 			    uint16_t x, uint16_t y);
 
-gboolean gvnc_key_event(struct gvnc *gvnc, uint8_t down_flag, uint32_t key);
+gboolean gvnc_key_event(struct gvnc *gvnc, uint8_t down_flag,
+			uint32_t key, uint16_t scancode);
 
 gboolean gvnc_framebuffer_update_request(struct gvnc *gvnc,
 					 uint8_t incremental,
@@ -171,6 +173,9 @@ int gvnc_get_width(struct gvnc *gvnc);
 int gvnc_get_width(struct gvnc *gvnc);
 int gvnc_get_height(struct gvnc *gvnc);
 
+/* HACK this is temporary */
+gboolean gvnc_using_raw_keycodes(struct gvnc *gvnc);
+
 #endif
 /*
  * Local variables:
diff -r a3bcd91c40e8 -r 2d87caab4637 src/vnc_keycodes.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vnc_keycodes.h	Sat Feb 02 14:24:08 2008 -0600
@@ -0,0 +1,14 @@
+#ifndef _GTK_VNC_KEYCODES
+#define _GTK_VNC_KEYCODES
+
+/* All keycodes from 0 to 0xFF correspond to the hardware keycodes generated
+ * by a US101 PC keyboard with the following encoding:
+ * 
+ * 0) Sequences of XX are replaced with XX
+ * 1) Sequences of 0xe0 XX are replaces with XX | 0x80
+ * 2) All other keys are defined below
+ */
+
+#define VKC_PAUSE	0x100
+
+#endif
diff -r a3bcd91c40e8 -r 2d87caab4637 src/vncdisplay.c
--- a/src/vncdisplay.c	Sat Feb 02 14:14:09 2008 -0600
+++ b/src/vncdisplay.c	Sat Feb 02 14:24:08 2008 -0600
@@ -67,6 +67,7 @@ struct _VncDisplayPrivate
 	gboolean in_keyboard_grab;
 
 	guint down_keyval[16];
+	guint down_scancode[16];
 
 	int button_mask;
 	int last_x;
@@ -496,6 +497,16 @@ static gboolean key_event(GtkWidget *wid
 	if (priv->read_only)
 		return FALSE;
 
+	if (gvnc_using_raw_keycodes(priv->gvnc)) {
+		if (key->type == GDK_KEY_PRESS)
+			gvnc_key_event(priv->gvnc, 1,
+				       key->keyval, key->hardware_keycode);
+		else
+			gvnc_key_event(priv->gvnc, 0,
+				       key->keyval, key->hardware_keycode);
+		return TRUE;
+	}
+
 	/*
 	 * Key handling in VNC is screwy. The event.keyval from GTK is
 	 * interpreted relative to modifier state. This really messes
@@ -543,8 +554,9 @@ static gboolean key_event(GtkWidget *wid
 		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;
+				priv->down_scancode[i] = key->hardware_keycode;
 				/* Send the actual key event we're dealing with */
-				gvnc_key_event(priv->gvnc, 1, keyval);
+				gvnc_key_event(priv->gvnc, 1, keyval, key->hardware_keycode);
 				break;
 			} else if (priv->down_keyval[i] == keyval) {
 				/* Got an press when we're already pressed ! Why ... ?
@@ -556,9 +568,9 @@ static gboolean key_event(GtkWidget *wid
 				 * 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);
+				gvnc_key_event(priv->gvnc, 0, keyval, key->hardware_keycode);
 				/* Now send our actual ldown event */
-				gvnc_key_event(priv->gvnc, 1, keyval);
+				gvnc_key_event(priv->gvnc, 1, keyval, key->hardware_keycode);
 			}
 		}
 	} else {
@@ -567,8 +579,9 @@ static gboolean key_event(GtkWidget *wid
 			/* We were pressed, and now we're released, so... */
 			if (priv->down_keyval[i] == keyval) {
 				priv->down_keyval[i] = 0;
+				priv->down_scancode[i] = 0;
 				/* ..send the key releae event we're dealing with */
-				gvnc_key_event(priv->gvnc, 0, keyval);
+				gvnc_key_event(priv->gvnc, 0, keyval, key->hardware_keycode);
 				break;
 			}
 		}
@@ -634,8 +647,10 @@ static gboolean focus_event(GtkWidget *w
 		/* 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]);
+			gvnc_key_event(priv->gvnc, 0,
+				       priv->down_keyval[i], priv->down_scancode[i]);
 			priv->down_keyval[i] = 0;
+			priv->down_scancode[i] = 0;
 		}
 	}
 
@@ -1204,6 +1219,7 @@ static void *vnc_coroutine(void *opaque)
 	/* this order is extremely important! */
 	int32_t encodings[] = {	GVNC_ENCODING_TIGHT_JPEG5,
 				GVNC_ENCODING_TIGHT,
+				GVNC_ENCODING_EXT_KEY_EVENT,
 				GVNC_ENCODING_DESKTOP_RESIZE,
 				GVNC_ENCODING_RICH_CURSOR,
 				GVNC_ENCODING_XCURSOR,
@@ -1372,21 +1388,40 @@ void vnc_display_send_keys(VncDisplay *o
 				 nkeyvals, VNC_DISPLAY_KEY_EVENT_CLICK);
 }
 
+static guint get_keycode_from_keyval(guint keyval)
+{
+	guint keycode = 0;
+	GdkKeymapKey *keys = NULL;
+	gint n_keys = 0;
+
+	if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(),
+					      keyval, &keys, &n_keys)) {
+		/* FIXME what about levels? */
+		keycode = keys[0].keycode;
+		g_free(keys);
+	}
+
+	return keycode;
+}
+
 void vnc_display_send_keys_ex(VncDisplay *obj, const guint *keyvals,
 			      int nkeyvals, VncDisplayKeyEvent kind)
 {
 	int i;
+
 	if (obj->priv->gvnc == NULL || !gvnc_is_open(obj->priv->gvnc))
 		return;
 
 	if (kind & VNC_DISPLAY_KEY_EVENT_PRESS) {
 		for (i = 0 ; i < nkeyvals ; i++)
-			gvnc_key_event(obj->priv->gvnc, 1, keyvals[i]);
+			gvnc_key_event(obj->priv->gvnc, 1, keyvals[i],
+				       get_keycode_from_keyval(keyvals[i]));
 	}
 
 	if (kind & VNC_DISPLAY_KEY_EVENT_RELEASE) {
 		for (i = (nkeyvals-1) ; i >= 0 ; i--)
-			gvnc_key_event(obj->priv->gvnc, 0, keyvals[i]);
+			gvnc_key_event(obj->priv->gvnc, 0, keyvals[i],
+				       get_keycode_from_keyval(keyvals[i]));
 	}
 }
 
diff -r a3bcd91c40e8 -r 2d87caab4637 src/x_keymap.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/x_keymap.c	Sat Feb 02 14:24:08 2008 -0600
@@ -0,0 +1,133 @@
+/*
+ * QEMU SDL display driver
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * Adapted for gtk-vnc from QEMU x_keymap.c revision 1.3 (on 20080113)
+ *
+ * Copyright (C) 2008  Anthony Liguori <anthony codemonkey ws>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "x_keymap.h"
+
+static const uint8_t x_keycode_to_pc_keycode_table[115] = {
+   0xc7,      /*  97  Home   */
+   0xc8,      /*  98  Up     */
+   0xc9,      /*  99  PgUp   */
+   0xcb,      /* 100  Left   */
+   0x4c,        /* 101  KP-5   */
+   0xcd,      /* 102  Right  */
+   0xcf,      /* 103  End    */
+   0xd0,      /* 104  Down   */
+   0xd1,      /* 105  PgDn   */
+   0xd2,      /* 106  Ins    */
+   0xd3,      /* 107  Del    */
+   0x9c,      /* 108  Enter  */
+   0x9d,      /* 109  Ctrl-R */
+   0x0,       /* 110  Pause  */
+   0xb7,      /* 111  Print  */
+   0xb5,      /* 112  Divide */
+   0xb8,      /* 113  Alt-R  */
+   0xc6,      /* 114  Break  */
+   0x0,         /* 115 */
+   0x0,         /* 116 */
+   0x0,         /* 117 */
+   0x0,         /* 118 */
+   0x0,         /* 119 */
+   0x0,         /* 120 */
+   0x0,         /* 121 */
+   0x0,         /* 122 */
+   0x0,         /* 123 */
+   0x0,         /* 124 */
+   0x0,         /* 125 */
+   0x0,         /* 126 */
+   0x0,         /* 127 */
+   0x0,         /* 128 */
+   0x79,         /* 129 Henkan */
+   0x0,         /* 130 */
+   0x7b,         /* 131 Muhenkan */
+   0x0,         /* 132 */
+   0x7d,         /* 133 Yen */
+   0x0,         /* 134 */
+   0x0,         /* 135 */
+   0x47,         /* 136 KP_7 */
+   0x48,         /* 137 KP_8 */
+   0x49,         /* 138 KP_9 */
+   0x4b,         /* 139 KP_4 */
+   0x4c,         /* 140 KP_5 */
+   0x4d,         /* 141 KP_6 */
+   0x4f,         /* 142 KP_1 */
+   0x50,         /* 143 KP_2 */
+   0x51,         /* 144 KP_3 */
+   0x52,         /* 145 KP_0 */
+   0x53,         /* 146 KP_. */
+   0x47,         /* 147 KP_HOME */
+   0x48,         /* 148 KP_UP */
+   0x49,         /* 149 KP_PgUp */
+   0x4b,         /* 150 KP_Left */
+   0x4c,         /* 151 KP_ */
+   0x4d,         /* 152 KP_Right */
+   0x4f,         /* 153 KP_End */
+   0x50,         /* 154 KP_Down */
+   0x51,         /* 155 KP_PgDn */
+   0x52,         /* 156 KP_Ins */
+   0x53,         /* 157 KP_Del */
+   0x0,         /* 158 */
+   0x0,         /* 159 */
+   0x0,         /* 160 */
+   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,         /* 170 */
+   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,         /* 180 */
+   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,         /* 190 */
+   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,         /* 200 */
+   0x0,         /* 201 */
+   0x0,         /* 202 */
+   0x0,         /* 203 */
+   0x0,         /* 204 */
+   0x0,         /* 205 */
+   0x0,         /* 206 */
+   0x0,         /* 207 */
+   0x70,         /* 208 Hiragana_Katakana */
+   0x0,         /* 209 */
+   0x0,         /* 210 */
+   0x73,         /* 211 backslash */
+};
+
+/* FIXME N.B. on Windows, gtk probably returns PC scan codes */
+
+uint8_t x_keycode_to_pc_keycode(int keycode)
+{
+	if (keycode < 9)
+		keycode = 0;
+	else if (keycode < 97)
+		keycode -= 8; /* just an offset */
+	else if (keycode < 212)
+		keycode = x_keycode_to_pc_keycode_table[keycode - 97];
+	else
+		keycode = 0;
+
+	return keycode;
+}
diff -r a3bcd91c40e8 -r 2d87caab4637 src/x_keymap.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/x_keymap.h	Sat Feb 02 14:24:08 2008 -0600
@@ -0,0 +1,8 @@
+#ifndef _GTK_VNC_X_KEYMAP_H
+#define _GTK_VNC_X_KEYMAP_H
+
+#include <stdint.h>
+
+uint8_t x_keycode_to_pc_keycode(int keycode);
+
+#endif


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