modifiers.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. /*
  2. * Copyright © 2023 Pierre Le Marre <dev@wismill.eu>
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "config.h"
  6. #include "test-config.h"
  7. #include <assert.h>
  8. #include <stdint.h>
  9. #include <stdlib.h>
  10. #include "xkbcommon/xkbcommon.h"
  11. #include "xkbcommon/xkbcommon-names.h"
  12. #include "evdev-scancodes.h"
  13. #include "test.h"
  14. #include "keymap.h"
  15. #include "utils.h"
  16. #define GOLDEN_TESTS_OUTPUTS "keymaps/"
  17. /* Standard real modifier masks */
  18. enum real_mod_mask {
  19. ShiftMask = (UINT32_C(1) << XKB_MOD_INDEX_SHIFT),
  20. LockMask = (UINT32_C(1) << XKB_MOD_INDEX_CAPS),
  21. ControlMask = (UINT32_C(1) << XKB_MOD_INDEX_CTRL),
  22. Mod1Mask = (UINT32_C(1) << XKB_MOD_INDEX_MOD1),
  23. Mod2Mask = (UINT32_C(1) << XKB_MOD_INDEX_MOD2),
  24. Mod3Mask = (UINT32_C(1) << XKB_MOD_INDEX_MOD3),
  25. Mod4Mask = (UINT32_C(1) << XKB_MOD_INDEX_MOD4),
  26. Mod5Mask = (UINT32_C(1) << XKB_MOD_INDEX_MOD5),
  27. NoModifier = 0
  28. };
  29. /* Our keymap compiler is the xkbcommon buffer compiler */
  30. static struct xkb_keymap *
  31. compile_buffer(struct xkb_context *context, enum xkb_keymap_format format,
  32. const char *buf, size_t len, void *private)
  33. {
  34. const enum xkb_keymap_compile_flags flags
  35. = (private)
  36. ? *(enum xkb_keymap_compile_flags*)private
  37. : TEST_KEYMAP_COMPILE_FLAGS;
  38. return test_compile_buffer2(context, format, flags, buf, len);
  39. }
  40. static bool
  41. test_real_mod(struct xkb_keymap *keymap, const char* name,
  42. xkb_mod_index_t idx, xkb_mod_mask_t mapping)
  43. {
  44. return xkb_keymap_mod_get_index(keymap, name) == idx &&
  45. (keymap->mods.mods[idx].type == MOD_REAL) &&
  46. mapping == keymap->mods.mods[idx].mapping &&
  47. mapping == (UINT32_C(1) << idx) &&
  48. xkb_keymap_mod_get_mask(keymap, name) == mapping &&
  49. xkb_keymap_mod_get_mask2(keymap, idx) == mapping;
  50. }
  51. static bool
  52. test_virtual_mod(struct xkb_keymap *keymap, const char* name,
  53. xkb_mod_index_t idx, xkb_mod_mask_t mapping)
  54. {
  55. return xkb_keymap_mod_get_index(keymap, name) == idx &&
  56. (keymap->mods.mods[idx].type == MOD_VIRT) &&
  57. mapping == keymap->mods.mods[idx].mapping &&
  58. xkb_keymap_mod_get_mask(keymap, name) == mapping &&
  59. xkb_keymap_mod_get_mask2(keymap, idx) == mapping;
  60. }
  61. /* Check that the provided modifier names work */
  62. static void
  63. test_modifiers_names(struct xkb_context *context)
  64. {
  65. struct xkb_keymap *keymap;
  66. keymap = test_compile_rules(context, XKB_KEYMAP_FORMAT_TEXT_V1, "evdev",
  67. "pc104", "us", NULL, NULL);
  68. assert(keymap);
  69. /* Real modifiers
  70. * The indices and masks are fixed and always valid */
  71. assert(test_real_mod(keymap, XKB_MOD_NAME_SHIFT, XKB_MOD_INDEX_SHIFT, ShiftMask));
  72. assert(test_real_mod(keymap, XKB_MOD_NAME_CAPS, XKB_MOD_INDEX_CAPS, LockMask));
  73. assert(test_real_mod(keymap, XKB_MOD_NAME_CTRL, XKB_MOD_INDEX_CTRL, ControlMask));
  74. assert(test_real_mod(keymap, XKB_MOD_NAME_MOD1, XKB_MOD_INDEX_MOD1, Mod1Mask));
  75. assert(test_real_mod(keymap, XKB_MOD_NAME_MOD2, XKB_MOD_INDEX_MOD2, Mod2Mask));
  76. assert(test_real_mod(keymap, XKB_MOD_NAME_MOD3, XKB_MOD_INDEX_MOD3, Mod3Mask));
  77. assert(test_real_mod(keymap, XKB_MOD_NAME_MOD4, XKB_MOD_INDEX_MOD4, Mod4Mask));
  78. assert(test_real_mod(keymap, XKB_MOD_NAME_MOD5, XKB_MOD_INDEX_MOD5, Mod5Mask));
  79. /* Usual virtual mods mappings */
  80. assert(test_real_mod(keymap, XKB_MOD_NAME_ALT, XKB_MOD_INDEX_MOD1, Mod1Mask));
  81. assert(test_real_mod(keymap, XKB_MOD_NAME_NUM, XKB_MOD_INDEX_MOD2, Mod2Mask));
  82. assert(test_real_mod(keymap, XKB_MOD_NAME_LOGO, XKB_MOD_INDEX_MOD4, Mod4Mask));
  83. /* Virtual modifiers
  84. * The indices depends on the keymap files */
  85. assert(test_virtual_mod(keymap, XKB_VMOD_NAME_ALT, XKB_MOD_INDEX_MOD5 + 2, Mod1Mask));
  86. assert(test_virtual_mod(keymap, XKB_VMOD_NAME_META, XKB_MOD_INDEX_MOD5 + 11, Mod1Mask));
  87. assert(test_virtual_mod(keymap, XKB_VMOD_NAME_NUM, XKB_MOD_INDEX_MOD5 + 1, Mod2Mask));
  88. assert(test_virtual_mod(keymap, XKB_VMOD_NAME_SUPER, XKB_MOD_INDEX_MOD5 + 12, Mod4Mask));
  89. assert(test_virtual_mod(keymap, XKB_VMOD_NAME_HYPER, XKB_MOD_INDEX_MOD5 + 13, Mod4Mask));
  90. assert(test_virtual_mod(keymap, XKB_VMOD_NAME_LEVEL3, XKB_MOD_INDEX_MOD5 + 3, Mod5Mask));
  91. assert(test_virtual_mod(keymap, XKB_VMOD_NAME_SCROLL, XKB_MOD_INDEX_MOD5 + 8, 0 ));
  92. /* TODO: current xkeyboard-config maps LevelFive to Nod3 by default */
  93. assert(test_virtual_mod(keymap, XKB_VMOD_NAME_LEVEL5, XKB_MOD_INDEX_MOD5 + 9, 0));
  94. /* Legacy stuff, removed from xkeyboard-config */
  95. assert(keymap->mods.num_mods == 21);
  96. assert(test_virtual_mod(keymap, "LAlt", XKB_MOD_INDEX_MOD5 + 4, 0 ));
  97. assert(test_virtual_mod(keymap, "RAlt", XKB_MOD_INDEX_MOD5 + 5, 0 ));
  98. assert(test_virtual_mod(keymap, "LControl", XKB_MOD_INDEX_MOD5 + 7, 0 ));
  99. assert(test_virtual_mod(keymap, "RControl", XKB_MOD_INDEX_MOD5 + 6, 0 ));
  100. assert(test_virtual_mod(keymap, "AltGr", XKB_MOD_INDEX_MOD5 + 10, Mod5Mask));
  101. xkb_keymap_unref(keymap);
  102. }
  103. static void
  104. test_modmap_none(struct xkb_context *context)
  105. {
  106. struct xkb_keymap *keymap;
  107. const struct xkb_key *key;
  108. xkb_keycode_t keycode;
  109. keymap = test_compile_file(
  110. context, XKB_KEYMAP_FORMAT_TEXT_V2, "keymaps/modmap-none.xkb"
  111. );
  112. assert(keymap);
  113. static const struct {
  114. const char *key_name;
  115. enum real_mod_mask modmap;
  116. } tests[] = {
  117. { "LVL3", NoModifier },
  118. { "LFSH", NoModifier },
  119. { "RTSH", NoModifier },
  120. { "LWIN", Mod4Mask },
  121. { "RWIN", Mod4Mask },
  122. { "LCTL", ControlMask },
  123. { "RCTL", ControlMask },
  124. { "LALT", Mod1Mask },
  125. { "RALT", (Mod2Mask | Mod5Mask) },
  126. { "CAPS", LockMask },
  127. { "AD01", Mod1Mask },
  128. { "AD02", NoModifier },
  129. { "AD03", NoModifier },
  130. { "AD04", Mod1Mask },
  131. { "AD05", Mod2Mask },
  132. { "AD06", Mod3Mask },
  133. { "AD07", Mod1Mask },
  134. { "AD08", Mod2Mask },
  135. { "AD09", Mod3Mask },
  136. { "AD10", (Mod3Mask | Mod4Mask) },
  137. { "AD11", (Mod3Mask | Mod4Mask | Mod5Mask) },
  138. };
  139. for (size_t t = 0; t < ARRAY_SIZE(tests); t++) {
  140. fprintf(stderr, "------\n*** %s #%zu: key %s ***\n",
  141. __func__, t, tests[t].key_name);
  142. keycode = xkb_keymap_key_by_name(keymap, tests[t].key_name);
  143. assert(keycode != XKB_KEYCODE_INVALID);
  144. key = XkbKey(keymap, keycode);
  145. assert(key);
  146. assert(key->modmap == (xkb_mod_mask_t)tests[t].modmap);
  147. }
  148. xkb_keymap_unref(keymap);
  149. }
  150. static void
  151. test_modmap_mask(struct xkb_context *ctx, bool update_output_files)
  152. {
  153. static const struct {
  154. const char * keymap;
  155. struct {
  156. const char * v1;
  157. const char * v2;
  158. } expected;
  159. } tests[] = {
  160. {
  161. .keymap =
  162. "xkb_keymap {\n"
  163. " xkb_keycodes { <> = 1; };\n"
  164. " xkb_compat {\n"
  165. " virtual_modifiers Alt;\n"
  166. " interpret Shift_L + Any {\n"
  167. " action = SetMods(modifiers=Shift);\n"
  168. " };\n"
  169. " interpret Alt_L + Any {\n"
  170. " virtualModifier = Alt;\n"
  171. " action = SetMods(modifiers=Alt);\n"
  172. " };\n"
  173. " };\n"
  174. " xkb_types {\n"
  175. " type \"TWO_LEVEL\" {\n"
  176. " modifiers = Shift;\n"
  177. " map[Shift] = 2;\n"
  178. " };\n"
  179. " };\n"
  180. " xkb_symbols {\n"
  181. " key <> { [Alt_L, Shift_L] };\n"
  182. " modifier_map Shift { Shift_L };\n"
  183. " modifier_map Mod1 { <> };\n"
  184. " };\n"
  185. "};",
  186. .expected = {
  187. .v1 = GOLDEN_TESTS_OUTPUTS "modmap-key+keysym-v1.xkb",
  188. .v2 = GOLDEN_TESTS_OUTPUTS "modmap-key+keysym-v2.xkb",
  189. }
  190. },
  191. {
  192. .keymap =
  193. "xkb_keymap {\n"
  194. " xkb_keycodes { <> = 1; };\n"
  195. " xkb_symbols {\n"
  196. " modifier_map Shift+Mod1 { <> };\n"
  197. " };\n"
  198. "};",
  199. .expected = {
  200. .v1 = NULL,
  201. .v2 = GOLDEN_TESTS_OUTPUTS "modmap-identifier-mask-v2.xkb",
  202. }
  203. },
  204. {
  205. .keymap =
  206. "xkb_keymap {\n"
  207. " xkb_keycodes { <> = 1; };\n"
  208. " xkb_symbols {\n"
  209. " modifier_map 0x9 { <> };\n"
  210. " };\n"
  211. "};",
  212. .expected = {
  213. .v1 = NULL,
  214. .v2 = GOLDEN_TESTS_OUTPUTS "modmap-identifier-mask-v2.xkb",
  215. }
  216. },
  217. };
  218. for (uint8_t t = 0; t < (uint8_t)ARRAY_SIZE(tests); t++) {
  219. fprintf(stderr, "------\n*** %s: #%u ***\n", __func__, t);
  220. assert(test_compile_output(ctx, XKB_KEYMAP_FORMAT_TEXT_V1,
  221. XKB_KEYMAP_USE_ORIGINAL_FORMAT,
  222. compile_buffer, NULL, __func__,
  223. tests[t].keymap, strlen(tests[t].keymap),
  224. tests[t].expected.v1, update_output_files));
  225. assert(test_compile_output(ctx, XKB_KEYMAP_FORMAT_TEXT_V2,
  226. XKB_KEYMAP_USE_ORIGINAL_FORMAT,
  227. compile_buffer, NULL, __func__,
  228. tests[t].keymap, strlen(tests[t].keymap),
  229. tests[t].expected.v2, update_output_files));
  230. }
  231. }
  232. static void
  233. test_explicit_virtual_modifiers(struct xkb_context *context)
  234. {
  235. static const struct {
  236. const char* keymap;
  237. struct mod_props {
  238. enum mod_type type;
  239. xkb_mod_mask_t mapping;
  240. xkb_mod_mask_t mapping_effective;
  241. } m1;
  242. struct mod_props m2;
  243. } tests[] = {
  244. /* Test virtual modifiers with canonical mappings */
  245. {
  246. .keymap =
  247. "xkb_keymap {\n"
  248. " xkb_compat {\n"
  249. /* Vmods map to themselves */
  250. " virtual_modifiers M1 = 0x100, M2 = 0x200;\n"
  251. " };\n"
  252. "};",
  253. .m1 = {
  254. .type = MOD_VIRT,
  255. .mapping = 0x100,
  256. .mapping_effective = 0x100
  257. },
  258. .m2 = {
  259. .type = MOD_VIRT,
  260. .mapping = 0x200,
  261. .mapping_effective = 0x200
  262. }
  263. },
  264. /* Test virtual modifiers overlapping: identical */
  265. {
  266. .keymap =
  267. "xkb_keymap {\n"
  268. " xkb_compat {\n"
  269. " virtual_modifiers M1 = 0x100, M2 = 0x100;\n"
  270. " };\n"
  271. "};",
  272. .m1 = {
  273. .type = MOD_VIRT,
  274. .mapping = 0x100,
  275. .mapping_effective = 0x100
  276. },
  277. .m2 = {
  278. .type = MOD_VIRT,
  279. .mapping = 0x100,
  280. .mapping_effective = 0x100
  281. }
  282. },
  283. /* Test virtual modifiers overlapping: non identical */
  284. {
  285. .keymap =
  286. "xkb_keymap {\n"
  287. " xkb_compat {\n"
  288. " virtual_modifiers M1 = 0x100, M2 = 0x300;\n"
  289. " };\n"
  290. "};",
  291. .m1 = {
  292. .type = MOD_VIRT,
  293. .mapping = 0x100,
  294. .mapping_effective = 0x100
  295. },
  296. .m2 = {
  297. .type = MOD_VIRT,
  298. .mapping = 0x300,
  299. .mapping_effective = 0x300
  300. }
  301. },
  302. /* Test virtual modifiers with swapped mappings */
  303. {
  304. .keymap =
  305. "xkb_keymap {\n"
  306. " xkb_compat {\n"
  307. /* The mapping of each modifier is the mask of the other */
  308. " virtual_modifiers M1 = 0x200, M2 = 0x100;\n"
  309. " };\n"
  310. "};",
  311. .m1 = {
  312. .type = MOD_VIRT,
  313. .mapping = 0x200,
  314. .mapping_effective = 0x100 /* different from mapping! */
  315. },
  316. .m2 = {
  317. .type = MOD_VIRT,
  318. .mapping = 0x100,
  319. .mapping_effective = 0x200 /* different from mapping! */
  320. }
  321. },
  322. /* Test virtual modifiers mapping to undefined modifiers */
  323. {
  324. .keymap =
  325. "xkb_keymap {\n"
  326. " xkb_compat {\n"
  327. " virtual_modifiers M1 = 0x400, M2 = 0x800;\n"
  328. " };\n"
  329. "};",
  330. .m1 = {
  331. .type = MOD_VIRT,
  332. .mapping = 0x400,
  333. .mapping_effective = 0 /* no mod entry */
  334. },
  335. .m2 = {
  336. .type = MOD_VIRT,
  337. .mapping = 0x800,
  338. .mapping_effective = 0 /* no mod entry */
  339. }
  340. },
  341. };
  342. for (unsigned int k = 0; k < ARRAY_SIZE(tests); k++) {
  343. fprintf(stderr, "------\n*** %s: #%u ***\n", __func__, k);
  344. struct xkb_keymap *keymap = test_compile_buffer(
  345. context, XKB_KEYMAP_FORMAT_TEXT_V1,
  346. tests[k].keymap, strlen(tests[k].keymap)
  347. );
  348. assert(keymap);
  349. const xkb_mod_index_t m1_idx = xkb_keymap_mod_get_index(keymap, "M1");
  350. const xkb_mod_index_t m2_idx = xkb_keymap_mod_get_index(keymap, "M2");
  351. assert(m1_idx == 8);
  352. assert(m2_idx == 9);
  353. assert(keymap->mods.mods[m1_idx].type == tests[k].m1.type);
  354. assert(keymap->mods.mods[m2_idx].type == tests[k].m2.type);
  355. const xkb_mod_mask_t m1 = UINT32_C(1) << m1_idx;
  356. const xkb_mod_mask_t m2 = UINT32_C(1) << m2_idx;
  357. const xkb_mod_mask_t m1_mapping = mod_mask_get_effective(keymap, m1);
  358. const xkb_mod_mask_t m2_mapping = mod_mask_get_effective(keymap, m2);
  359. assert(m1_mapping == tests[k].m1.mapping);
  360. assert(m2_mapping == tests[k].m2.mapping);
  361. /* mod_mask_get_effective is not idempotent */
  362. assert(mod_mask_get_effective(keymap, m1_mapping) ==
  363. tests[k].m1.mapping_effective);
  364. assert(mod_mask_get_effective(keymap, m2_mapping) ==
  365. tests[k].m2.mapping_effective);
  366. struct xkb_state *state =
  367. xkb_state_new_with_mode(keymap, XKB_STATE_MODE_CLIENT);
  368. assert(state);
  369. /* Not in the canonical modifier mask nor denotes a *known* virtual
  370. * modifiers, so it will be discarded. */
  371. const xkb_mod_mask_t noise = UINT32_C(0x8000);
  372. assert((keymap->canonical_state_mask & noise) == 0);
  373. /* Update the state, then check round-trip and mods state */
  374. const xkb_mod_mask_t set_masks[] = {m1_mapping, m2_mapping};
  375. for (unsigned int m = 0; m < ARRAY_SIZE(set_masks); m++) {
  376. const xkb_mod_mask_t expected = set_masks[m];
  377. xkb_state_update_mask(state, expected | noise, 0, noise, 0, 0, 0);
  378. const xkb_mod_mask_t got =
  379. xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE);
  380. assert_printf(got == expected, /* round-trip */
  381. "expected %#"PRIx32", got %#"PRIx32"\n",
  382. expected, got);
  383. assert(
  384. xkb_state_mod_index_is_active(state, m1_idx,
  385. XKB_STATE_MODS_EFFECTIVE) ==
  386. ((expected & m1_mapping) == m1_mapping)
  387. );
  388. assert(
  389. xkb_state_mod_index_is_active(state, m2_idx,
  390. XKB_STATE_MODS_EFFECTIVE) ==
  391. ((expected & m2_mapping) == m2_mapping)
  392. );
  393. }
  394. xkb_state_unref(state);
  395. xkb_keymap_unref(keymap);
  396. }
  397. }
  398. /*
  399. * Test the hack documented in the FAQ to get virtual modifiers mapping using
  400. * `xkb_state_update_mask`/`xkb_state_serialize_mods`.
  401. *
  402. * This should work without problem for keymap using only real mods to map
  403. * virtual modifiers.
  404. *
  405. * [NOTE] If the test requires an update, do not forget to update the FAQ as well!
  406. */
  407. static void
  408. test_virtual_modifiers_mapping_hack(struct xkb_context *context)
  409. {
  410. struct xkb_keymap *keymap = test_compile_rules(context,
  411. XKB_KEYMAP_FORMAT_TEXT_V1,
  412. "evdev", "pc104",
  413. "us", NULL, NULL);
  414. assert(keymap);
  415. struct xkb_state* state =
  416. xkb_state_new_with_mode(keymap, XKB_STATE_MODE_CLIENT);
  417. assert(state);
  418. static const struct {
  419. const char* name;
  420. xkb_mod_index_t index;
  421. xkb_mod_mask_t mapping;
  422. } mods[] = {
  423. /* Real modifiers */
  424. {
  425. .name = XKB_MOD_NAME_SHIFT,
  426. .index = XKB_MOD_INDEX_SHIFT,
  427. .mapping = UINT32_C(1) << XKB_MOD_INDEX_SHIFT
  428. },
  429. {
  430. .name = XKB_MOD_NAME_CAPS,
  431. .index = XKB_MOD_INDEX_CAPS,
  432. .mapping = UINT32_C(1) << XKB_MOD_INDEX_CAPS
  433. },
  434. {
  435. .name = XKB_MOD_NAME_CTRL,
  436. .index = XKB_MOD_INDEX_CTRL,
  437. .mapping = UINT32_C(1) << XKB_MOD_INDEX_CTRL
  438. },
  439. {
  440. .name = XKB_MOD_NAME_MOD1,
  441. .index = XKB_MOD_INDEX_MOD1,
  442. .mapping = UINT32_C(1) << XKB_MOD_INDEX_MOD1
  443. },
  444. {
  445. .name = XKB_MOD_NAME_MOD2,
  446. .index = XKB_MOD_INDEX_MOD2,
  447. .mapping = UINT32_C(1) << XKB_MOD_INDEX_MOD2
  448. },
  449. {
  450. .name = XKB_MOD_NAME_MOD3,
  451. .index = XKB_MOD_INDEX_MOD3,
  452. .mapping = UINT32_C(1) << XKB_MOD_INDEX_MOD3
  453. },
  454. {
  455. .name = XKB_MOD_NAME_MOD4,
  456. .index = XKB_MOD_INDEX_MOD4,
  457. .mapping = UINT32_C(1) << XKB_MOD_INDEX_MOD4
  458. },
  459. {
  460. .name = XKB_MOD_NAME_MOD5,
  461. .index = XKB_MOD_INDEX_MOD5,
  462. .mapping = UINT32_C(1) << XKB_MOD_INDEX_MOD5
  463. },
  464. /* Virtual modifiers
  465. * The indices depends on the keymap files */
  466. {
  467. .name = XKB_VMOD_NAME_ALT,
  468. .index = XKB_MOD_INDEX_MOD5 + 2,
  469. .mapping = Mod1Mask
  470. },
  471. {
  472. .name = XKB_VMOD_NAME_META,
  473. .index = XKB_MOD_INDEX_MOD5 + 11,
  474. .mapping = Mod1Mask
  475. },
  476. {
  477. .name = XKB_VMOD_NAME_NUM,
  478. .index = XKB_MOD_INDEX_MOD5 + 1,
  479. .mapping = Mod2Mask
  480. },
  481. {
  482. .name = XKB_VMOD_NAME_SUPER,
  483. .index = XKB_MOD_INDEX_MOD5 + 12,
  484. .mapping = Mod4Mask
  485. },
  486. {
  487. .name = XKB_VMOD_NAME_HYPER,
  488. .index = XKB_MOD_INDEX_MOD5 + 13,
  489. .mapping = Mod4Mask
  490. },
  491. {
  492. .name = XKB_VMOD_NAME_LEVEL3,
  493. .index = XKB_MOD_INDEX_MOD5 + 3,
  494. .mapping = Mod5Mask
  495. },
  496. {
  497. .name = XKB_VMOD_NAME_SCROLL,
  498. .index = XKB_MOD_INDEX_MOD5 + 8,
  499. .mapping = 0
  500. },
  501. {
  502. .name = XKB_VMOD_NAME_LEVEL5,
  503. .index = XKB_MOD_INDEX_MOD5 + 9,
  504. .mapping = 0
  505. },
  506. /* Legacy stuff, removed from xkeyboard-config */
  507. {
  508. .name = "LAlt",
  509. .index = XKB_MOD_INDEX_MOD5 + 4,
  510. .mapping = 0
  511. },
  512. {
  513. .name = "RAlt",
  514. .index = XKB_MOD_INDEX_MOD5 + 5,
  515. .mapping = 0
  516. },
  517. {
  518. .name = "LControl",
  519. .index = XKB_MOD_INDEX_MOD5 + 7,
  520. .mapping = 0
  521. },
  522. {
  523. .name = "RControl",
  524. .index = XKB_MOD_INDEX_MOD5 + 6,
  525. .mapping = 0
  526. },
  527. {
  528. .name = "AltGr",
  529. .index = XKB_MOD_INDEX_MOD5 + 10,
  530. .mapping = Mod5Mask
  531. },
  532. };
  533. for (unsigned int k = 0; k < ARRAY_SIZE(mods); k++) {
  534. const xkb_mod_mask_t index =
  535. xkb_keymap_mod_get_index(keymap, mods[k].name);
  536. assert_printf(index == mods[k].index,
  537. "%s: expected %"PRIu32", got: %"PRIu32"\n",
  538. mods[k].name, mods[k].index, index);
  539. const xkb_mod_mask_t mask = UINT32_C(1) << index;
  540. xkb_state_update_mask(state, mask, 0, 0, 0, 0, 0);
  541. const xkb_mod_mask_t mapping =
  542. xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE);
  543. assert_printf(mapping == mods[k].mapping,
  544. "%s: expected %#"PRIx32", got: %#"PRIx32"\n",
  545. mods[k].name, mods[k].mapping, mapping);
  546. assert(mapping == xkb_keymap_mod_get_mask(keymap, mods[k].name));
  547. assert(mapping == xkb_keymap_mod_get_mask2(keymap, mods[k].index));
  548. }
  549. xkb_state_unref(state);
  550. xkb_keymap_unref(keymap);
  551. }
  552. static void
  553. test_pure_virtual_modifiers(struct xkb_context *context)
  554. {
  555. struct xkb_keymap *keymap;
  556. /* Test definition of >20 pure virtual modifiers.
  557. * We overcome the X11 limit of 16 virtual modifiers. */
  558. struct {
  559. const char* path;
  560. enum xkb_keymap_format formats[2];
  561. } keymaps[] = {
  562. {
  563. .path = "keymaps/pure-virtual-mods-explicit.xkb",
  564. .formats = { XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_FORMAT_TEXT_V2 }
  565. },
  566. {
  567. .path = "keymaps/pure-virtual-mods-implicit.xkb",
  568. /* Auto canonical vmod available since keymap format v2 */
  569. .formats = { XKB_KEYMAP_FORMAT_TEXT_V2 }
  570. }
  571. };
  572. for (unsigned int k = 0; k < ARRAY_SIZE(keymaps); k++) {
  573. for (unsigned int f = 0; f < ARRAY_SIZE(keymaps[k].formats); f++) {
  574. if (!keymaps[k].formats[f])
  575. break;
  576. fprintf(stderr, "------\n*** %s: #%u %s (%d) ***\n",
  577. __func__, k, keymaps[k].path, keymaps[k].formats[f]);
  578. keymap = test_compile_file(context, keymaps[k].formats[f],
  579. keymaps[k].path);
  580. assert(keymap);
  581. assert(test_key_seq(keymap,
  582. KEY_W, BOTH, XKB_KEY_w, NEXT,
  583. KEY_A, DOWN, XKB_KEY_a, NEXT,
  584. KEY_W, BOTH, XKB_KEY_a, NEXT,
  585. KEY_A, UP, XKB_KEY_a, NEXT,
  586. KEY_B, DOWN, XKB_KEY_b, NEXT,
  587. KEY_W, BOTH, XKB_KEY_b, NEXT,
  588. KEY_B, UP, XKB_KEY_b, NEXT,
  589. KEY_C, DOWN, XKB_KEY_c, NEXT,
  590. KEY_W, BOTH, XKB_KEY_c, NEXT,
  591. KEY_C, UP, XKB_KEY_c, NEXT,
  592. KEY_D, DOWN, XKB_KEY_d, NEXT,
  593. KEY_W, BOTH, XKB_KEY_d, NEXT,
  594. KEY_D, UP, XKB_KEY_d, NEXT,
  595. KEY_E, DOWN, XKB_KEY_e, NEXT,
  596. KEY_W, BOTH, XKB_KEY_e, NEXT,
  597. KEY_E, UP, XKB_KEY_e, NEXT,
  598. KEY_F, DOWN, XKB_KEY_f, NEXT,
  599. KEY_W, BOTH, XKB_KEY_f, NEXT,
  600. KEY_F, UP, XKB_KEY_f, NEXT,
  601. KEY_G, DOWN, XKB_KEY_g, NEXT,
  602. KEY_W, BOTH, XKB_KEY_g, NEXT,
  603. KEY_G, UP, XKB_KEY_g, NEXT,
  604. KEY_H, DOWN, XKB_KEY_h, NEXT,
  605. KEY_W, BOTH, XKB_KEY_h, NEXT,
  606. KEY_H, UP, XKB_KEY_h, NEXT,
  607. KEY_I, DOWN, XKB_KEY_i, NEXT,
  608. KEY_W, BOTH, XKB_KEY_i, NEXT,
  609. KEY_I, UP, XKB_KEY_i, NEXT,
  610. KEY_J, DOWN, XKB_KEY_j, NEXT,
  611. KEY_W, BOTH, XKB_KEY_j, NEXT,
  612. KEY_J, UP, XKB_KEY_j, NEXT,
  613. KEY_K, DOWN, XKB_KEY_k, NEXT,
  614. KEY_W, BOTH, XKB_KEY_k, NEXT,
  615. KEY_K, UP, XKB_KEY_k, NEXT,
  616. KEY_L, DOWN, XKB_KEY_l, NEXT,
  617. KEY_W, BOTH, XKB_KEY_l, NEXT,
  618. KEY_L, UP, XKB_KEY_l, NEXT,
  619. KEY_M, DOWN, XKB_KEY_m, NEXT,
  620. KEY_W, BOTH, XKB_KEY_m, NEXT,
  621. KEY_M, UP, XKB_KEY_m, NEXT,
  622. KEY_N, DOWN, XKB_KEY_n, NEXT,
  623. KEY_W, BOTH, XKB_KEY_n, NEXT,
  624. KEY_N, UP, XKB_KEY_n, NEXT,
  625. KEY_O, DOWN, XKB_KEY_o, NEXT,
  626. KEY_W, BOTH, XKB_KEY_o, NEXT,
  627. KEY_O, UP, XKB_KEY_o, NEXT,
  628. KEY_P, DOWN, XKB_KEY_p, NEXT,
  629. KEY_W, BOTH, XKB_KEY_p, NEXT,
  630. KEY_P, UP, XKB_KEY_p, NEXT,
  631. KEY_Q, DOWN, XKB_KEY_q, NEXT,
  632. KEY_W, BOTH, XKB_KEY_q, NEXT,
  633. KEY_Q, UP, XKB_KEY_q, NEXT,
  634. KEY_R, DOWN, XKB_KEY_r, NEXT,
  635. KEY_W, BOTH, XKB_KEY_r, NEXT,
  636. KEY_R, UP, XKB_KEY_r, NEXT,
  637. KEY_S, DOWN, XKB_KEY_s, NEXT,
  638. KEY_W, BOTH, XKB_KEY_s, NEXT,
  639. KEY_S, UP, XKB_KEY_s, NEXT,
  640. KEY_T, DOWN, XKB_KEY_t, NEXT,
  641. KEY_W, BOTH, XKB_KEY_t, NEXT,
  642. KEY_T, UP, XKB_KEY_t, NEXT,
  643. KEY_U, DOWN, XKB_KEY_u, NEXT,
  644. KEY_W, BOTH, XKB_KEY_u, NEXT,
  645. KEY_U, UP, XKB_KEY_u, NEXT,
  646. KEY_V, DOWN, XKB_KEY_v, NEXT,
  647. KEY_W, BOTH, XKB_KEY_v, NEXT,
  648. KEY_LEFTSHIFT, DOWN, XKB_KEY_Shift_L, NEXT,
  649. KEY_W, BOTH, XKB_KEY_V, NEXT,
  650. KEY_LEFTSHIFT, UP, XKB_KEY_Shift_L, NEXT,
  651. KEY_V, UP, XKB_KEY_v, NEXT,
  652. KEY_A, DOWN, XKB_KEY_a, NEXT,
  653. KEY_S, DOWN, XKB_KEY_s, NEXT,
  654. KEY_W, BOTH, XKB_KEY_1, NEXT,
  655. KEY_RIGHTALT, DOWN, XKB_KEY_ISO_Level3_Shift, NEXT,
  656. KEY_W, BOTH, XKB_KEY_4, NEXT,
  657. KEY_S, UP, XKB_KEY_s, NEXT,
  658. KEY_W, BOTH, XKB_KEY_3, NEXT,
  659. KEY_RIGHTALT, UP, XKB_KEY_ISO_Level3_Shift, NEXT,
  660. KEY_Q, DOWN, XKB_KEY_q, NEXT,
  661. KEY_W, BOTH, XKB_KEY_2, NEXT,
  662. KEY_Q, UP, XKB_KEY_q, NEXT,
  663. KEY_B, DOWN, XKB_KEY_b, NEXT,
  664. KEY_C, DOWN, XKB_KEY_c, NEXT,
  665. KEY_W, BOTH, XKB_KEY_5, NEXT,
  666. KEY_C, UP, XKB_KEY_c, NEXT,
  667. KEY_B, UP, XKB_KEY_b, NEXT,
  668. KEY_A, UP, XKB_KEY_a, NEXT,
  669. KEY_Y, BOTH, XKB_KEY_y, FINISH));
  670. xkb_keymap_unref(keymap);
  671. }}
  672. /* Test invalid interpret using a virtual modifier */
  673. const char keymap_str[] =
  674. "xkb_keymap {"
  675. " xkb_keycodes { include \"evdev\" };"
  676. " xkb_types { include \"complete\" };"
  677. " xkb_compat { include \"complete+basic(invalid-pure-virtual-modifiers)\" };"
  678. " xkb_symbols { include \"pc(pc105-pure-virtual-modifiers)\" };"
  679. "};";
  680. keymap = test_compile_string(context, XKB_KEYMAP_FORMAT_TEXT_V1, keymap_str);
  681. assert(!keymap);
  682. }
  683. /* Test FAQ snippet */
  684. // NOLINTBEGIN(readability-duplicate-include)
  685. //! [xkb_keymap_mod_get_codes]
  686. #include <xkbcommon/xkbcommon.h>
  687. /**
  688. * Get the keycodes associated with a modifier by index.
  689. *
  690. * @param[in] keymap The keymap
  691. * @param[in] idx The index of the modifier
  692. * @param[out] codes_out A buffer in which the codes should be stored
  693. * @param[out] codes_size The size of the codes_out buffer
  694. *
  695. * @returns the number of key codes in the keysyms_out array, or a negative
  696. * in case of error.
  697. */
  698. static ssize_t
  699. xkb_keymap_mod_get_codes(struct xkb_keymap *keymap, xkb_mod_index_t mod,
  700. xkb_keycode_t *codes_out, size_t codes_size)
  701. {
  702. if (mod >= xkb_keymap_num_mods(keymap))
  703. return -1;
  704. ssize_t idx = 0;
  705. for (xkb_keycode_t k = xkb_keymap_min_keycode(keymap);
  706. k <= xkb_keymap_max_keycode(keymap) && idx >= 0; k++) {
  707. /*
  708. * We only test the first level of the first group.
  709. *
  710. * Since there is currently no way to reset the state, use a new one to
  711. * avoid side effects (latches, etc.)
  712. */
  713. struct xkb_state * const state =
  714. xkb_state_new_with_mode(keymap, XKB_STATE_MODE_SERVER);
  715. assert(state);
  716. static const enum xkb_key_direction directions[] = {
  717. XKB_KEY_DOWN,
  718. XKB_KEY_UP
  719. };
  720. for (size_t d = 0; d < ARRAY_SIZE(directions); d++) {
  721. if (xkb_state_update_key(state, k, directions[d]) &&
  722. xkb_state_mod_index_is_active(state, mod,
  723. XKB_STATE_MODS_EFFECTIVE)) {
  724. if ((size_t) idx < codes_size) {
  725. assert(idx < (ssize_t) (SIZE_MAX / 2));
  726. codes_out[idx++] = k;
  727. } else {
  728. idx = -2;
  729. }
  730. break;
  731. }
  732. }
  733. xkb_state_unref(state);
  734. }
  735. return idx;
  736. }
  737. //! [xkb_keymap_mod_get_codes]
  738. // NOLINTEND(readability-duplicate-include)
  739. static void
  740. test_get_modifier_keycodes(struct xkb_context *context)
  741. {
  742. struct xkb_keymap *keymap = test_compile_rules(context,
  743. XKB_KEYMAP_FORMAT_TEXT_V1,
  744. "evdev", "pc104",
  745. "cz", NULL, NULL);
  746. assert(keymap);
  747. #define MAX_KEYCODES_COUNT 10
  748. #define KEY_LVL3 (92 - EVDEV_OFFSET)
  749. const struct {
  750. const char *mod;
  751. xkb_keycode_t keycodes[MAX_KEYCODES_COUNT];
  752. } mods[] = {
  753. { .mod = XKB_MOD_NAME_SHIFT, .keycodes = { KEY_LEFTSHIFT, KEY_RIGHTSHIFT, 0 } },
  754. { .mod = XKB_MOD_NAME_CAPS, .keycodes = { KEY_CAPSLOCK, 0 } },
  755. { .mod = XKB_MOD_NAME_CTRL, .keycodes = { KEY_LEFTCTRL, KEY_RIGHTCTRL, 0 } },
  756. { .mod = XKB_MOD_NAME_MOD1, .keycodes = { KEY_LEFTALT, 0 } },
  757. { .mod = XKB_MOD_NAME_MOD2, .keycodes = { KEY_NUMLOCK, 0 } },
  758. { .mod = XKB_MOD_NAME_MOD3, .keycodes = { 0 } },
  759. { .mod = XKB_MOD_NAME_MOD4, .keycodes = { KEY_LEFTMETA, KEY_RIGHTMETA, 0 } },
  760. { .mod = XKB_MOD_NAME_MOD5, .keycodes = { KEY_LVL3, KEY_RIGHTALT, 0 } },
  761. { .mod = XKB_VMOD_NAME_ALT, .keycodes = { KEY_LEFTALT, 0 } },
  762. { .mod = XKB_VMOD_NAME_META, .keycodes = { KEY_LEFTALT, 0 } },
  763. { .mod = XKB_VMOD_NAME_SUPER, .keycodes = { KEY_LEFTMETA, KEY_RIGHTMETA, 0 } },
  764. { .mod = XKB_VMOD_NAME_HYPER, .keycodes = { KEY_LEFTMETA, KEY_RIGHTMETA, 0 } },
  765. { .mod = XKB_VMOD_NAME_NUM, .keycodes = { KEY_NUMLOCK, 0 } },
  766. { .mod = XKB_VMOD_NAME_LEVEL3, .keycodes = { KEY_LVL3, KEY_RIGHTALT, 0 } },
  767. { .mod = XKB_VMOD_NAME_LEVEL5, .keycodes = { 0 } },
  768. };
  769. xkb_keycode_t got[MAX_KEYCODES_COUNT] = {0};
  770. for (size_t m = 0; m < ARRAY_SIZE(mods); m++) {
  771. const xkb_mod_index_t mod = xkb_keymap_mod_get_index(keymap, mods[m].mod);
  772. assert(mod != XKB_MOD_INVALID);
  773. const ssize_t count =
  774. xkb_keymap_mod_get_codes(keymap, mod, got, ARRAY_SIZE(got));
  775. assert(count >= 0);
  776. const xkb_keycode_t * const expected = mods[m].keycodes;
  777. for (size_t k = 0; k < ARRAY_SIZE(got); k++) {
  778. if (expected[k] == 0) {
  779. assert_printf(k == (size_t) count,
  780. "Mod %s: expected %zu, got %zd\n",
  781. mods[m].mod, k, count);
  782. break;
  783. }
  784. assert_printf(k < (size_t) count,
  785. "Mod %s: Missing keycode 0x%"PRIu32"\n",
  786. mods[m].mod, expected[k]);
  787. assert_printf(got[k] == expected[k] + EVDEV_OFFSET,
  788. "Mod %s: Expected keycode %"PRIu32" but got: %"PRIu32"\n",
  789. mods[m].mod, expected[k] + EVDEV_OFFSET, got[k]);
  790. }
  791. }
  792. xkb_keymap_unref(keymap);
  793. }
  794. #undef MAX_KEYCODES_COUNT
  795. int
  796. main(int argc, char *argv[])
  797. {
  798. test_init();
  799. bool update_output_files = false;
  800. int arg_index = 0;
  801. while (++arg_index < argc) {
  802. if (streq(argv[arg_index], "update")) {
  803. /* Update files with *obtained* results */
  804. update_output_files = true;
  805. }
  806. }
  807. struct xkb_context *context = test_get_context(CONTEXT_NO_FLAG);
  808. assert(context);
  809. test_modmap_none(context);
  810. test_modifiers_names(context);
  811. test_modmap_mask(context, update_output_files);
  812. test_explicit_virtual_modifiers(context);
  813. test_virtual_modifiers_mapping_hack(context);
  814. test_pure_virtual_modifiers(context);
  815. test_get_modifier_keycodes(context);
  816. xkb_context_unref(context);
  817. return 0;
  818. }