From 0421feb6dbda3a86aba68cb48e2932190b966155 Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Fri, 29 Nov 2024 10:03:21 +0100 Subject: [PATCH] Add tests for pure virtual modifiers --- test/data/compat/basic | 50 +++++ test/data/keymaps/pure-virtual-mods.xkb | 278 ++++++++++++++++++++++++ test/data/rules/evdev-pure-virtual-mods | 24 ++ test/data/symbols/pc | 54 +++++ test/keyseq.c | 45 ++-- test/modifiers.c | 115 ++++++++++ test/state.c | 264 ++++++++++++++-------- 7 files changed, 722 insertions(+), 108 deletions(-) create mode 100644 test/data/keymaps/pure-virtual-mods.xkb create mode 100644 test/data/rules/evdev-pure-virtual-mods diff --git a/test/data/compat/basic b/test/data/compat/basic index 745cbbaed..8e8e5f394 100644 --- a/test/data/compat/basic +++ b/test/data/compat/basic @@ -47,3 +47,53 @@ default xkb_compatibility "basic" { modifiers= Shift; }; }; + +xkb_compatibility "pure-virtual-modifiers" { + + virtual_modifiers NumLock,AltGr,Alt; + + interpret.repeat= False; + setMods.clearLocks= True; + latchMods.clearLocks= True; + latchMods.latchToLock= True; + + interpret Shift_Lock { + action= LockMods(modifiers=Shift); + }; + + interpret Num_Lock { + virtualModifier= NumLock; + action= LockMods(modifiers=NumLock); + }; + + interpret Shift_L { + action= SetMods(modifiers=Shift); + }; + + interpret Shift_R { + action= SetMods(modifiers=Shift); + }; + + interpret Control_L { + action= SetMods(modifiers=Control); + }; + + interpret Control_R { + action= SetMods(modifiers=Control); + }; + + interpret Alt_L { + action= SetMods(modifiers=Alt); + }; + + interpret Alt_R { + action= SetMods(modifiers=Alt); + }; +}; + +xkb_compatibility "invalid-pure-virtual-modifiers" { + virtual_modifiers Alt; + interpret Alt_R + Alt { + action= SetMods(modifiers=Alt); + }; +}; diff --git a/test/data/keymaps/pure-virtual-mods.xkb b/test/data/keymaps/pure-virtual-mods.xkb new file mode 100644 index 000000000..13459e1b6 --- /dev/null +++ b/test/data/keymaps/pure-virtual-mods.xkb @@ -0,0 +1,278 @@ +xkb_keymap { +xkb_keycodes "test" { + minimum = 8; + maximum = 255; + + = 49; + = 10; + = 11; + = 12; + = 13; + = 14; + = 15; + = 16; + = 17; + = 18; + = 19; + = 20; + = 21; + = 22; + + = 23; + = 24; + = 25; + = 26; + = 27; + = 28; + = 29; + = 30; + = 31; + = 32; + = 33; + = 34; + = 35; + = 51; + = 36; + + = 66; + = 38; + = 39; + = 40; + = 41; + = 42; + = 43; + = 44; + = 45; + = 46; + = 47; + = 48; + alias = ; + + = 50; + = 94; + = 52; + = 53; + = 54; + = 55; + = 56; + = 57; + = 58; + = 59; + = 60; + = 61; + = 62; + + = 92; + = 108; +}; + +xkb_types "complete" { + // Define >20 virtual modifiers. This lead to overcome the X11 limit of + // 16 virtual modifiers. + virtual_modifiers LevelThree, ModA, ModB, ModC, ModD, ModE, ModF, + ModG, ModH, ModI, ModJ, ModK, ModL, ModM, ModN, + ModO, ModP, ModQ, ModR, ModS, ModT, ModU, ModV; + + type "ONE_LEVEL" { + modifiers= none; + level_name[Level1]= "Any"; + }; + type "TWO_LEVEL" { + modifiers= Shift; + map[Shift]= 2; + level_name[1]= "Base"; + level_name[2]= "Shift"; + }; + type "TEST" { + modifiers= Shift + LevelThree + + ModA + ModB + ModC + ModD + ModE + ModF + ModG + + ModH + ModI + ModJ + ModK + ModL + ModM + ModN + + ModO + ModP + ModQ + ModR + ModS + ModT + ModU + ModV; + map[ModA]= 2; + map[ModB]= 3; + map[ModC]= 4; + map[ModD]= 5; + map[ModE]= 6; + map[ModF]= 7; + map[ModG]= 8; + map[ModH]= 9; + map[ModI]= 10; + map[ModJ]= 11; + map[ModK]= 12; + map[ModL]= 13; + map[ModM]= 14; + map[ModN]= 15; + map[ModO]= 16; + map[ModP]= 17; + map[ModQ]= 18; + map[ModR]= 19; + map[ModS]= 20; + map[ModT]= 21; + map[ModU]= 22; + map[ModV]= 23; + map[ModV+Shift]= 24; + map[ModA+ModS]= 25; + map[ModA+ModQ]= 26; + map[LevelThree+ModA]= 27; + map[LevelThree+ModA+ModS]= 28; + map[ModA+ModB+ModC]= 29; + + level_name[1]= "1"; + level_name[2]= "2"; + level_name[3]= "3"; + level_name[4]= "4"; + level_name[5]= "5"; + level_name[6]= "6"; + level_name[7]= "7"; + level_name[8]= "8"; + level_name[9]= "9"; + level_name[10]= "10"; + level_name[11]= "11"; + level_name[12]= "12"; + level_name[13]= "13"; + level_name[14]= "14"; + level_name[15]= "15"; + level_name[16]= "16"; + level_name[17]= "17"; + level_name[18]= "18"; + level_name[19]= "19"; + level_name[20]= "20"; + level_name[21]= "21"; + level_name[22]= "22"; + level_name[23]= "23"; + level_name[24]= "24"; + level_name[25]= "25"; + level_name[26]= "26"; + level_name[27]= "27"; + level_name[28]= "28"; + level_name[29]= "29"; + }; +}; +xkb_compatibility "complete" { + virtual_modifiers LevelThree, ModA, ModB, ModC, ModD; + + interpret.useModMapMods= AnyLevel; + interpret.repeat= False; + interpret.locking= False; + + interpret Any+AnyOf(all) { + action= SetMods(modifiers=modMapMods,clearLocks); + }; + + interpret ISO_Level3_Shift+AnyOf(all) { + virtualModifier= LevelThree; + useModMapMods=level1; + action= SetMods(modifiers=LevelThree,clearLocks); + }; + interpret a { + action= SetMods(modifiers=ModA,clearLocks); + }; + interpret b { + action= SetMods(modifiers=ModB,clearLocks); + }; + interpret c { + action= SetMods(modifiers=ModC,clearLocks); + }; + interpret d { + action= SetMods(modifiers=ModD,clearLocks); + }; + interpret e { + action= SetMods(modifiers=ModE,clearLocks); + }; + interpret f { + action= SetMods(modifiers=ModF,clearLocks); + }; + interpret g { + action= SetMods(modifiers=ModG,clearLocks); + }; + interpret h { + action= SetMods(modifiers=ModH,clearLocks); + }; + interpret i { + action= SetMods(modifiers=ModI,clearLocks); + }; + interpret j { + action= SetMods(modifiers=ModJ,clearLocks); + }; + interpret k { + action= SetMods(modifiers=ModK,clearLocks); + }; + interpret l { + action= SetMods(modifiers=ModL,clearLocks); + }; + interpret m { + action= SetMods(modifiers=ModM,clearLocks); + }; + interpret n { + action= SetMods(modifiers=ModN,clearLocks); + }; + interpret o { + action= SetMods(modifiers=ModO,clearLocks); + }; + interpret p { + action= SetMods(modifiers=ModP,clearLocks); + }; + interpret q { + action= SetMods(modifiers=ModQ,clearLocks); + }; + interpret r { + action= SetMods(modifiers=ModR,clearLocks); + }; + interpret s { + action= SetMods(modifiers=ModS,clearLocks); + }; + interpret t { + action= SetMods(modifiers=ModT,clearLocks); + }; + interpret u { + action= SetMods(modifiers=ModU,clearLocks); + }; + interpret v { + action= SetMods(modifiers=ModV,clearLocks); + }; +}; +xkb_symbols { + name[group1]="Test"; + + key { [Shift_L] }; + key { [ISO_Level3_Shift] }; + key { [ISO_Level3_Shift] }; + modmap Shift { }; + modmap Mod5 { , }; + + key {[ q, Q ]}; + key {[ w, W ]}; + key {[ e, E ]}; + key {[ r, R ]}; + key {[ t, T ]}; + key {[ y, Y ]}; + key {[ u, U ]}; + key {[ i, I ]}; + key {[ o, O ]}; + key {[ p, P ]}; + + key {[ a, A ]}; + key {[ s, S ]}; + key {[ d, D ]}; + key {[ f, F ]}; + key {[ g, G ]}; + key {[ h, H ]}; + key {[ j, J ]}; + key {[ k, K ]}; + key {[ l, L ]}; + + key {[ z, Z ]}; + key {[ x, X ]}; + key {[ c, C ]}; + key {[ v, V ]}; + key {[ b, B ]}; + key {[ n, N ]}; + key {[ m, M ]}; + + key.type[1] = "TEST"; + key { + [ w, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v + , V, 1, 2, 3, 4, 5 ] + }; +}; +}; diff --git a/test/data/rules/evdev-pure-virtual-mods b/test/data/rules/evdev-pure-virtual-mods new file mode 100644 index 000000000..3b2f8ea53 --- /dev/null +++ b/test/data/rules/evdev-pure-virtual-mods @@ -0,0 +1,24 @@ +// Special rules to test pure virtual modifiers. + +// Needed for a test involving `applealu_ansi`. +! $macvendorlayouts = ch de dk fi fr gb is it latam nl no pt se us +! $applealu = applealu_ansi applealu_iso applealu_jis + +! model layout = symbols + $applealu $macvendorlayouts = macintosh_vndr/apple(alukbd)+macintosh_vndr/%l%(v) + * * = pc(pc105-pure-virtual-modifiers)+%l%(v) + +! model layout[1] = symbols + * * = pc(pc105-pure-virtual-modifiers)+%l[1]%(v[1]) + +! model layout = compat + * * = complete+basic(pure-virtual-modifiers) + +! model layout[1] = compat + * * = complete+basic(pure-virtual-modifiers) + +// The rules in the current file will *not* be overridden by the +// following include, because the keymap sections do not start with +// an explicit merge operator. E.g. `[pc(x), pc]` is merged as `pc(x)`, +// while `[pc, +us]` is merged as `pc+us`. +! include evdev diff --git a/test/data/symbols/pc b/test/data/symbols/pc index dbe08bbf7..5f2b4b8cd 100644 --- a/test/data/symbols/pc +++ b/test/data/symbols/pc @@ -62,6 +62,60 @@ xkb_symbols "pc105" { key { [ XF86KbdBrightnessUp ] }; }; +xkb_symbols "pc105-pure-virtual-modifiers" { + + key { [ Escape ] }; + + // The extra key on many European keyboards: + key { [ less, greater, bar, brokenbar ] }; + + // The following keys are common to all layouts. + key { [ backslash, bar ] }; + key { [ space ] }; + + include "srvr_ctrl(fkey2vt)" + include "pc(editing)" + include "keypad(x11)" + + key { [ BackSpace, BackSpace ] }; + + key { [ Tab, ISO_Left_Tab ] }; + key { [ Return ] }; + + key { [ Caps_Lock ] }; + key { [ Num_Lock ] }; + + key { [ Shift_L ] }; + key { [ Control_L ] }; + key { [ Super_L ] }; + + key { [ Shift_R ] }; + key { [ Control_R ] }; + key { [ Super_R ] }; + key { [ Menu ] }; + + // Fake keys for virtual<->real modifiers mapping: + key { [ ISO_Level3_Shift ] }; + key { [ Mode_switch ] }; + + key { [ NoSymbol, Alt_L ] }; + key { [ Alt_L, Meta_L ] }; + key { type[Group1] = "TWO_LEVEL", + symbols[Group1] = [ Alt_R, Meta_R ] }; + + key { [ NoSymbol, Meta_L ] }; + + key { [ NoSymbol, Super_L ] }; + + key { [ NoSymbol, Hyper_L ] }; + // End of modifier mappings. + + key { [ XF86Display ] }; + key { [ XF86KbdLightOnOff ] }; + key { [ XF86KbdBrightnessDown ] }; + key { [ XF86KbdBrightnessUp ] }; +}; + hidden partial alphanumeric_keys xkb_symbols "editing" { key { diff --git a/test/keyseq.c b/test/keyseq.c index 7fdc06f37..8fd517d85 100644 --- a/test/keyseq.c +++ b/test/keyseq.c @@ -365,20 +365,12 @@ test_explicit_actions(struct xkb_context *ctx) } } -int -main(void) +static void +test_keymaps(struct xkb_context *ctx, const char* rules) { - test_init(); - - struct xkb_context *ctx = test_get_context(CONTEXT_NO_FLAG); struct xkb_keymap *keymap; - assert(ctx); - - test_group_latch(ctx); - test_explicit_actions(ctx); - - keymap = test_compile_rules(ctx, "evdev", "evdev", + keymap = test_compile_rules(ctx, rules, "", "us,il,ru,de", ",,phonetic,neo", "grp:alt_shift_toggle,grp:menu_toggle"); assert(keymap); @@ -656,7 +648,7 @@ main(void) KEY_V, BOTH, XKB_KEY_p, FINISH)); xkb_keymap_unref(keymap); - keymap = test_compile_rules(ctx, "evdev", "", "de", "neo", ""); + keymap = test_compile_rules(ctx, rules, "", "de", "neo", ""); assert(keymap); assert(test_key_seq(keymap, /* Level 5. */ @@ -708,7 +700,7 @@ main(void) xkb_keymap_unref(keymap); - keymap = test_compile_rules(ctx, "evdev", "", "us,il,ru", "", + keymap = test_compile_rules(ctx, rules, "", "us,il,ru", "", "grp:alt_shift_toggle_bidir,grp:menu_toggle"); assert(keymap); @@ -747,7 +739,7 @@ main(void) KEY_H, BOTH, XKB_KEY_h, FINISH)); xkb_keymap_unref(keymap); - keymap = test_compile_rules(ctx, "evdev", "", "us,il,ru", "", + keymap = test_compile_rules(ctx, rules, "", "us,il,ru", "", "grp:switch,grp:lswitch,grp:menu_toggle"); assert(keymap); @@ -790,7 +782,7 @@ main(void) KEY_H, BOTH, XKB_KEY_h, FINISH)); xkb_keymap_unref(keymap); - keymap = test_compile_rules(ctx, "evdev", "", "us", "euro", ""); + keymap = test_compile_rules(ctx, rules, "", "us", "euro", ""); assert(keymap); assert(test_key_seq(keymap, @@ -810,7 +802,7 @@ main(void) KEY_Z, BOTH, XKB_KEY_y, FINISH)); xkb_keymap_unref(keymap); - keymap = test_compile_rules(ctx, "evdev", "applealu_ansi", "us", "", + keymap = test_compile_rules(ctx, rules, "applealu_ansi", "us", "", "terminate:ctrl_alt_bksp"); assert(keymap); @@ -830,6 +822,25 @@ main(void) KEY_A, BOTH, XKB_KEY_a, FINISH)); xkb_keymap_unref(keymap); +} + +int +main(void) +{ + test_init(); + + struct xkb_context *ctx = test_get_context(CONTEXT_NO_FLAG); + assert(ctx); + + /* Usual rules */ + test_keymaps(ctx, "evdev"); + /* Special rules to make no use of modmaps */ + test_keymaps(ctx, "evdev-pure-virtual-mods"); + + test_group_latch(ctx); + + test_explicit_actions(ctx); + xkb_context_unref(ctx); - return 0; + return EXIT_SUCCESS; } diff --git a/test/modifiers.c b/test/modifiers.c index d952d4e41..5b3b62962 100644 --- a/test/modifiers.c +++ b/test/modifiers.c @@ -27,6 +27,7 @@ #include #include +#include "evdev-scancodes.h" #include "test.h" #include "keymap.h" @@ -224,6 +225,119 @@ test_modmap_none(struct xkb_context *context) 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 superate the X11 limit of 16 virtual modifiers. */ + keymap = test_compile_file(context, "keymaps/pure-virtual-mods.xkb"); + 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, keymap_str); + assert(!keymap); +} + int main(void) { @@ -234,6 +348,7 @@ main(void) test_modmap_none(context); test_modifiers_names(context); + test_pure_virtual_modifiers(context); xkb_context_unref(context); diff --git a/test/state.c b/test/state.c index 7fd6d4790..7feee904e 100644 --- a/test/state.c +++ b/test/state.c @@ -30,6 +30,7 @@ #include #include "evdev-scancodes.h" +#include "keymap.h" #include "test.h" /* Offset between evdev keycodes (where KEY_ESCAPE is 1), and the evdev XKB @@ -111,13 +112,30 @@ print_state(struct xkb_state *state) } } +static int +is_active(int x) +{ + return x > 0; +} + +static int +is_not_active(int x) +{ + return x == 0; +} + +typedef int (* is_active_t)(int) ; + +#define CANONICAL_MOD(is_pure, vmod, real) (is_pure ? vmod : real) + static void -test_update_key(struct xkb_keymap *keymap) +test_update_key(struct xkb_keymap *keymap, bool pure_vmods) { struct xkb_state *state = xkb_state_new(keymap); const xkb_keysym_t *syms; xkb_keysym_t one_sym; int num_syms; + is_active_t check_active = pure_vmods ? is_not_active : is_active; assert(state); @@ -139,23 +157,34 @@ test_update_key(struct xkb_keymap *keymap) print_state(state); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_DEPRESSED) > 0); - assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_MOD1, - XKB_STATE_MODS_DEPRESSED) > 0); assert(xkb_state_mod_name_is_active(state, XKB_VMOD_NAME_ALT, XKB_STATE_MODS_DEPRESSED) > 0); - assert(xkb_state_mod_name_is_active(state, XKB_VMOD_NAME_META, - XKB_STATE_MODS_DEPRESSED) > 0); - assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, - XKB_STATE_MATCH_ALL, - XKB_MOD_NAME_CTRL, - XKB_MOD_NAME_MOD1, - XKB_VMOD_NAME_ALT, - XKB_VMOD_NAME_META, - NULL) > 0); - assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_DEPRESSED, - XKB_STATE_MATCH_ALL, - ctrl, mod1, alt, meta, - XKB_MOD_INVALID) > 0); + assert(check_active(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_MOD1, + XKB_STATE_MODS_DEPRESSED))); + assert(check_active(xkb_state_mod_name_is_active(state, XKB_VMOD_NAME_META, + XKB_STATE_MODS_DEPRESSED))); + if (pure_vmods) { + assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, + XKB_STATE_MATCH_ALL, + XKB_MOD_NAME_CTRL, + XKB_VMOD_NAME_ALT, + NULL) > 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_DEPRESSED, + XKB_STATE_MATCH_ALL, ctrl, alt, + XKB_MOD_INVALID) > 0); + } else { + assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, + XKB_STATE_MATCH_ALL, + XKB_MOD_NAME_CTRL, + XKB_MOD_NAME_MOD1, + XKB_VMOD_NAME_ALT, + XKB_VMOD_NAME_META, + NULL) > 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_DEPRESSED, + XKB_STATE_MATCH_ALL, + ctrl, mod1, alt, meta, + XKB_MOD_INVALID) > 0); + } assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, XKB_STATE_MATCH_ALL, XKB_MOD_NAME_MOD1, @@ -168,36 +197,36 @@ test_update_key(struct xkb_keymap *keymap) XKB_STATE_MATCH_ALL, XKB_VMOD_NAME_META, NULL) == 0); - assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, - XKB_STATE_MATCH_ALL | - XKB_STATE_MATCH_NON_EXCLUSIVE, - XKB_MOD_NAME_MOD1, - NULL) > 0); assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, XKB_STATE_MATCH_ALL | XKB_STATE_MATCH_NON_EXCLUSIVE, XKB_VMOD_NAME_ALT, NULL) > 0); - assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, - XKB_STATE_MATCH_ALL | - XKB_STATE_MATCH_NON_EXCLUSIVE, - XKB_VMOD_NAME_META, - NULL) > 0); - assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, - (XKB_STATE_MATCH_ANY | - XKB_STATE_MATCH_NON_EXCLUSIVE), - XKB_MOD_NAME_MOD1, - NULL) > 0); assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, (XKB_STATE_MATCH_ANY | XKB_STATE_MATCH_NON_EXCLUSIVE), XKB_VMOD_NAME_ALT, NULL) > 0); - assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, - (XKB_STATE_MATCH_ANY | - XKB_STATE_MATCH_NON_EXCLUSIVE), - XKB_VMOD_NAME_META, - NULL) > 0); + assert(check_active(xkb_state_mod_names_are_active( + state, XKB_STATE_MODS_DEPRESSED, + XKB_STATE_MATCH_ALL | XKB_STATE_MATCH_NON_EXCLUSIVE, + XKB_MOD_NAME_MOD1, + NULL))); + assert(check_active(xkb_state_mod_names_are_active( + state, XKB_STATE_MODS_DEPRESSED, + XKB_STATE_MATCH_ALL | XKB_STATE_MATCH_NON_EXCLUSIVE, + XKB_VMOD_NAME_META, + NULL))); + assert(check_active(xkb_state_mod_names_are_active( + state, XKB_STATE_MODS_DEPRESSED, + (XKB_STATE_MATCH_ANY | XKB_STATE_MATCH_NON_EXCLUSIVE), + XKB_MOD_NAME_MOD1, + NULL))); + assert(check_active(xkb_state_mod_names_are_active( + state, XKB_STATE_MODS_DEPRESSED, + (XKB_STATE_MATCH_ANY | XKB_STATE_MATCH_NON_EXCLUSIVE), + XKB_VMOD_NAME_META, + NULL))); /* RAlt down */ xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_UP); @@ -205,12 +234,12 @@ test_update_key(struct xkb_keymap *keymap) print_state(state); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE) == 0); - assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_MOD1, - XKB_STATE_MODS_DEPRESSED) > 0); assert(xkb_state_mod_name_is_active(state, XKB_VMOD_NAME_ALT, XKB_STATE_MODS_DEPRESSED) > 0); - assert(xkb_state_mod_name_is_active(state, XKB_VMOD_NAME_META, - XKB_STATE_MODS_DEPRESSED) > 0); + assert(check_active(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_MOD1, + XKB_STATE_MODS_DEPRESSED))); + assert(check_active(xkb_state_mod_name_is_active(state, XKB_VMOD_NAME_META, + XKB_STATE_MODS_DEPRESSED))); assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, XKB_STATE_MATCH_ANY, XKB_MOD_NAME_CTRL, @@ -257,10 +286,10 @@ test_update_key(struct xkb_keymap *keymap) print_state(state); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_LOCKED) > 0); - assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_MOD2, - XKB_STATE_MODS_LOCKED) > 0); assert(xkb_state_mod_name_is_active(state, XKB_VMOD_NAME_NUM, XKB_STATE_MODS_LOCKED) > 0); + assert(check_active(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_MOD2, + XKB_STATE_MODS_LOCKED))); num_syms = xkb_state_key_get_syms(state, KEY_KP1 + EVDEV_OFFSET, &syms); assert(num_syms == 1 && syms[0] == XKB_KEY_KP_1); assert(xkb_state_led_name_is_active(state, XKB_LED_NAME_NUM) > 0); @@ -311,7 +340,7 @@ struct test_active_mods_entry { }; static void -test_serialisation(struct xkb_keymap *keymap) +test_serialisation(struct xkb_keymap *keymap, bool pure_vmods) { struct xkb_state *state = xkb_state_new(keymap); xkb_mod_mask_t base_mods; @@ -383,7 +412,7 @@ test_serialisation(struct xkb_keymap *keymap) assert(xkb_state_mod_index_is_active(state, ctrlIdx, XKB_STATE_MODS_DEPRESSED) > 0); assert(xkb_state_mod_index_is_active(state, ctrlIdx, XKB_STATE_MODS_EFFECTIVE) > 0); - const struct test_active_mods_entry test_data[] = { + const struct test_active_mods_entry test_data_real[] = { { .state = 0, .active = 0 }, { .state = shift, .active = shift }, { .state = caps, .active = caps }, @@ -396,16 +425,50 @@ test_serialisation(struct xkb_keymap *keymap) { .state = shift | mod1, .active = shift | mod1 | alt | meta }, { .state = shift | mod2, .active = shift | mod2 | num }, }; - - for (unsigned k = 0; k < ARRAY_SIZE(test_data); k++) { + const struct test_active_mods_entry test_data_virtual[] = { + { .state = 0, .active = 0 }, + { .state = shift, .active = shift }, + { .state = caps, .active = caps }, + { .state = ctrl, .active = ctrl }, + { .state = mod1, .active = mod1 }, + { .state = mod2, .active = mod2 }, + { .state = mod3, .active = mod3 }, + { .state = mod4, .active = mod4 }, + { .state = mod5, .active = mod5 }, + { .state = alt, .active = alt }, + { .state = meta, .active = meta }, + { .state = super, .active = super }, + { .state = hyper, .active = hyper }, + { .state = num, .active = num }, + { .state = level3, .active = level3 }, + { .state = shift | mod1, .active = shift | mod1 }, + { .state = mod1 | alt, .active = mod1 | alt }, + { .state = alt | meta, .active = alt | meta }, + { .state = alt | level3, .active = alt | level3 }, + }; + const struct test_active_mods_entry *test_data = pure_vmods + ? test_data_virtual + : test_data_real; + unsigned k_max = pure_vmods + ? ARRAY_SIZE(test_data_virtual) + : ARRAY_SIZE(test_data_real); + + for (unsigned k = 0; k < k_max; k++) { const struct test_active_mods_entry *entry = &test_data[k]; #define check_mods(keymap, state, entry, type) \ for (xkb_mod_index_t idx = 0; idx < xkb_keymap_num_mods(keymap); idx++) { \ xkb_mod_mask_t mask = 1u << idx; \ + fprintf(stderr, "#%u State 0x%x, mod: %u\n", k, entry->state, idx); \ + { \ + xkb_mod_mask_t expected = \ + entry->state | mod_mask_get_effective(keymap, entry->state); \ + xkb_mod_mask_t got = xkb_state_serialize_mods(state, type); \ + assert_printf(got == expected, \ + "xkb_state_serialize_mods, " STRINGIFY2(type) \ + ", %u != %u\n", got, expected); \ + } \ bool expected = !!(mask & entry->active); \ bool got = !!xkb_state_mod_index_is_active(state, idx, type); \ - fprintf(stderr, "#%u State 0x%x, mod: %u: expected %u, got: %u\n", \ - k, entry->state, idx, expected, got); \ assert_printf(got == expected, \ "xkb_state_mod_index_is_active, " STRINGIFY2(type) "\n"); \ got = !!xkb_state_mod_index_is_active(state, idx, \ @@ -437,7 +500,7 @@ test_serialisation(struct xkb_keymap *keymap) } static void -test_update_mask_mods(struct xkb_keymap *keymap) +test_update_mask_mods(struct xkb_keymap *keymap, bool pure_vmods) { enum xkb_state_component changed; struct xkb_state *state = xkb_state_new(keymap); @@ -479,18 +542,18 @@ test_update_mask_mods(struct xkb_keymap *keymap) changed = xkb_state_update_mask(state, alt, 0, 0, 0, 0, 0); assert(changed == (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_EFFECTIVE)); assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) == - (alt | mod1)); + (alt | CANONICAL_MOD(pure_vmods, alt, mod1))); changed = xkb_state_update_mask(state, meta, 0, 0, 0, 0, 0); assert(changed == (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_EFFECTIVE)); assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) == - (meta | mod1)); + (meta | CANONICAL_MOD(pure_vmods, meta, mod1))); changed = xkb_state_update_mask(state, 0, 0, num, 0, 0, 0); assert(changed == (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LOCKED | XKB_STATE_MODS_EFFECTIVE | XKB_STATE_LEDS)); assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) == - (num | mod2)); + (num | CANONICAL_MOD(pure_vmods, num, mod2))); xkb_state_update_mask(state, 0, 0, 0, 0, 0, 0); @@ -502,7 +565,7 @@ test_update_mask_mods(struct xkb_keymap *keymap) assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED) == mod2); assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED) == - (num | mod2)); + (num | CANONICAL_MOD(pure_vmods, num, mod2))); xkb_state_unref(state); } @@ -518,17 +581,19 @@ test_repeat(struct xkb_keymap *keymap) } static void -test_consume(struct xkb_keymap *keymap) +test_consume(struct xkb_keymap *keymap, bool pure_vmods) { xkb_mod_mask_t mask; - xkb_mod_index_t shift = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); - xkb_mod_index_t caps = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); - xkb_mod_index_t ctrl = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); - xkb_mod_index_t mod1 = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD1); - xkb_mod_index_t mod2 = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD2); - xkb_mod_index_t mod5 = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD5); - xkb_mod_index_t alt = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_ALT); - xkb_mod_index_t meta = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_META); + xkb_mod_index_t shift = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); + xkb_mod_index_t caps = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); + xkb_mod_index_t ctrl = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); + xkb_mod_index_t mod1 = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD1); + xkb_mod_index_t mod2 = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD2); + xkb_mod_index_t mod5 = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD5); + xkb_mod_index_t alt = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_ALT); + xkb_mod_index_t meta = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_META); + xkb_mod_index_t num = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_NUM); + xkb_mod_index_t level3 = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_LEVEL3); struct xkb_state *state = xkb_state_new(keymap); assert(state); @@ -541,10 +606,10 @@ test_consume(struct xkb_keymap *keymap) print_state(state); mask = xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE); - assert(mask == ((1U << mod1) | (1U << shift))); + assert(mask == ((1U << CANONICAL_MOD(pure_vmods, alt, mod1)) | (1U << shift))); mask = xkb_state_mod_mask_remove_consumed(state, KEY_EQUAL + EVDEV_OFFSET, mask); - assert(mask == (1U << mod1)); + assert(mask == (1U << CANONICAL_MOD(pure_vmods, alt, mod1))); /* Test get_consumed_mods() */ mask = xkb_state_key_get_consumed_mods(state, KEY_EQUAL + EVDEV_OFFSET); @@ -589,16 +654,19 @@ test_consume(struct xkb_keymap *keymap) assert(state); mask = xkb_state_key_get_consumed_mods(state, KEY_F1 + EVDEV_OFFSET); - assert(mask == ((1U << shift) | (1U << mod1) | (1U << ctrl) | (1U << mod5))); + assert(mask == ((1U << shift) | (1U << CANONICAL_MOD(pure_vmods, alt, mod1)) | + (1U << ctrl) | (1U << CANONICAL_MOD(pure_vmods, level3, mod5)))); /* Shift is preserved. */ xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN); mask = xkb_state_key_get_consumed_mods(state, KEY_F1 + EVDEV_OFFSET); - assert(mask == ((1U << mod1) | (1U << ctrl) | (1U << mod5))); + assert(mask == ((1U << CANONICAL_MOD(pure_vmods, alt, mod1)) | (1U << ctrl) | + (1U << CANONICAL_MOD(pure_vmods, level3, mod5)))); xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_UP); mask = xkb_state_key_get_consumed_mods(state, KEY_F1 + EVDEV_OFFSET); - assert(mask == ((1U << shift) | (1U << mod1) | (1U << ctrl) | (1U << mod5))); + assert(mask == ((1U << shift) | (1U << CANONICAL_MOD(pure_vmods, alt, mod1)) | + (1U << ctrl) | (1U << CANONICAL_MOD(pure_vmods, level3, mod5)))); xkb_state_unref(state); @@ -618,18 +686,25 @@ test_consume(struct xkb_keymap *keymap) xkb_state_update_key(state, KEY_LEFTALT + EVDEV_OFFSET, XKB_KEY_DOWN); mask = xkb_state_key_get_consumed_mods2(state, KEY_F1 + EVDEV_OFFSET, XKB_CONSUMED_MODE_GTK); - assert(mask == ((1U << mod1) | (1U << ctrl))); + assert(mask == ((1U << CANONICAL_MOD(pure_vmods, alt, mod1)) | (1U << ctrl))); assert(xkb_state_mod_index_is_consumed(state, KEY_F1 + EVDEV_OFFSET, shift) > 0); assert(xkb_state_mod_index_is_consumed(state, KEY_F1 + EVDEV_OFFSET, ctrl) > 0); - assert(xkb_state_mod_index_is_consumed(state, KEY_F1 + EVDEV_OFFSET, mod1) > 0); assert(xkb_state_mod_index_is_consumed(state, KEY_F1 + EVDEV_OFFSET, alt) > 0); - assert(xkb_state_mod_index_is_consumed(state, KEY_F1 + EVDEV_OFFSET, meta) > 0); - mask = (1U << ctrl) | (1U << mod1) | (1U << mod2); + if (pure_vmods) { + assert(xkb_state_mod_index_is_consumed(state, KEY_F1 + EVDEV_OFFSET, mod1) == 0); + assert(xkb_state_mod_index_is_consumed(state, KEY_F1 + EVDEV_OFFSET, meta) == 0); + } else { + assert(xkb_state_mod_index_is_consumed(state, KEY_F1 + EVDEV_OFFSET, mod1) > 0); + assert(xkb_state_mod_index_is_consumed(state, KEY_F1 + EVDEV_OFFSET, meta) > 0); + } + mask = (1U << ctrl) | (1U << CANONICAL_MOD(pure_vmods, alt, mod1)) | + (1U << CANONICAL_MOD(pure_vmods, num, mod2)); mask = xkb_state_mod_mask_remove_consumed(state, KEY_F1 + EVDEV_OFFSET, mask); - assert(mask == (1U << mod2)); - mask = (1U << ctrl) | (1U << alt) | (1U << meta) | (1U << mod2); + assert(mask == (1U << CANONICAL_MOD(pure_vmods, num, mod2))); + mask = (1U << ctrl) | (1U << alt) | (1U << CANONICAL_MOD(pure_vmods, alt, meta)) | + (1U << CANONICAL_MOD(pure_vmods, num, mod2)); mask = xkb_state_mod_mask_remove_consumed(state, KEY_F1 + EVDEV_OFFSET, mask); - assert(mask == (1U << mod2)); + assert(mask == (1U << CANONICAL_MOD(pure_vmods, num, mod2))); xkb_state_unref(state); @@ -1156,26 +1231,33 @@ main(void) xkb_keymap_unref(NULL); xkb_state_unref(NULL); - keymap = test_compile_rules(context, "evdev", "pc104", "us,ru", NULL, - "grp:menu_toggle"); - assert(keymap); + const char* rules[] = {"evdev", "evdev-pure-virtual-mods"}; - test_update_key(keymap); - test_serialisation(keymap); - test_update_mask_mods(keymap); - test_repeat(keymap); - test_consume(keymap); - test_range(keymap); - test_get_utf8_utf32(keymap); - test_ctrl_string_transformation(keymap); - test_overlapping_mods(context); + for (size_t r = 0; r < ARRAY_SIZE(rules); r++) { + fprintf(stderr, "=== Rules set: %s ===\n", rules[r]); + keymap = test_compile_rules(context, rules[r], "pc104", "us,ru", NULL, + "grp:menu_toggle"); + assert(keymap); - xkb_keymap_unref(keymap); - keymap = test_compile_rules(context, "evdev", NULL, "ch", "fr", NULL); - assert(keymap); + test_update_key(keymap, !!r); + test_serialisation(keymap, !!r); + test_update_mask_mods(keymap, !!r); + test_repeat(keymap); + test_consume(keymap, !!r); + test_range(keymap); + test_get_utf8_utf32(keymap); + test_ctrl_string_transformation(keymap); - test_caps_keysym_transformation(keymap); + xkb_keymap_unref(keymap); + keymap = test_compile_rules(context, rules[r], NULL, "ch", "fr", NULL); + assert(keymap); + + test_caps_keysym_transformation(keymap); + + xkb_keymap_unref(keymap); + } + + test_overlapping_mods(context); - xkb_keymap_unref(keymap); xkb_context_unref(context); }