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 */ 24 25 #include "qemu/osdep.h" 26 #include "keymaps.h" 27 #include "sysemu/sysemu.h" 28 #include "trace.h" 29 #include "qemu/error-report.h" 30 31 struct keysym2code { 32 uint32_t count; 33 uint16_t keycodes[4]; 34 }; 35 36 struct kbd_layout_t { 37 GHashTable *hash; 38 }; 39 40 static int get_keysym(const name2keysym_t *table, 41 const char *name) 42 { 43 const name2keysym_t *p; 44 for(p = table; p->name != NULL; p++) { 45 if (!strcmp(p->name, name)) { 46 return p->keysym; 47 } 48 } 49 if (name[0] == 'U' && strlen(name) == 5) { /* try unicode Uxxxx */ 50 char *end; 51 int ret = (int)strtoul(name + 1, &end, 16); 52 if (*end == '\0' && ret > 0) { 53 return ret; 54 } 55 } 56 return 0; 57 } 58 59 60 static void add_keysym(char *line, int keysym, int keycode, kbd_layout_t *k) 61 { 62 struct keysym2code *keysym2code; 63 64 keysym2code = g_hash_table_lookup(k->hash, GINT_TO_POINTER(keysym)); 65 if (keysym2code) { 66 if (keysym2code->count < ARRAY_SIZE(keysym2code->keycodes)) { 67 keysym2code->keycodes[keysym2code->count++] = keycode; 68 } else { 69 warn_report("more than %zd keycodes for keysym %d", 70 ARRAY_SIZE(keysym2code->keycodes), keysym); 71 } 72 return; 73 } 74 75 keysym2code = g_new0(struct keysym2code, 1); 76 keysym2code->keycodes[0] = keycode; 77 keysym2code->count = 1; 78 g_hash_table_replace(k->hash, GINT_TO_POINTER(keysym), keysym2code); 79 trace_keymap_add(keysym, keycode, line); 80 } 81 82 static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, 83 const char *language, 84 kbd_layout_t *k) 85 { 86 FILE *f; 87 char * filename; 88 char line[1024]; 89 char keyname[64]; 90 int len; 91 92 filename = qemu_find_file(QEMU_FILE_TYPE_KEYMAP, language); 93 trace_keymap_parse(filename); 94 f = filename ? fopen(filename, "r") : NULL; 95 g_free(filename); 96 if (!f) { 97 fprintf(stderr, "Could not read keymap file: '%s'\n", language); 98 return NULL; 99 } 100 101 if (!k) { 102 k = g_new0(kbd_layout_t, 1); 103 k->hash = g_hash_table_new(NULL, NULL); 104 } 105 106 for(;;) { 107 if (fgets(line, 1024, f) == NULL) { 108 break; 109 } 110 len = strlen(line); 111 if (len > 0 && line[len - 1] == '\n') { 112 line[len - 1] = '\0'; 113 } 114 if (line[0] == '#') { 115 continue; 116 } 117 if (!strncmp(line, "map ", 4)) { 118 continue; 119 } 120 if (!strncmp(line, "include ", 8)) { 121 parse_keyboard_layout(table, line + 8, k); 122 } else { 123 int offset = 0; 124 while (line[offset] != 0 && 125 line[offset] != ' ' && 126 offset < sizeof(keyname) - 1) { 127 keyname[offset] = line[offset]; 128 offset++; 129 } 130 keyname[offset] = 0; 131 if (strlen(keyname)) { 132 int keysym; 133 keysym = get_keysym(table, keyname); 134 if (keysym == 0) { 135 /* warn_report("unknown keysym %s", line);*/ 136 } else { 137 const char *rest = line + offset + 1; 138 int keycode = strtol(rest, NULL, 0); 139 140 if (strstr(rest, "shift")) { 141 keycode |= SCANCODE_SHIFT; 142 } 143 if (strstr(rest, "altgr")) { 144 keycode |= SCANCODE_ALTGR; 145 } 146 if (strstr(rest, "ctrl")) { 147 keycode |= SCANCODE_CTRL; 148 } 149 150 add_keysym(line, keysym, keycode, k); 151 152 if (strstr(rest, "addupper")) { 153 char *c; 154 for (c = keyname; *c; c++) { 155 *c = qemu_toupper(*c); 156 } 157 keysym = get_keysym(table, keyname); 158 if (keysym) { 159 add_keysym(line, keysym, 160 keycode | SCANCODE_SHIFT, k); 161 } 162 } 163 } 164 } 165 } 166 } 167 fclose(f); 168 return k; 169 } 170 171 172 kbd_layout_t *init_keyboard_layout(const name2keysym_t *table, 173 const char *language) 174 { 175 return parse_keyboard_layout(table, language, NULL); 176 } 177 178 179 int keysym2scancode(kbd_layout_t *k, int keysym, 180 bool shift, bool altgr, bool ctrl) 181 { 182 static const uint32_t mask = 183 SCANCODE_SHIFT | SCANCODE_ALTGR | SCANCODE_CTRL; 184 uint32_t mods, i; 185 struct keysym2code *keysym2code; 186 187 #ifdef XK_ISO_Left_Tab 188 if (keysym == XK_ISO_Left_Tab) { 189 keysym = XK_Tab; 190 } 191 #endif 192 193 keysym2code = g_hash_table_lookup(k->hash, GINT_TO_POINTER(keysym)); 194 if (!keysym2code) { 195 trace_keymap_unmapped(keysym); 196 warn_report("no scancode found for keysym %d", keysym); 197 return 0; 198 } 199 200 if (keysym2code->count == 1) { 201 return keysym2code->keycodes[0]; 202 } 203 204 /* 205 * We have multiple keysym -> keycode mappings. 206 * 207 * Check whenever we find one mapping where the modifier state of 208 * the mapping matches the current user interface modifier state. 209 * If so, prefer that one. 210 */ 211 mods = 0; 212 if (shift) { 213 mods |= SCANCODE_SHIFT; 214 } 215 if (altgr) { 216 mods |= SCANCODE_ALTGR; 217 } 218 if (ctrl) { 219 mods |= SCANCODE_CTRL; 220 } 221 222 for (i = 0; i < keysym2code->count; i++) { 223 if ((keysym2code->keycodes[i] & mask) == mods) { 224 return keysym2code->keycodes[i]; 225 } 226 } 227 return keysym2code->keycodes[0]; 228 } 229 230 int keycode_is_keypad(kbd_layout_t *k, int keycode) 231 { 232 if (keycode >= 0x47 && keycode <= 0x53) { 233 return true; 234 } 235 return false; 236 } 237 238 int keysym_is_numlock(kbd_layout_t *k, int keysym) 239 { 240 switch (keysym) { 241 case 0xffb0 ... 0xffb9: /* KP_0 .. KP_9 */ 242 case 0xffac: /* KP_Separator */ 243 case 0xffae: /* KP_Decimal */ 244 return true; 245 } 246 return false; 247 } 248