# HG changeset patch
# User Ewan Mellor <ewan@xxxxxxxxxxxxx>
# Node ID c7f4a89eb054a1ad411da1e4cdc8aeda1a98c4fa
# Parent 565cd8f32c70da8ae7dbaaeb9dff28aa8b6307e1
Fix numpad handling in QEMU's VNC server. The keymaps that we have include
information on which keys change depending upon the numlock setting, but
this isn't being used. By forcing numlock on and off as necessary, when
receiving these keysyms through the VNC connection, we ensure that the
server's numlock status is the same as the client's.
Signed-off-by: Ewan Mellor <ewan@xxxxxxxxxxxxx>
---
tools/ioemu/keymaps.c | 63 +++++++++++++++++++++++++++++++++++++++++++++--
tools/ioemu/vnc.c | 32 +++++++++++++++++++++++
tools/ioemu/vnc_keysym.h | 14 ++++++++++
3 files changed, 107 insertions(+), 2 deletions(-)
diff -r 565cd8f32c70 -r c7f4a89eb054 tools/ioemu/keymaps.c
--- a/tools/ioemu/keymaps.c Mon Dec 04 13:57:18 2006 +0000
+++ b/tools/ioemu/keymaps.c Mon Dec 04 17:52:33 2006 +0000
@@ -36,8 +36,10 @@ static int get_keysym(const char *name)
#define MAX_EXTRA_COUNT 256
typedef struct {
uint16_t keysym2keycode[MAX_NORMAL_KEYCODE];
+ int keysym2numlock[MAX_NORMAL_KEYCODE];
struct {
int keysym;
+ int numlock;
uint16_t keycode;
} keysym2keycode_extra[MAX_EXTRA_COUNT];
int extra_count;
@@ -50,6 +52,8 @@ static kbd_layout_t *parse_keyboard_layo
char file_name[1024];
char line[1024];
int len;
+ int *keycode2numlock;
+ int i;
snprintf(file_name, sizeof(file_name),
"%s/keymaps/%s", bios_dir, language);
@@ -63,6 +67,15 @@ static kbd_layout_t *parse_keyboard_layo
"Could not read keymap file: '%s'\n", file_name);
return 0;
}
+
+ /* Allocate a temporary map tracking which keycodes change when numlock is
+ set. Keycodes are 16 bit, so 65536 is safe. */
+ keycode2numlock = malloc(65536 * sizeof(int));
+ if (!keycode2numlock) {
+ perror("Could not read keymap file");
+ return 0;
+ }
+
for(;;) {
if (fgets(line, 1024, f) == NULL)
break;
@@ -86,13 +99,19 @@ static kbd_layout_t *parse_keyboard_layo
if (keysym == 0) {
// fprintf(stderr, "Warning: unknown keysym
%s\n", line);
} else {
- const char *rest = end_of_keysym + 1;
- int keycode = strtol(rest, NULL, 0);
+ char *rest = end_of_keysym + 1;
+ int keycode = strtol(rest, &rest, 0);
+ int numlock = (rest != NULL &&
+ strstr(rest, "numlock") != NULL);
+
+ keycode2numlock[keycode] = numlock;
+
/* if(keycode&0x80)
keycode=(keycode<<8)^0x80e0; */
if (keysym < MAX_NORMAL_KEYCODE) {
//fprintf(stderr,"Setting keysym %s (%d) to
%d\n",line,keysym,keycode);
k->keysym2keycode[keysym] = keycode;
+ k->keysym2numlock[keysym] = numlock;
} else {
if (k->extra_count >= MAX_EXTRA_COUNT) {
fprintf(stderr,
@@ -107,6 +126,8 @@ static kbd_layout_t *parse_keyboard_layo
keysym = keysym;
k->keysym2keycode_extra[k->extra_count].
keycode = keycode;
+ k->keysym2keycode_extra[k->extra_count].
+ numlock = numlock;
k->extra_count++;
}
}
@@ -115,6 +136,22 @@ static kbd_layout_t *parse_keyboard_layo
}
}
fclose(f);
+
+ for (int i = 0; i < MAX_NORMAL_KEYCODE; i++) {
+ if (k->keysym2numlock[i] != 1) {
+ k->keysym2numlock[i] = -keycode2numlock[k->keysym2keycode[i]];
+ }
+ }
+
+ for (int i = 0; i < k->extra_count; i++) {
+ if (k->keysym2keycode_extra[i].numlock != 1) {
+ k->keysym2keycode_extra[i].numlock =
+ -keycode2numlock[k->keysym2keycode_extra[i].keycode];
+ }
+ }
+
+ free(keycode2numlock);
+
return k;
}
@@ -143,3 +180,25 @@ static int keysym2scancode(void *kbd_lay
}
return 0;
}
+
+/**
+ * Returns 1 if the given keysym requires numlock to be pressed, -1 if it
+ * requires it to be cleared, and 0 otherwise.
+ */
+static int keysym2numlock(void *kbd_layout, int keysym)
+{
+ kbd_layout_t *k = kbd_layout;
+ if (keysym < MAX_NORMAL_KEYCODE) {
+ return k->keysym2numlock[keysym];
+ } else {
+ int i;
+#ifdef XK_ISO_Left_Tab
+ if (keysym == XK_ISO_Left_Tab)
+ keysym = XK_Tab;
+#endif
+ for (i = 0; i < k->extra_count; i++)
+ if (k->keysym2keycode_extra[i].keysym == keysym)
+ return k->keysym2keycode_extra[i].numlock;
+ }
+ return 0;
+}
diff -r 565cd8f32c70 -r c7f4a89eb054 tools/ioemu/vnc.c
--- a/tools/ioemu/vnc.c Mon Dec 04 13:57:18 2006 +0000
+++ b/tools/ioemu/vnc.c Mon Dec 04 17:52:33 2006 +0000
@@ -115,6 +115,7 @@ struct VncState
int ctl_keys; /* Ctrl+Alt starts calibration */
int shift_keys; /* Shift / CapsLock keys */
+ int numlock;
};
#define DIRTY_PIXEL_BITS 64
@@ -854,14 +855,40 @@ static void pointer_event(VncState *vs,
}
}
+static void press_key(VncState *vs, int keycode)
+{
+ kbd_put_keycode(keysym2scancode(vs->kbd_layout, keycode) & 0x7f);
+ kbd_put_keycode(keysym2scancode(vs->kbd_layout, keycode) | 0x80);
+}
+
static void do_key_event(VncState *vs, int down, uint32_t sym)
{
sym &= 0xFFFF;
if (is_graphic_console()) {
int keycode;
+ int numlock;
keycode = keysym2scancode(vs->kbd_layout, sym);
+ numlock = keysym2numlock(vs->kbd_layout, sym);
+
+ /* If the numlock state needs to change then simulate an additional
+ keypress before sending this one. This will happen if the user
+ toggles numlock away from the VNC window.
+ */
+ if (numlock == 1) {
+ if (!vs->numlock) {
+ vs->numlock = 1;
+ press_key(vs, XK_Num_Lock);
+ }
+ }
+ else if (numlock == -1) {
+ if (vs->numlock) {
+ vs->numlock = 0;
+ press_key(vs, XK_Num_Lock);
+ }
+ }
+
if (keycode & 0x80)
kbd_put_keycode(0xe0);
if (down)
@@ -930,6 +957,10 @@ static void do_key_event(VncState *vs, i
case XK_Caps_Lock:
vs->shift_keys ^= 2;
+ break;
+
+ case XK_Num_Lock:
+ vs->numlock = !vs->numlock;
break;
case XK_1 ... XK_9:
@@ -1355,6 +1386,7 @@ int vnc_display_init(DisplayState *ds, i
vs->lsock = -1;
vs->csock = -1;
vs->depth = 4;
+ vs->numlock = 0;
vs->ds = ds;
diff -r 565cd8f32c70 -r c7f4a89eb054 tools/ioemu/vnc_keysym.h
--- a/tools/ioemu/vnc_keysym.h Mon Dec 04 13:57:18 2006 +0000
+++ b/tools/ioemu/vnc_keysym.h Mon Dec 04 17:52:33 2006 +0000
@@ -231,6 +231,19 @@ static name2keysym_t name2keysym[]={
{"Home", 0xff50}, /* XK_Home */
{"End", 0xff57}, /* XK_End */
{"Scroll_Lock", 0xff14}, /* XK_Scroll_Lock */
+{"KP_Home", 0xff95},
+{"KP_Left", 0xff96},
+{"KP_Up", 0xff97},
+{"KP_Right", 0xff98},
+{"KP_Down", 0xff99},
+{"KP_Prior", 0xff9a},
+{"KP_Page_Up", 0xff9a},
+{"KP_Next", 0xff9b},
+{"KP_Page_Down", 0xff9b},
+{"KP_End", 0xff9c},
+{"KP_Begin", 0xff9d},
+{"KP_Insert", 0xff9e},
+{"KP_Delete", 0xff9f},
{"F1", 0xffbe}, /* XK_F1 */
{"F2", 0xffbf}, /* XK_F2 */
{"F3", 0xffc0}, /* XK_F3 */
@@ -258,6 +271,7 @@ static name2keysym_t name2keysym[]={
{"KP_8", 0xffb8}, /* XK_KP_8 */
{"KP_9", 0xffb9}, /* XK_KP_9 */
{"KP_Add", 0xffab}, /* XK_KP_Add */
+{"KP_Separator", 0xffac},/* XK_KP_Separator */
{"KP_Decimal", 0xffae}, /* XK_KP_Decimal */
{"KP_Divide", 0xffaf}, /* XK_KP_Divide */
{"KP_Enter", 0xff8d}, /* XK_KP_Enter */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|