keymaps.c 8.0 KB

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