| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871 |
- /*
- * Copyright © 2023 Pierre Le Marre <dev@wismill.eu>
- * SPDX-License-Identifier: MIT
- */
- #include "config.h"
- #include "test-config.h"
- #include <assert.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include "xkbcommon/xkbcommon.h"
- #include "xkbcommon/xkbcommon-names.h"
- #include "evdev-scancodes.h"
- #include "test.h"
- #include "keymap.h"
- #include "utils.h"
- #define GOLDEN_TESTS_OUTPUTS "keymaps/"
- /* Standard real modifier masks */
- enum real_mod_mask {
- ShiftMask = (UINT32_C(1) << XKB_MOD_INDEX_SHIFT),
- LockMask = (UINT32_C(1) << XKB_MOD_INDEX_CAPS),
- ControlMask = (UINT32_C(1) << XKB_MOD_INDEX_CTRL),
- Mod1Mask = (UINT32_C(1) << XKB_MOD_INDEX_MOD1),
- Mod2Mask = (UINT32_C(1) << XKB_MOD_INDEX_MOD2),
- Mod3Mask = (UINT32_C(1) << XKB_MOD_INDEX_MOD3),
- Mod4Mask = (UINT32_C(1) << XKB_MOD_INDEX_MOD4),
- Mod5Mask = (UINT32_C(1) << XKB_MOD_INDEX_MOD5),
- NoModifier = 0
- };
- /* Our keymap compiler is the xkbcommon buffer compiler */
- static struct xkb_keymap *
- compile_buffer(struct xkb_context *context, enum xkb_keymap_format format,
- const char *buf, size_t len, void *private)
- {
- const enum xkb_keymap_compile_flags flags
- = (private)
- ? *(enum xkb_keymap_compile_flags*)private
- : TEST_KEYMAP_COMPILE_FLAGS;
- return test_compile_buffer2(context, format, flags, buf, len);
- }
- static bool
- test_real_mod(struct xkb_keymap *keymap, const char* name,
- xkb_mod_index_t idx, xkb_mod_mask_t mapping)
- {
- return xkb_keymap_mod_get_index(keymap, name) == idx &&
- (keymap->mods.mods[idx].type == MOD_REAL) &&
- mapping == keymap->mods.mods[idx].mapping &&
- mapping == (UINT32_C(1) << idx) &&
- xkb_keymap_mod_get_mask(keymap, name) == mapping &&
- xkb_keymap_mod_get_mask2(keymap, idx) == mapping;
- }
- static bool
- test_virtual_mod(struct xkb_keymap *keymap, const char* name,
- xkb_mod_index_t idx, xkb_mod_mask_t mapping)
- {
- return xkb_keymap_mod_get_index(keymap, name) == idx &&
- (keymap->mods.mods[idx].type == MOD_VIRT) &&
- mapping == keymap->mods.mods[idx].mapping &&
- xkb_keymap_mod_get_mask(keymap, name) == mapping &&
- xkb_keymap_mod_get_mask2(keymap, idx) == mapping;
- }
- /* Check that the provided modifier names work */
- static void
- test_modifiers_names(struct xkb_context *context)
- {
- struct xkb_keymap *keymap;
- keymap = test_compile_rules(context, XKB_KEYMAP_FORMAT_TEXT_V1, "evdev",
- "pc104", "us", NULL, NULL);
- assert(keymap);
- /* Real modifiers
- * The indices and masks are fixed and always valid */
- assert(test_real_mod(keymap, XKB_MOD_NAME_SHIFT, XKB_MOD_INDEX_SHIFT, ShiftMask));
- assert(test_real_mod(keymap, XKB_MOD_NAME_CAPS, XKB_MOD_INDEX_CAPS, LockMask));
- assert(test_real_mod(keymap, XKB_MOD_NAME_CTRL, XKB_MOD_INDEX_CTRL, ControlMask));
- assert(test_real_mod(keymap, XKB_MOD_NAME_MOD1, XKB_MOD_INDEX_MOD1, Mod1Mask));
- assert(test_real_mod(keymap, XKB_MOD_NAME_MOD2, XKB_MOD_INDEX_MOD2, Mod2Mask));
- assert(test_real_mod(keymap, XKB_MOD_NAME_MOD3, XKB_MOD_INDEX_MOD3, Mod3Mask));
- assert(test_real_mod(keymap, XKB_MOD_NAME_MOD4, XKB_MOD_INDEX_MOD4, Mod4Mask));
- assert(test_real_mod(keymap, XKB_MOD_NAME_MOD5, XKB_MOD_INDEX_MOD5, Mod5Mask));
- /* Usual virtual mods mappings */
- assert(test_real_mod(keymap, XKB_MOD_NAME_ALT, XKB_MOD_INDEX_MOD1, Mod1Mask));
- assert(test_real_mod(keymap, XKB_MOD_NAME_NUM, XKB_MOD_INDEX_MOD2, Mod2Mask));
- assert(test_real_mod(keymap, XKB_MOD_NAME_LOGO, XKB_MOD_INDEX_MOD4, Mod4Mask));
- /* Virtual modifiers
- * The indices depends on the keymap files */
- assert(test_virtual_mod(keymap, XKB_VMOD_NAME_ALT, XKB_MOD_INDEX_MOD5 + 2, Mod1Mask));
- assert(test_virtual_mod(keymap, XKB_VMOD_NAME_META, XKB_MOD_INDEX_MOD5 + 11, Mod1Mask));
- assert(test_virtual_mod(keymap, XKB_VMOD_NAME_NUM, XKB_MOD_INDEX_MOD5 + 1, Mod2Mask));
- assert(test_virtual_mod(keymap, XKB_VMOD_NAME_SUPER, XKB_MOD_INDEX_MOD5 + 12, Mod4Mask));
- assert(test_virtual_mod(keymap, XKB_VMOD_NAME_HYPER, XKB_MOD_INDEX_MOD5 + 13, Mod4Mask));
- assert(test_virtual_mod(keymap, XKB_VMOD_NAME_LEVEL3, XKB_MOD_INDEX_MOD5 + 3, Mod5Mask));
- assert(test_virtual_mod(keymap, XKB_VMOD_NAME_SCROLL, XKB_MOD_INDEX_MOD5 + 8, 0 ));
- /* TODO: current xkeyboard-config maps LevelFive to Nod3 by default */
- assert(test_virtual_mod(keymap, XKB_VMOD_NAME_LEVEL5, XKB_MOD_INDEX_MOD5 + 9, 0));
- /* Legacy stuff, removed from xkeyboard-config */
- assert(keymap->mods.num_mods == 21);
- assert(test_virtual_mod(keymap, "LAlt", XKB_MOD_INDEX_MOD5 + 4, 0 ));
- assert(test_virtual_mod(keymap, "RAlt", XKB_MOD_INDEX_MOD5 + 5, 0 ));
- assert(test_virtual_mod(keymap, "LControl", XKB_MOD_INDEX_MOD5 + 7, 0 ));
- assert(test_virtual_mod(keymap, "RControl", XKB_MOD_INDEX_MOD5 + 6, 0 ));
- assert(test_virtual_mod(keymap, "AltGr", XKB_MOD_INDEX_MOD5 + 10, Mod5Mask));
- xkb_keymap_unref(keymap);
- }
- static void
- test_modmap_none(struct xkb_context *context)
- {
- struct xkb_keymap *keymap;
- const struct xkb_key *key;
- xkb_keycode_t keycode;
- keymap = test_compile_file(
- context, XKB_KEYMAP_FORMAT_TEXT_V2, "keymaps/modmap-none.xkb"
- );
- assert(keymap);
- static const struct {
- const char *key_name;
- enum real_mod_mask modmap;
- } tests[] = {
- { "LVL3", NoModifier },
- { "LFSH", NoModifier },
- { "RTSH", NoModifier },
- { "LWIN", Mod4Mask },
- { "RWIN", Mod4Mask },
- { "LCTL", ControlMask },
- { "RCTL", ControlMask },
- { "LALT", Mod1Mask },
- { "RALT", (Mod2Mask | Mod5Mask) },
- { "CAPS", LockMask },
- { "AD01", Mod1Mask },
- { "AD02", NoModifier },
- { "AD03", NoModifier },
- { "AD04", Mod1Mask },
- { "AD05", Mod2Mask },
- { "AD06", Mod3Mask },
- { "AD07", Mod1Mask },
- { "AD08", Mod2Mask },
- { "AD09", Mod3Mask },
- { "AD10", (Mod3Mask | Mod4Mask) },
- { "AD11", (Mod3Mask | Mod4Mask | Mod5Mask) },
- };
- for (size_t t = 0; t < ARRAY_SIZE(tests); t++) {
- fprintf(stderr, "------\n*** %s #%zu: key %s ***\n",
- __func__, t, tests[t].key_name);
- keycode = xkb_keymap_key_by_name(keymap, tests[t].key_name);
- assert(keycode != XKB_KEYCODE_INVALID);
- key = XkbKey(keymap, keycode);
- assert(key);
- assert(key->modmap == (xkb_mod_mask_t)tests[t].modmap);
- }
- xkb_keymap_unref(keymap);
- }
- static void
- test_modmap_mask(struct xkb_context *ctx, bool update_output_files)
- {
- static const struct {
- const char * keymap;
- struct {
- const char * v1;
- const char * v2;
- } expected;
- } tests[] = {
- {
- .keymap =
- "xkb_keymap {\n"
- " xkb_keycodes { <> = 1; };\n"
- " xkb_compat {\n"
- " virtual_modifiers Alt;\n"
- " interpret Shift_L + Any {\n"
- " action = SetMods(modifiers=Shift);\n"
- " };\n"
- " interpret Alt_L + Any {\n"
- " virtualModifier = Alt;\n"
- " action = SetMods(modifiers=Alt);\n"
- " };\n"
- " };\n"
- " xkb_types {\n"
- " type \"TWO_LEVEL\" {\n"
- " modifiers = Shift;\n"
- " map[Shift] = 2;\n"
- " };\n"
- " };\n"
- " xkb_symbols {\n"
- " key <> { [Alt_L, Shift_L] };\n"
- " modifier_map Shift { Shift_L };\n"
- " modifier_map Mod1 { <> };\n"
- " };\n"
- "};",
- .expected = {
- .v1 = GOLDEN_TESTS_OUTPUTS "modmap-key+keysym-v1.xkb",
- .v2 = GOLDEN_TESTS_OUTPUTS "modmap-key+keysym-v2.xkb",
- }
- },
- {
- .keymap =
- "xkb_keymap {\n"
- " xkb_keycodes { <> = 1; };\n"
- " xkb_symbols {\n"
- " modifier_map Shift+Mod1 { <> };\n"
- " };\n"
- "};",
- .expected = {
- .v1 = NULL,
- .v2 = GOLDEN_TESTS_OUTPUTS "modmap-identifier-mask-v2.xkb",
- }
- },
- {
- .keymap =
- "xkb_keymap {\n"
- " xkb_keycodes { <> = 1; };\n"
- " xkb_symbols {\n"
- " modifier_map 0x9 { <> };\n"
- " };\n"
- "};",
- .expected = {
- .v1 = NULL,
- .v2 = GOLDEN_TESTS_OUTPUTS "modmap-identifier-mask-v2.xkb",
- }
- },
- };
- for (uint8_t t = 0; t < (uint8_t)ARRAY_SIZE(tests); t++) {
- fprintf(stderr, "------\n*** %s: #%u ***\n", __func__, t);
- assert(test_compile_output(ctx, XKB_KEYMAP_FORMAT_TEXT_V1,
- XKB_KEYMAP_USE_ORIGINAL_FORMAT,
- compile_buffer, NULL, __func__,
- tests[t].keymap, strlen(tests[t].keymap),
- tests[t].expected.v1, update_output_files));
- assert(test_compile_output(ctx, XKB_KEYMAP_FORMAT_TEXT_V2,
- XKB_KEYMAP_USE_ORIGINAL_FORMAT,
- compile_buffer, NULL, __func__,
- tests[t].keymap, strlen(tests[t].keymap),
- tests[t].expected.v2, update_output_files));
- }
- }
- static void
- test_explicit_virtual_modifiers(struct xkb_context *context)
- {
- static const struct {
- const char* keymap;
- struct mod_props {
- enum mod_type type;
- xkb_mod_mask_t mapping;
- xkb_mod_mask_t mapping_effective;
- } m1;
- struct mod_props m2;
- } tests[] = {
- /* Test virtual modifiers with canonical mappings */
- {
- .keymap =
- "xkb_keymap {\n"
- " xkb_compat {\n"
- /* Vmods map to themselves */
- " virtual_modifiers M1 = 0x100, M2 = 0x200;\n"
- " };\n"
- "};",
- .m1 = {
- .type = MOD_VIRT,
- .mapping = 0x100,
- .mapping_effective = 0x100
- },
- .m2 = {
- .type = MOD_VIRT,
- .mapping = 0x200,
- .mapping_effective = 0x200
- }
- },
- /* Test virtual modifiers overlapping: identical */
- {
- .keymap =
- "xkb_keymap {\n"
- " xkb_compat {\n"
- " virtual_modifiers M1 = 0x100, M2 = 0x100;\n"
- " };\n"
- "};",
- .m1 = {
- .type = MOD_VIRT,
- .mapping = 0x100,
- .mapping_effective = 0x100
- },
- .m2 = {
- .type = MOD_VIRT,
- .mapping = 0x100,
- .mapping_effective = 0x100
- }
- },
- /* Test virtual modifiers overlapping: non identical */
- {
- .keymap =
- "xkb_keymap {\n"
- " xkb_compat {\n"
- " virtual_modifiers M1 = 0x100, M2 = 0x300;\n"
- " };\n"
- "};",
- .m1 = {
- .type = MOD_VIRT,
- .mapping = 0x100,
- .mapping_effective = 0x100
- },
- .m2 = {
- .type = MOD_VIRT,
- .mapping = 0x300,
- .mapping_effective = 0x300
- }
- },
- /* Test virtual modifiers with swapped mappings */
- {
- .keymap =
- "xkb_keymap {\n"
- " xkb_compat {\n"
- /* The mapping of each modifier is the mask of the other */
- " virtual_modifiers M1 = 0x200, M2 = 0x100;\n"
- " };\n"
- "};",
- .m1 = {
- .type = MOD_VIRT,
- .mapping = 0x200,
- .mapping_effective = 0x100 /* different from mapping! */
- },
- .m2 = {
- .type = MOD_VIRT,
- .mapping = 0x100,
- .mapping_effective = 0x200 /* different from mapping! */
- }
- },
- /* Test virtual modifiers mapping to undefined modifiers */
- {
- .keymap =
- "xkb_keymap {\n"
- " xkb_compat {\n"
- " virtual_modifiers M1 = 0x400, M2 = 0x800;\n"
- " };\n"
- "};",
- .m1 = {
- .type = MOD_VIRT,
- .mapping = 0x400,
- .mapping_effective = 0 /* no mod entry */
- },
- .m2 = {
- .type = MOD_VIRT,
- .mapping = 0x800,
- .mapping_effective = 0 /* no mod entry */
- }
- },
- };
- for (unsigned int k = 0; k < ARRAY_SIZE(tests); k++) {
- fprintf(stderr, "------\n*** %s: #%u ***\n", __func__, k);
- struct xkb_keymap *keymap = test_compile_buffer(
- context, XKB_KEYMAP_FORMAT_TEXT_V1,
- tests[k].keymap, strlen(tests[k].keymap)
- );
- assert(keymap);
- const xkb_mod_index_t m1_idx = xkb_keymap_mod_get_index(keymap, "M1");
- const xkb_mod_index_t m2_idx = xkb_keymap_mod_get_index(keymap, "M2");
- assert(m1_idx == 8);
- assert(m2_idx == 9);
- assert(keymap->mods.mods[m1_idx].type == tests[k].m1.type);
- assert(keymap->mods.mods[m2_idx].type == tests[k].m2.type);
- const xkb_mod_mask_t m1 = UINT32_C(1) << m1_idx;
- const xkb_mod_mask_t m2 = UINT32_C(1) << m2_idx;
- const xkb_mod_mask_t m1_mapping = mod_mask_get_effective(keymap, m1);
- const xkb_mod_mask_t m2_mapping = mod_mask_get_effective(keymap, m2);
- assert(m1_mapping == tests[k].m1.mapping);
- assert(m2_mapping == tests[k].m2.mapping);
- /* mod_mask_get_effective is not idempotent */
- assert(mod_mask_get_effective(keymap, m1_mapping) ==
- tests[k].m1.mapping_effective);
- assert(mod_mask_get_effective(keymap, m2_mapping) ==
- tests[k].m2.mapping_effective);
- struct xkb_state *state =
- xkb_state_new_with_mode(keymap, XKB_STATE_MODE_CLIENT);
- assert(state);
- /* Not in the canonical modifier mask nor denotes a *known* virtual
- * modifiers, so it will be discarded. */
- const xkb_mod_mask_t noise = UINT32_C(0x8000);
- assert((keymap->canonical_state_mask & noise) == 0);
- /* Update the state, then check round-trip and mods state */
- const xkb_mod_mask_t set_masks[] = {m1_mapping, m2_mapping};
- for (unsigned int m = 0; m < ARRAY_SIZE(set_masks); m++) {
- const xkb_mod_mask_t expected = set_masks[m];
- xkb_state_update_mask(state, expected | noise, 0, noise, 0, 0, 0);
- const xkb_mod_mask_t got =
- xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE);
- assert_printf(got == expected, /* round-trip */
- "expected %#"PRIx32", got %#"PRIx32"\n",
- expected, got);
- assert(
- xkb_state_mod_index_is_active(state, m1_idx,
- XKB_STATE_MODS_EFFECTIVE) ==
- ((expected & m1_mapping) == m1_mapping)
- );
- assert(
- xkb_state_mod_index_is_active(state, m2_idx,
- XKB_STATE_MODS_EFFECTIVE) ==
- ((expected & m2_mapping) == m2_mapping)
- );
- }
- xkb_state_unref(state);
- xkb_keymap_unref(keymap);
- }
- }
- /*
- * Test the hack documented in the FAQ to get virtual modifiers mapping using
- * `xkb_state_update_mask`/`xkb_state_serialize_mods`.
- *
- * This should work without problem for keymap using only real mods to map
- * virtual modifiers.
- *
- * [NOTE] If the test requires an update, do not forget to update the FAQ as well!
- */
- static void
- test_virtual_modifiers_mapping_hack(struct xkb_context *context)
- {
- struct xkb_keymap *keymap = test_compile_rules(context,
- XKB_KEYMAP_FORMAT_TEXT_V1,
- "evdev", "pc104",
- "us", NULL, NULL);
- assert(keymap);
- struct xkb_state* state =
- xkb_state_new_with_mode(keymap, XKB_STATE_MODE_CLIENT);
- assert(state);
- static const struct {
- const char* name;
- xkb_mod_index_t index;
- xkb_mod_mask_t mapping;
- } mods[] = {
- /* Real modifiers */
- {
- .name = XKB_MOD_NAME_SHIFT,
- .index = XKB_MOD_INDEX_SHIFT,
- .mapping = UINT32_C(1) << XKB_MOD_INDEX_SHIFT
- },
- {
- .name = XKB_MOD_NAME_CAPS,
- .index = XKB_MOD_INDEX_CAPS,
- .mapping = UINT32_C(1) << XKB_MOD_INDEX_CAPS
- },
- {
- .name = XKB_MOD_NAME_CTRL,
- .index = XKB_MOD_INDEX_CTRL,
- .mapping = UINT32_C(1) << XKB_MOD_INDEX_CTRL
- },
- {
- .name = XKB_MOD_NAME_MOD1,
- .index = XKB_MOD_INDEX_MOD1,
- .mapping = UINT32_C(1) << XKB_MOD_INDEX_MOD1
- },
- {
- .name = XKB_MOD_NAME_MOD2,
- .index = XKB_MOD_INDEX_MOD2,
- .mapping = UINT32_C(1) << XKB_MOD_INDEX_MOD2
- },
- {
- .name = XKB_MOD_NAME_MOD3,
- .index = XKB_MOD_INDEX_MOD3,
- .mapping = UINT32_C(1) << XKB_MOD_INDEX_MOD3
- },
- {
- .name = XKB_MOD_NAME_MOD4,
- .index = XKB_MOD_INDEX_MOD4,
- .mapping = UINT32_C(1) << XKB_MOD_INDEX_MOD4
- },
- {
- .name = XKB_MOD_NAME_MOD5,
- .index = XKB_MOD_INDEX_MOD5,
- .mapping = UINT32_C(1) << XKB_MOD_INDEX_MOD5
- },
- /* Virtual modifiers
- * The indices depends on the keymap files */
- {
- .name = XKB_VMOD_NAME_ALT,
- .index = XKB_MOD_INDEX_MOD5 + 2,
- .mapping = Mod1Mask
- },
- {
- .name = XKB_VMOD_NAME_META,
- .index = XKB_MOD_INDEX_MOD5 + 11,
- .mapping = Mod1Mask
- },
- {
- .name = XKB_VMOD_NAME_NUM,
- .index = XKB_MOD_INDEX_MOD5 + 1,
- .mapping = Mod2Mask
- },
- {
- .name = XKB_VMOD_NAME_SUPER,
- .index = XKB_MOD_INDEX_MOD5 + 12,
- .mapping = Mod4Mask
- },
- {
- .name = XKB_VMOD_NAME_HYPER,
- .index = XKB_MOD_INDEX_MOD5 + 13,
- .mapping = Mod4Mask
- },
- {
- .name = XKB_VMOD_NAME_LEVEL3,
- .index = XKB_MOD_INDEX_MOD5 + 3,
- .mapping = Mod5Mask
- },
- {
- .name = XKB_VMOD_NAME_SCROLL,
- .index = XKB_MOD_INDEX_MOD5 + 8,
- .mapping = 0
- },
- {
- .name = XKB_VMOD_NAME_LEVEL5,
- .index = XKB_MOD_INDEX_MOD5 + 9,
- .mapping = 0
- },
- /* Legacy stuff, removed from xkeyboard-config */
- {
- .name = "LAlt",
- .index = XKB_MOD_INDEX_MOD5 + 4,
- .mapping = 0
- },
- {
- .name = "RAlt",
- .index = XKB_MOD_INDEX_MOD5 + 5,
- .mapping = 0
- },
- {
- .name = "LControl",
- .index = XKB_MOD_INDEX_MOD5 + 7,
- .mapping = 0
- },
- {
- .name = "RControl",
- .index = XKB_MOD_INDEX_MOD5 + 6,
- .mapping = 0
- },
- {
- .name = "AltGr",
- .index = XKB_MOD_INDEX_MOD5 + 10,
- .mapping = Mod5Mask
- },
- };
- for (unsigned int k = 0; k < ARRAY_SIZE(mods); k++) {
- const xkb_mod_mask_t index =
- xkb_keymap_mod_get_index(keymap, mods[k].name);
- assert_printf(index == mods[k].index,
- "%s: expected %"PRIu32", got: %"PRIu32"\n",
- mods[k].name, mods[k].index, index);
- const xkb_mod_mask_t mask = UINT32_C(1) << index;
- xkb_state_update_mask(state, mask, 0, 0, 0, 0, 0);
- const xkb_mod_mask_t mapping =
- xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE);
- assert_printf(mapping == mods[k].mapping,
- "%s: expected %#"PRIx32", got: %#"PRIx32"\n",
- mods[k].name, mods[k].mapping, mapping);
- assert(mapping == xkb_keymap_mod_get_mask(keymap, mods[k].name));
- assert(mapping == xkb_keymap_mod_get_mask2(keymap, mods[k].index));
- }
- xkb_state_unref(state);
- xkb_keymap_unref(keymap);
- }
- static void
- test_pure_virtual_modifiers(struct xkb_context *context)
- {
- struct xkb_keymap *keymap;
- /* Test definition of >20 pure virtual modifiers.
- * We overcome the X11 limit of 16 virtual modifiers. */
- struct {
- const char* path;
- enum xkb_keymap_format formats[2];
- } keymaps[] = {
- {
- .path = "keymaps/pure-virtual-mods-explicit.xkb",
- .formats = { XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_FORMAT_TEXT_V2 }
- },
- {
- .path = "keymaps/pure-virtual-mods-implicit.xkb",
- /* Auto canonical vmod available since keymap format v2 */
- .formats = { XKB_KEYMAP_FORMAT_TEXT_V2 }
- }
- };
- for (unsigned int k = 0; k < ARRAY_SIZE(keymaps); k++) {
- for (unsigned int f = 0; f < ARRAY_SIZE(keymaps[k].formats); f++) {
- if (!keymaps[k].formats[f])
- break;
- fprintf(stderr, "------\n*** %s: #%u %s (%d) ***\n",
- __func__, k, keymaps[k].path, keymaps[k].formats[f]);
- keymap = test_compile_file(context, keymaps[k].formats[f],
- keymaps[k].path);
- assert(keymap);
- assert(test_key_seq(keymap,
- KEY_W, BOTH, XKB_KEY_w, NEXT,
- KEY_A, DOWN, XKB_KEY_a, NEXT,
- KEY_W, BOTH, XKB_KEY_a, NEXT,
- KEY_A, UP, XKB_KEY_a, NEXT,
- KEY_B, DOWN, XKB_KEY_b, NEXT,
- KEY_W, BOTH, XKB_KEY_b, NEXT,
- KEY_B, UP, XKB_KEY_b, NEXT,
- KEY_C, DOWN, XKB_KEY_c, NEXT,
- KEY_W, BOTH, XKB_KEY_c, NEXT,
- KEY_C, UP, XKB_KEY_c, NEXT,
- KEY_D, DOWN, XKB_KEY_d, NEXT,
- KEY_W, BOTH, XKB_KEY_d, NEXT,
- KEY_D, UP, XKB_KEY_d, NEXT,
- KEY_E, DOWN, XKB_KEY_e, NEXT,
- KEY_W, BOTH, XKB_KEY_e, NEXT,
- KEY_E, UP, XKB_KEY_e, NEXT,
- KEY_F, DOWN, XKB_KEY_f, NEXT,
- KEY_W, BOTH, XKB_KEY_f, NEXT,
- KEY_F, UP, XKB_KEY_f, NEXT,
- KEY_G, DOWN, XKB_KEY_g, NEXT,
- KEY_W, BOTH, XKB_KEY_g, NEXT,
- KEY_G, UP, XKB_KEY_g, NEXT,
- KEY_H, DOWN, XKB_KEY_h, NEXT,
- KEY_W, BOTH, XKB_KEY_h, NEXT,
- KEY_H, UP, XKB_KEY_h, NEXT,
- KEY_I, DOWN, XKB_KEY_i, NEXT,
- KEY_W, BOTH, XKB_KEY_i, NEXT,
- KEY_I, UP, XKB_KEY_i, NEXT,
- KEY_J, DOWN, XKB_KEY_j, NEXT,
- KEY_W, BOTH, XKB_KEY_j, NEXT,
- KEY_J, UP, XKB_KEY_j, NEXT,
- KEY_K, DOWN, XKB_KEY_k, NEXT,
- KEY_W, BOTH, XKB_KEY_k, NEXT,
- KEY_K, UP, XKB_KEY_k, NEXT,
- KEY_L, DOWN, XKB_KEY_l, NEXT,
- KEY_W, BOTH, XKB_KEY_l, NEXT,
- KEY_L, UP, XKB_KEY_l, NEXT,
- KEY_M, DOWN, XKB_KEY_m, NEXT,
- KEY_W, BOTH, XKB_KEY_m, NEXT,
- KEY_M, UP, XKB_KEY_m, NEXT,
- KEY_N, DOWN, XKB_KEY_n, NEXT,
- KEY_W, BOTH, XKB_KEY_n, NEXT,
- KEY_N, UP, XKB_KEY_n, NEXT,
- KEY_O, DOWN, XKB_KEY_o, NEXT,
- KEY_W, BOTH, XKB_KEY_o, NEXT,
- KEY_O, UP, XKB_KEY_o, NEXT,
- KEY_P, DOWN, XKB_KEY_p, NEXT,
- KEY_W, BOTH, XKB_KEY_p, NEXT,
- KEY_P, UP, XKB_KEY_p, NEXT,
- KEY_Q, DOWN, XKB_KEY_q, NEXT,
- KEY_W, BOTH, XKB_KEY_q, NEXT,
- KEY_Q, UP, XKB_KEY_q, NEXT,
- KEY_R, DOWN, XKB_KEY_r, NEXT,
- KEY_W, BOTH, XKB_KEY_r, NEXT,
- KEY_R, UP, XKB_KEY_r, NEXT,
- KEY_S, DOWN, XKB_KEY_s, NEXT,
- KEY_W, BOTH, XKB_KEY_s, NEXT,
- KEY_S, UP, XKB_KEY_s, NEXT,
- KEY_T, DOWN, XKB_KEY_t, NEXT,
- KEY_W, BOTH, XKB_KEY_t, NEXT,
- KEY_T, UP, XKB_KEY_t, NEXT,
- KEY_U, DOWN, XKB_KEY_u, NEXT,
- KEY_W, BOTH, XKB_KEY_u, NEXT,
- KEY_U, UP, XKB_KEY_u, NEXT,
- KEY_V, DOWN, XKB_KEY_v, NEXT,
- KEY_W, BOTH, XKB_KEY_v, NEXT,
- KEY_LEFTSHIFT, DOWN, XKB_KEY_Shift_L, NEXT,
- KEY_W, BOTH, XKB_KEY_V, NEXT,
- KEY_LEFTSHIFT, UP, XKB_KEY_Shift_L, NEXT,
- KEY_V, UP, XKB_KEY_v, NEXT,
- KEY_A, DOWN, XKB_KEY_a, NEXT,
- KEY_S, DOWN, XKB_KEY_s, NEXT,
- KEY_W, BOTH, XKB_KEY_1, NEXT,
- KEY_RIGHTALT, DOWN, XKB_KEY_ISO_Level3_Shift, NEXT,
- KEY_W, BOTH, XKB_KEY_4, NEXT,
- KEY_S, UP, XKB_KEY_s, NEXT,
- KEY_W, BOTH, XKB_KEY_3, NEXT,
- KEY_RIGHTALT, UP, XKB_KEY_ISO_Level3_Shift, NEXT,
- KEY_Q, DOWN, XKB_KEY_q, NEXT,
- KEY_W, BOTH, XKB_KEY_2, NEXT,
- KEY_Q, UP, XKB_KEY_q, NEXT,
- KEY_B, DOWN, XKB_KEY_b, NEXT,
- KEY_C, DOWN, XKB_KEY_c, NEXT,
- KEY_W, BOTH, XKB_KEY_5, NEXT,
- KEY_C, UP, XKB_KEY_c, NEXT,
- KEY_B, UP, XKB_KEY_b, NEXT,
- KEY_A, UP, XKB_KEY_a, NEXT,
- KEY_Y, BOTH, XKB_KEY_y, FINISH));
- xkb_keymap_unref(keymap);
- }}
- /* Test invalid interpret using a virtual modifier */
- const char keymap_str[] =
- "xkb_keymap {"
- " xkb_keycodes { include \"evdev\" };"
- " xkb_types { include \"complete\" };"
- " xkb_compat { include \"complete+basic(invalid-pure-virtual-modifiers)\" };"
- " xkb_symbols { include \"pc(pc105-pure-virtual-modifiers)\" };"
- "};";
- keymap = test_compile_string(context, XKB_KEYMAP_FORMAT_TEXT_V1, keymap_str);
- assert(!keymap);
- }
- /* Test FAQ snippet */
- // NOLINTBEGIN(readability-duplicate-include)
- //! [xkb_keymap_mod_get_codes]
- #include <xkbcommon/xkbcommon.h>
- /**
- * Get the keycodes associated with a modifier by index.
- *
- * @param[in] keymap The keymap
- * @param[in] idx The index of the modifier
- * @param[out] codes_out A buffer in which the codes should be stored
- * @param[out] codes_size The size of the codes_out buffer
- *
- * @returns the number of key codes in the keysyms_out array, or a negative
- * in case of error.
- */
- static ssize_t
- xkb_keymap_mod_get_codes(struct xkb_keymap *keymap, xkb_mod_index_t mod,
- xkb_keycode_t *codes_out, size_t codes_size)
- {
- if (mod >= xkb_keymap_num_mods(keymap))
- return -1;
- ssize_t idx = 0;
- for (xkb_keycode_t k = xkb_keymap_min_keycode(keymap);
- k <= xkb_keymap_max_keycode(keymap) && idx >= 0; k++) {
- /*
- * We only test the first level of the first group.
- *
- * Since there is currently no way to reset the state, use a new one to
- * avoid side effects (latches, etc.)
- */
- struct xkb_state * const state =
- xkb_state_new_with_mode(keymap, XKB_STATE_MODE_SERVER);
- assert(state);
- static const enum xkb_key_direction directions[] = {
- XKB_KEY_DOWN,
- XKB_KEY_UP
- };
- for (size_t d = 0; d < ARRAY_SIZE(directions); d++) {
- if (xkb_state_update_key(state, k, directions[d]) &&
- xkb_state_mod_index_is_active(state, mod,
- XKB_STATE_MODS_EFFECTIVE)) {
- if ((size_t) idx < codes_size) {
- assert(idx < (ssize_t) (SIZE_MAX / 2));
- codes_out[idx++] = k;
- } else {
- idx = -2;
- }
- break;
- }
- }
- xkb_state_unref(state);
- }
- return idx;
- }
- //! [xkb_keymap_mod_get_codes]
- // NOLINTEND(readability-duplicate-include)
- static void
- test_get_modifier_keycodes(struct xkb_context *context)
- {
- struct xkb_keymap *keymap = test_compile_rules(context,
- XKB_KEYMAP_FORMAT_TEXT_V1,
- "evdev", "pc104",
- "cz", NULL, NULL);
- assert(keymap);
- #define MAX_KEYCODES_COUNT 10
- #define KEY_LVL3 (92 - EVDEV_OFFSET)
- const struct {
- const char *mod;
- xkb_keycode_t keycodes[MAX_KEYCODES_COUNT];
- } mods[] = {
- { .mod = XKB_MOD_NAME_SHIFT, .keycodes = { KEY_LEFTSHIFT, KEY_RIGHTSHIFT, 0 } },
- { .mod = XKB_MOD_NAME_CAPS, .keycodes = { KEY_CAPSLOCK, 0 } },
- { .mod = XKB_MOD_NAME_CTRL, .keycodes = { KEY_LEFTCTRL, KEY_RIGHTCTRL, 0 } },
- { .mod = XKB_MOD_NAME_MOD1, .keycodes = { KEY_LEFTALT, 0 } },
- { .mod = XKB_MOD_NAME_MOD2, .keycodes = { KEY_NUMLOCK, 0 } },
- { .mod = XKB_MOD_NAME_MOD3, .keycodes = { 0 } },
- { .mod = XKB_MOD_NAME_MOD4, .keycodes = { KEY_LEFTMETA, KEY_RIGHTMETA, 0 } },
- { .mod = XKB_MOD_NAME_MOD5, .keycodes = { KEY_LVL3, KEY_RIGHTALT, 0 } },
- { .mod = XKB_VMOD_NAME_ALT, .keycodes = { KEY_LEFTALT, 0 } },
- { .mod = XKB_VMOD_NAME_META, .keycodes = { KEY_LEFTALT, 0 } },
- { .mod = XKB_VMOD_NAME_SUPER, .keycodes = { KEY_LEFTMETA, KEY_RIGHTMETA, 0 } },
- { .mod = XKB_VMOD_NAME_HYPER, .keycodes = { KEY_LEFTMETA, KEY_RIGHTMETA, 0 } },
- { .mod = XKB_VMOD_NAME_NUM, .keycodes = { KEY_NUMLOCK, 0 } },
- { .mod = XKB_VMOD_NAME_LEVEL3, .keycodes = { KEY_LVL3, KEY_RIGHTALT, 0 } },
- { .mod = XKB_VMOD_NAME_LEVEL5, .keycodes = { 0 } },
- };
- xkb_keycode_t got[MAX_KEYCODES_COUNT] = {0};
- for (size_t m = 0; m < ARRAY_SIZE(mods); m++) {
- const xkb_mod_index_t mod = xkb_keymap_mod_get_index(keymap, mods[m].mod);
- assert(mod != XKB_MOD_INVALID);
- const ssize_t count =
- xkb_keymap_mod_get_codes(keymap, mod, got, ARRAY_SIZE(got));
- assert(count >= 0);
- const xkb_keycode_t * const expected = mods[m].keycodes;
- for (size_t k = 0; k < ARRAY_SIZE(got); k++) {
- if (expected[k] == 0) {
- assert_printf(k == (size_t) count,
- "Mod %s: expected %zu, got %zd\n",
- mods[m].mod, k, count);
- break;
- }
- assert_printf(k < (size_t) count,
- "Mod %s: Missing keycode 0x%"PRIu32"\n",
- mods[m].mod, expected[k]);
- assert_printf(got[k] == expected[k] + EVDEV_OFFSET,
- "Mod %s: Expected keycode %"PRIu32" but got: %"PRIu32"\n",
- mods[m].mod, expected[k] + EVDEV_OFFSET, got[k]);
- }
- }
- xkb_keymap_unref(keymap);
- }
- #undef MAX_KEYCODES_COUNT
- int
- main(int argc, char *argv[])
- {
- test_init();
- bool update_output_files = false;
- int arg_index = 0;
- while (++arg_index < argc) {
- if (streq(argv[arg_index], "update")) {
- /* Update files with *obtained* results */
- update_output_files = true;
- }
- }
- struct xkb_context *context = test_get_context(CONTEXT_NO_FLAG);
- assert(context);
- test_modmap_none(context);
- test_modifiers_names(context);
- test_modmap_mask(context, update_output_files);
- test_explicit_virtual_modifiers(context);
- test_virtual_modifiers_mapping_hack(context);
- test_pure_virtual_modifiers(context);
- test_get_modifier_keycodes(context);
- xkb_context_unref(context);
- return 0;
- }
|