direct-io.hg

view tools/ioemu/keymaps.c @ 12729:c7f4a89eb054

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@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Mon Dec 04 17:52:33 2006 +0000 (2006-12-04)
parents b450f21472a0
children 897bb9b7ed06
line source
1 /*
2 * QEMU keysym to keycode conversion using rdesktop keymaps
3 *
4 * Copyright (c) 2004 Johannes Schindelin
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
25 static int get_keysym(const char *name)
26 {
27 name2keysym_t *p;
28 for(p = name2keysym; p->name != NULL; p++) {
29 if (!strcmp(p->name, name))
30 return p->keysym;
31 }
32 return 0;
33 }
35 #define MAX_NORMAL_KEYCODE 512
36 #define MAX_EXTRA_COUNT 256
37 typedef struct {
38 uint16_t keysym2keycode[MAX_NORMAL_KEYCODE];
39 int keysym2numlock[MAX_NORMAL_KEYCODE];
40 struct {
41 int keysym;
42 int numlock;
43 uint16_t keycode;
44 } keysym2keycode_extra[MAX_EXTRA_COUNT];
45 int extra_count;
46 } kbd_layout_t;
48 static kbd_layout_t *parse_keyboard_layout(const char *language,
49 kbd_layout_t * k)
50 {
51 FILE *f;
52 char file_name[1024];
53 char line[1024];
54 int len;
55 int *keycode2numlock;
56 int i;
58 snprintf(file_name, sizeof(file_name),
59 "%s/keymaps/%s", bios_dir, language);
61 if (!k)
62 k = qemu_mallocz(sizeof(kbd_layout_t));
63 if (!k)
64 return 0;
65 if (!(f = fopen(file_name, "r"))) {
66 fprintf(stderr,
67 "Could not read keymap file: '%s'\n", file_name);
68 return 0;
69 }
71 /* Allocate a temporary map tracking which keycodes change when numlock is
72 set. Keycodes are 16 bit, so 65536 is safe. */
73 keycode2numlock = malloc(65536 * sizeof(int));
74 if (!keycode2numlock) {
75 perror("Could not read keymap file");
76 return 0;
77 }
79 for(;;) {
80 if (fgets(line, 1024, f) == NULL)
81 break;
82 len = strlen(line);
83 if (len > 0 && line[len - 1] == '\n')
84 line[len - 1] = '\0';
85 if (line[0] == '#')
86 continue;
87 if (!strncmp(line, "map ", 4))
88 continue;
89 if (!strncmp(line, "include ", 8)) {
90 parse_keyboard_layout(line + 8, k);
91 } else {
92 char *end_of_keysym = line;
93 while (*end_of_keysym != 0 && *end_of_keysym != ' ')
94 end_of_keysym++;
95 if (*end_of_keysym) {
96 int keysym;
97 *end_of_keysym = 0;
98 keysym = get_keysym(line);
99 if (keysym == 0) {
100 // fprintf(stderr, "Warning: unknown keysym %s\n", line);
101 } else {
102 char *rest = end_of_keysym + 1;
103 int keycode = strtol(rest, &rest, 0);
104 int numlock = (rest != NULL &&
105 strstr(rest, "numlock") != NULL);
107 keycode2numlock[keycode] = numlock;
109 /* if(keycode&0x80)
110 keycode=(keycode<<8)^0x80e0; */
111 if (keysym < MAX_NORMAL_KEYCODE) {
112 //fprintf(stderr,"Setting keysym %s (%d) to %d\n",line,keysym,keycode);
113 k->keysym2keycode[keysym] = keycode;
114 k->keysym2numlock[keysym] = numlock;
115 } else {
116 if (k->extra_count >= MAX_EXTRA_COUNT) {
117 fprintf(stderr,
118 "Warning: Could not assign keysym %s (0x%x) because of memory constraints.\n",
119 line, keysym);
120 } else {
121 #if 0
122 fprintf(stderr, "Setting %d: %d,%d\n",
123 k->extra_count, keysym, keycode);
124 #endif
125 k->keysym2keycode_extra[k->extra_count].
126 keysym = keysym;
127 k->keysym2keycode_extra[k->extra_count].
128 keycode = keycode;
129 k->keysym2keycode_extra[k->extra_count].
130 numlock = numlock;
131 k->extra_count++;
132 }
133 }
134 }
135 }
136 }
137 }
138 fclose(f);
140 for (int i = 0; i < MAX_NORMAL_KEYCODE; i++) {
141 if (k->keysym2numlock[i] != 1) {
142 k->keysym2numlock[i] = -keycode2numlock[k->keysym2keycode[i]];
143 }
144 }
146 for (int i = 0; i < k->extra_count; i++) {
147 if (k->keysym2keycode_extra[i].numlock != 1) {
148 k->keysym2keycode_extra[i].numlock =
149 -keycode2numlock[k->keysym2keycode_extra[i].keycode];
150 }
151 }
153 free(keycode2numlock);
155 return k;
156 }
158 static void *init_keyboard_layout(const char *language)
159 {
160 return parse_keyboard_layout(language, 0);
161 }
163 static int keysym2scancode(void *kbd_layout, int keysym)
164 {
165 kbd_layout_t *k = kbd_layout;
166 if (keysym < MAX_NORMAL_KEYCODE) {
167 if (k->keysym2keycode[keysym] == 0)
168 fprintf(stderr, "Warning: no scancode found for keysym %d\n",
169 keysym);
170 return k->keysym2keycode[keysym];
171 } else {
172 int i;
173 #ifdef XK_ISO_Left_Tab
174 if (keysym == XK_ISO_Left_Tab)
175 keysym = XK_Tab;
176 #endif
177 for (i = 0; i < k->extra_count; i++)
178 if (k->keysym2keycode_extra[i].keysym == keysym)
179 return k->keysym2keycode_extra[i].keycode;
180 }
181 return 0;
182 }
184 /**
185 * Returns 1 if the given keysym requires numlock to be pressed, -1 if it
186 * requires it to be cleared, and 0 otherwise.
187 */
188 static int keysym2numlock(void *kbd_layout, int keysym)
189 {
190 kbd_layout_t *k = kbd_layout;
191 if (keysym < MAX_NORMAL_KEYCODE) {
192 return k->keysym2numlock[keysym];
193 } else {
194 int i;
195 #ifdef XK_ISO_Left_Tab
196 if (keysym == XK_ISO_Left_Tab)
197 keysym = XK_Tab;
198 #endif
199 for (i = 0; i < k->extra_count; i++)
200 if (k->keysym2keycode_extra[i].keysym == keysym)
201 return k->keysym2keycode_extra[i].numlock;
202 }
203 return 0;
204 }