2
0

qemu-keymap.c 7.4 KB

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