2
0

qemu-keymap.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * QEMU keymap utility
  3. *
  4. * Copyright Red Hat, Inc. 2017
  5. *
  6. * Authors:
  7. * Gerd Hoffmann <kraxel@redhat.com>
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10. * See the COPYING file in the top-level directory.
  11. */
  12. #include "qemu/osdep.h"
  13. #include "qemu/notify.h"
  14. #include "ui/input.h"
  15. #include <xkbcommon/xkbcommon.h>
  16. struct xkb_rule_names names = {
  17. .rules = NULL,
  18. .model = "pc105",
  19. .layout = "us",
  20. .variant = NULL,
  21. .options = NULL,
  22. };
  23. static xkb_mod_mask_t shift;
  24. static xkb_mod_mask_t ctrl;
  25. static xkb_mod_mask_t altgr;
  26. static xkb_mod_mask_t numlock;
  27. static FILE *outfile;
  28. /* ------------------------------------------------------------------------ */
  29. static uint32_t qcode_to_number(uint32_t qcode)
  30. {
  31. KeyValue keyvalue;
  32. uint32_t number;
  33. keyvalue.type = KEY_VALUE_KIND_QCODE;
  34. keyvalue.u.qcode.data = qcode;
  35. number = qemu_input_key_value_to_number(&keyvalue);
  36. assert(number != 0);
  37. return number;
  38. }
  39. static void print_sym(xkb_keysym_t sym, uint32_t qcode, const char *mod)
  40. {
  41. char name[64];
  42. if (sym == XKB_KEY_NoSymbol) {
  43. return;
  44. }
  45. xkb_keysym_get_name(sym, name, sizeof(name));
  46. /* TODO: make ui/keymap.c parser accept QKeyCode names */
  47. fprintf(outfile, "%s 0x%02x%s\n", name, qcode_to_number(qcode), mod);
  48. }
  49. static void walk_map(struct xkb_keymap *map, xkb_keycode_t code, void *data)
  50. {
  51. struct xkb_state *state = data;
  52. xkb_keysym_t kbase, knumlock, kshift, kaltgr, kaltgrshift;
  53. uint32_t evdev, qcode;
  54. char name[64];
  55. fprintf(outfile, "\n");
  56. /*
  57. * map xkb keycode -> QKeyCode
  58. *
  59. * xkb keycode is linux evdev shifted by 8
  60. */
  61. evdev = code - 8;
  62. qcode = qemu_input_linux_to_qcode(evdev);
  63. if (qcode == Q_KEY_CODE_UNMAPPED) {
  64. xkb_state_update_mask(state, 0, 0, 0, 0, 0, 0);
  65. kbase = xkb_state_key_get_one_sym(state, code);
  66. xkb_keysym_get_name(kbase, name, sizeof(name));
  67. fprintf(outfile, "# evdev %d (0x%x): no evdev -> QKeyCode mapping"
  68. " (xkb keysym %s)\n", evdev, evdev, name);
  69. return;
  70. }
  71. fprintf(outfile, "# evdev %d (0x%x), QKeyCode \"%s\", number 0x%x\n",
  72. evdev, evdev,
  73. QKeyCode_str(qcode),
  74. qcode_to_number(qcode));
  75. /*
  76. * check which modifier states generate which keysyms
  77. */
  78. xkb_state_update_mask(state, 0, 0, 0, 0, 0, 0);
  79. kbase = xkb_state_key_get_one_sym(state, code);
  80. print_sym(kbase, qcode, "");
  81. xkb_state_update_mask(state, 0, 0, numlock, 0, 0, 0);
  82. knumlock = xkb_state_key_get_one_sym(state, code);
  83. if (kbase != knumlock) {
  84. print_sym(knumlock, qcode, " numlock");
  85. }
  86. xkb_state_update_mask(state, shift, 0, 0, 0, 0, 0);
  87. kshift = xkb_state_key_get_one_sym(state, code);
  88. if (kbase != kshift && knumlock != kshift) {
  89. print_sym(kshift, qcode, " shift");
  90. }
  91. xkb_state_update_mask(state, altgr, 0, 0, 0, 0, 0);
  92. kaltgr = xkb_state_key_get_one_sym(state, code);
  93. if (kbase != kaltgr) {
  94. print_sym(kaltgr, qcode, " altgr");
  95. }
  96. xkb_state_update_mask(state, altgr | shift, 0, 0, 0, 0, 0);
  97. kaltgrshift = xkb_state_key_get_one_sym(state, code);
  98. if (kshift != kaltgrshift && kaltgr != kaltgrshift) {
  99. print_sym(kaltgrshift, qcode, " shift altgr");
  100. }
  101. return;
  102. }
  103. static void usage(FILE *out)
  104. {
  105. fprintf(out,
  106. "\n"
  107. "This tool generates qemu reverse keymaps from xkb keymaps,\n"
  108. "which can be used with the qemu \"-k\" command line switch.\n"
  109. "\n"
  110. "usage: qemu-keymap <options>\n"
  111. "options:\n"
  112. " -h print this text\n"
  113. " -f <file> set output file (default: stdout)\n"
  114. " -m <model> set kbd model (default: %s)\n"
  115. " -l <layout> set kbd layout (default: %s)\n"
  116. " -v <variant> set kbd variant (default: %s)\n"
  117. " -o <options> set kbd options (default: %s)\n"
  118. "\n",
  119. names.model, names.layout,
  120. names.variant ?: "-",
  121. names.options ?: "-");
  122. }
  123. static xkb_mod_mask_t get_mod(struct xkb_keymap *map, const char *name)
  124. {
  125. xkb_mod_index_t mod;
  126. xkb_mod_mask_t mask = 0;
  127. mod = xkb_keymap_mod_get_index(map, name);
  128. if (mod != XKB_MOD_INVALID) {
  129. mask = (1 << mod);
  130. }
  131. return mask;
  132. }
  133. int main(int argc, char *argv[])
  134. {
  135. struct xkb_context *ctx;
  136. struct xkb_keymap *map;
  137. struct xkb_state *state;
  138. xkb_mod_index_t mod, mods;
  139. int rc;
  140. for (;;) {
  141. rc = getopt(argc, argv, "hm:l:v:o:f:");
  142. if (rc == -1) {
  143. break;
  144. }
  145. switch (rc) {
  146. case 'm':
  147. names.model = optarg;
  148. break;
  149. case 'l':
  150. names.layout = optarg;
  151. break;
  152. case 'v':
  153. names.variant = optarg;
  154. break;
  155. case 'o':
  156. names.options = optarg;
  157. break;
  158. case 'f':
  159. outfile = fopen(optarg, "w");
  160. if (outfile == NULL) {
  161. fprintf(stderr, "open %s: %s\n", optarg, strerror(errno));
  162. exit(1);
  163. }
  164. break;
  165. case 'h':
  166. usage(stdout);
  167. exit(0);
  168. default:
  169. usage(stderr);
  170. exit(1);
  171. }
  172. }
  173. if (outfile == NULL) {
  174. outfile = stdout;
  175. }
  176. fprintf(outfile,
  177. "# SPDX-License-Identifier: GPL-2.0-or-later\n"
  178. "#\n"
  179. "# generated by qemu-keymap\n"
  180. "# model : %s\n"
  181. "# layout : %s\n"
  182. "# variant : %s\n"
  183. "# options : %s\n"
  184. "\n",
  185. names.model, names.layout,
  186. names.variant ?: "-",
  187. names.options ?: "-");
  188. ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  189. map = xkb_keymap_new_from_names(ctx, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
  190. xkb_context_unref(ctx);
  191. if (!map) {
  192. /* libxkbcommon prints error */
  193. exit(1);
  194. }
  195. fprintf(outfile, "# name: \"%s\"\n\n",
  196. xkb_keymap_layout_get_name(map, 0));
  197. fprintf(outfile, "# modifiers\n");
  198. mods = xkb_keymap_num_mods(map);
  199. for (mod = 0; mod < mods; mod++) {
  200. fprintf(outfile, "# %2d: %s\n",
  201. mod, xkb_keymap_mod_get_name(map, mod));
  202. }
  203. shift = get_mod(map, "Shift");
  204. ctrl = get_mod(map, "Control");
  205. altgr = get_mod(map, "AltGr");
  206. numlock = get_mod(map, "NumLock");
  207. state = xkb_state_new(map);
  208. xkb_keymap_key_for_each(map, walk_map, state);
  209. xkb_state_unref(state);
  210. xkb_keymap_unref(map);
  211. /* add quirks */
  212. fprintf(outfile,
  213. "\n"
  214. "#\n"
  215. "# quirks section start\n"
  216. "#\n"
  217. "# Sometimes multiple keysyms map to the same keycodes.\n"
  218. "# The keycode -> keysym lookup finds only one of the\n"
  219. "# keysyms. So append them here.\n"
  220. "#\n"
  221. "\n");
  222. print_sym(XKB_KEY_Print, Q_KEY_CODE_SYSRQ, "");
  223. print_sym(XKB_KEY_Sys_Req, Q_KEY_CODE_SYSRQ, "");
  224. print_sym(XKB_KEY_Execute, Q_KEY_CODE_SYSRQ, "");
  225. print_sym(XKB_KEY_KP_Decimal, Q_KEY_CODE_KP_DECIMAL, " numlock");
  226. print_sym(XKB_KEY_KP_Separator, Q_KEY_CODE_KP_DECIMAL, " numlock");
  227. print_sym(XKB_KEY_Alt_R, Q_KEY_CODE_ALT_R, "");
  228. print_sym(XKB_KEY_ISO_Level3_Shift, Q_KEY_CODE_ALT_R, "");
  229. print_sym(XKB_KEY_Mode_switch, Q_KEY_CODE_ALT_R, "");
  230. fprintf(outfile,
  231. "\n"
  232. "# quirks section end\n");
  233. exit(0);
  234. }