Skip to content

Commit

Permalink
symbols: Add tests for multiple actions per level
Browse files Browse the repository at this point in the history
  • Loading branch information
wismill committed Oct 7, 2024
1 parent 362f4a0 commit 4075c7a
Show file tree
Hide file tree
Showing 3 changed files with 322 additions and 1 deletion.
7 changes: 6 additions & 1 deletion test/data/symbols/awesome
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ xkb_symbols "awesome" {
key <AC01> { [ a, A, Return, Return ] };
key <AC02> { [ s, S, Left] };
key <AC03> { [ d, D, Down] };
key <AC04> { [ f, F, Righ] };
key <AC04> { [ f, F, Right] };
key <AC05> { [ g, G, BackSpace, BackSpace ] };

key <AB05> { [ b, B, Delete, Delete ] };

key <LCTL> {
symbols[1] = [ {Control_L, ISO_Next_Group } ],
actions[1] = [ {SetMods(modifiers=Control), SetGroup(group=+1) } ]
};
};
104 changes: 104 additions & 0 deletions test/data/symbols/multiple_actions
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
default alphanumeric_keys modifier_keys
xkb_symbols "basic" {
name[1] = "Multiple actions";

virtual_modifiers Alt, Super, LevelThree;

// Multiple keysyms but no actions: OK
key <LCTL> {
symbols[1] = [ { Control_L, ISO_Group_Shift } ]
};
// Multiple actions but no keysyms: OK, but will use NoSymbol
key <RCTL> {
actions[1] = [ { SetMods(modifiers=Control), SetGroup(group=+1) } ]
};
// Multiple keysyms and matching actions
key <LVL3> {
virtualModifiers = LevelThree,
symbols[1] = [ { ISO_Level3_Shift, ISO_Group_Shift } ],
actions[1] = [ { SetMods(modifiers=LevelThree), SetGroup(group=+1) } ]
};
// Multiple actions and matching keysyms
key <MDSW> {
virtualModifiers = LevelThree,
actions[1] = [ { SetMods(modifiers=LevelThree), SetGroup(group=+1) } ],
symbols[1] = [ { ISO_Level3_Shift, ISO_Group_Shift } ]
};

// Incompatible actions and keysyms count: error
key <LALT> {
symbols[1] = [ { Alt_L } ],
actions[1] = [ { SetMods(modifiers=Alt), SetGroup(group=+1) } ]
};
key <RALT> {
symbols[1] = [ { Alt_R, ISO_Group_Shift } ],
actions[1] = [ { SetMods(modifiers=Alt) } ]
};
key <LWIN> {
symbols[1] = [ { Super_L, ISO_Group_Shift } ],
actions[1] = [ { SetMods(modifiers=Super), SetGroup(group=+1), NoAction() } ]
};
key <RWIN> {
symbols[1] = [ { Super_R, ISO_Group_Shift , NoSymbol } ],
actions[1] = [ { SetMods(modifiers=Super), SetGroup(group=+1) } ]
};

// Incompatible categories
key <AB11> {
symbols[1] = [ { Control_L, Shift_L } ]
};
modifier_map Control { <AB11> };
key <AE13> {
symbols[1] = [ { Control_L, Shift_L } ],
actions[1] = [ { SetMods(modifiers=Control), SetMods(modifiers=Shift) } ]
};

// Various overrides, different keysyms, no explicit actions
key <AB01> { [ x ] };
key <AB01> { [ { Control_L, ISO_Group_Shift } ] };

key <AB02> { [ { Control_L, ISO_Group_Shift } ] };
key <AB02> { [ x ] };

// Various overrides, no keysyms, explicit actions
key <AB03> { actions[1] = [ { SetMods(modifiers=LevelThree) } ] };
key <AB03> { actions[1] = [ { SetMods(modifiers=LevelThree), SetGroup(group=+1) } ] };

key <AB04> { actions[1] = [ { SetMods(modifiers=LevelThree), SetGroup(group=+1) } ] };
key <AB04> { actions[1] = [ { SetMods(modifiers=LevelThree) } ] };

// Various overrides, different keysyms & actions
key <AB05> {
virtualModifiers = LevelThree,
symbols[1] = [ Control_L ],
actions[1] = [ SetMods(modifiers=Control) ]
};
key <AB05> {
symbols[1] = [ { ISO_Level3_Shift, ISO_Group_Shift } ],
actions[1] = [ { SetMods(modifiers=LevelThree), SetGroup(group=+1) } ]
};

key <AB06> {
virtualModifiers = LevelThree,
symbols[1] = [ { ISO_Level3_Shift, ISO_Group_Shift } ],
actions[1] = [ { SetMods(modifiers=LevelThree), SetGroup(group=+1) } ]
};
key <AB06> {
symbols[1] = [ Control_L ],
actions[1] = [ SetMods(modifiers=Control) ]
};

// Various overrides, same keysyms but different actions
key <AB07> {
virtualModifiers = LevelThree,
symbols[1] = [ { ISO_Level3_Shift, ISO_Group_Shift } ],
actions[1] = [ { SetMods(modifiers=Control), Private(type=254, data="foo") } ]
};
key <AB07> {
symbols[1] = [ { ISO_Level3_Shift, ISO_Group_Shift } ],
actions[1] = [ { SetMods(modifiers=LevelThree), SetGroup(group=+1) } ]
};

// Our only alphanum key ✨
key <AE02> { [ 2, at ] };
};
212 changes: 212 additions & 0 deletions test/keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,13 @@
#include <stdio.h>
#include <stdlib.h>

#include "evdev-scancodes.h"
#include "test.h"
#include "keymap.h"

#define KEY_LVL3 84
#define KEY_LVL5 195

static void
test_garbage_key(void)
{
Expand Down Expand Up @@ -230,6 +234,213 @@ test_multiple_keysyms_per_level(void)
xkb_context_unref(context);
}

static void
test_multiple_actions_per_level(void)
{
struct xkb_context *context = test_get_context(0);
struct xkb_keymap *keymap;
struct xkb_state *state;
xkb_keycode_t kc;
int keysyms_count;
const xkb_layout_index_t first_layout = 0;
const xkb_keysym_t *keysyms;
xkb_mod_index_t ctrl, level3;
xkb_layout_index_t layout;
xkb_mod_mask_t base_mods;

assert(context);

/* Test various ways to set multiple actions */
keymap = test_compile_rules(context, "evdev", "pc104",
"multiple_actions,cz", NULL, NULL);
assert(keymap);

kc = xkb_keymap_key_by_name(keymap, "LCTL");
ctrl = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL);
level3 = xkb_keymap_mod_get_index(keymap, "Mod5");
state = xkb_state_new(keymap);
assert(state);
layout = xkb_state_key_get_layout(state, KEY_LEFTCTRL + EVDEV_OFFSET);
assert(layout == 0);
xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_DOWN);
base_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED);
assert(base_mods == (1U << ctrl));
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_DEPRESSED);
assert(layout == 1);
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_LATCHED);
assert(layout == 0);
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_LOCKED);
assert(layout == 0);
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_EFFECTIVE);
assert(layout == 1);
xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_UP);
base_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED);
assert(base_mods == 0);
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_DEPRESSED);
assert(layout == 0);
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_LATCHED);
assert(layout == 0);
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_LOCKED);
assert(layout == 0);
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_EFFECTIVE);
assert(layout == 0);
xkb_state_update_key(state, KEY_LVL3 + EVDEV_OFFSET, XKB_KEY_DOWN);
base_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED);
assert(base_mods == (1U << level3));
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_DEPRESSED);
assert(layout == 1);
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_LATCHED);
assert(layout == 0);
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_LOCKED);
assert(layout == 0);
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_EFFECTIVE);
assert(layout == 1);
xkb_state_update_key(state, KEY_LVL3 + EVDEV_OFFSET, XKB_KEY_UP);
base_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED);
assert(base_mods == 0);
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_DEPRESSED);
assert(layout == 0);
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_LATCHED);
assert(layout == 0);
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_LOCKED);
assert(layout == 0);
layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_EFFECTIVE);
assert(layout == 0);
xkb_state_unref(state);

assert(test_key_seq(
keymap,
KEY_2, BOTH, XKB_KEY_2, NEXT,
/* Control switch to the second group */
KEY_LEFTCTRL, DOWN, XKB_KEY_Control_L, XKB_KEY_ISO_Group_Shift, NEXT,
KEY_2, BOTH, XKB_KEY_ecaron, NEXT,
KEY_LEFTCTRL, UP, XKB_KEY_Control_L, XKB_KEY_ISO_Group_Shift, NEXT,
KEY_2, BOTH, XKB_KEY_2, NEXT,
KEY_RIGHTCTRL, DOWN, XKB_KEY_NoSymbol, XKB_KEY_NoSymbol, NEXT,
KEY_2, BOTH, XKB_KEY_ecaron, NEXT,
KEY_RIGHTCTRL, UP, XKB_KEY_NoSymbol, XKB_KEY_NoSymbol, NEXT,
KEY_2, BOTH, XKB_KEY_2, NEXT,
/* Fake keys switch to the second group too */
KEY_LVL3, DOWN, XKB_KEY_ISO_Level3_Shift, XKB_KEY_ISO_Group_Shift, NEXT,
KEY_2, BOTH, XKB_KEY_at, NEXT,
KEY_LVL3, UP, XKB_KEY_ISO_Level3_Shift,
/* Only one keysym, group=2 + level3(ralt_switch):2 */
NEXT,
KEY_2, BOTH, XKB_KEY_2, NEXT,
KEY_LVL5, DOWN, XKB_KEY_ISO_Level3_Shift, XKB_KEY_ISO_Group_Shift, NEXT,
KEY_2, BOTH, XKB_KEY_at, NEXT,
KEY_LVL5, UP, XKB_KEY_ISO_Level3_Shift, XKB_KEY_ISO_Group_Shift, NEXT,
KEY_2, BOTH, XKB_KEY_2, NEXT,
/* Alt have invalid entries and do not change the group */
KEY_LEFTALT, DOWN, XKB_KEY_Alt_L, NEXT,
KEY_2, BOTH, XKB_KEY_2, NEXT,
KEY_LEFTALT, UP, XKB_KEY_Alt_L, NEXT,
KEY_RIGHTALT, DOWN, XKB_KEY_Alt_R, XKB_KEY_ISO_Group_Shift, NEXT,
KEY_2, BOTH, XKB_KEY_2, NEXT,
KEY_RIGHTALT, UP, XKB_KEY_Alt_R, XKB_KEY_ISO_Group_Shift, NEXT,
/* Super have invalid entries and do not change the group */
KEY_LEFTMETA, DOWN, XKB_KEY_Super_L, XKB_KEY_ISO_Group_Shift, NEXT,
KEY_2, BOTH, XKB_KEY_2, NEXT,
KEY_LEFTMETA, UP, XKB_KEY_Super_L, XKB_KEY_ISO_Group_Shift, NEXT,
KEY_RIGHTMETA, DOWN, XKB_KEY_Super_R, XKB_KEY_ISO_Group_Shift,
XKB_KEY_NoSymbol, NEXT,
KEY_2, BOTH, XKB_KEY_2, NEXT,
KEY_RIGHTMETA, UP, XKB_KEY_Super_R, XKB_KEY_ISO_Group_Shift,
XKB_KEY_NoSymbol, NEXT,
KEY_2, BOTH, XKB_KEY_2, NEXT,
/* Incompatible actions categories */
KEY_RO, DOWN, XKB_KEY_Control_L, XKB_KEY_Shift_L, NEXT,
KEY_2, BOTH, XKB_KEY_2, NEXT,
KEY_RO, UP, XKB_KEY_Control_L, XKB_KEY_Shift_L, NEXT,
KEY_YEN, DOWN, XKB_KEY_Control_L, XKB_KEY_Shift_L, NEXT,
KEY_2, BOTH, XKB_KEY_2, NEXT,
KEY_YEN, UP, XKB_KEY_Control_L, XKB_KEY_Shift_L, NEXT,
/* Test various overrides */
KEY_Z, DOWN, XKB_KEY_Control_L, XKB_KEY_ISO_Group_Shift, NEXT,
KEY_2, BOTH, XKB_KEY_ecaron, NEXT,
KEY_Z, UP, XKB_KEY_y, NEXT,
KEY_X, BOTH, XKB_KEY_x, NEXT,
KEY_C, DOWN, XKB_KEY_NoSymbol, XKB_KEY_NoSymbol, NEXT,
KEY_2, BOTH, XKB_KEY_at, NEXT,
KEY_C, UP, XKB_KEY_ampersand, NEXT,
KEY_V, DOWN, XKB_KEY_NoSymbol, NEXT,
KEY_2, BOTH, XKB_KEY_2, NEXT,
KEY_V, UP, XKB_KEY_NoSymbol, NEXT,
KEY_B, DOWN, XKB_KEY_ISO_Level3_Shift, XKB_KEY_ISO_Group_Shift, NEXT,
KEY_2, BOTH, XKB_KEY_at, NEXT,
KEY_B, UP, XKB_KEY_braceleft,NEXT,
KEY_N, DOWN, XKB_KEY_Control_L, NEXT,
KEY_2, BOTH, XKB_KEY_2, NEXT,
KEY_N, UP, XKB_KEY_Control_L, NEXT,
KEY_M, DOWN, XKB_KEY_ISO_Level3_Shift, XKB_KEY_ISO_Group_Shift, NEXT,
KEY_2, BOTH, XKB_KEY_at, NEXT,
KEY_M, UP, XKB_KEY_asciicircum, NEXT,
KEY_2, BOTH, XKB_KEY_2, FINISH));

xkb_keymap_unref(keymap);

/* TODO: This example is intended to make keyboard shortcuts use the first
* layout. However, this requires to be able to configure group redirect
* at the *keymap* level, then use ISO_First_Group and SetGroup(group=-4).
* Change the symbols and this test once this is merged. */
keymap = test_compile_rules(context, "evdev", "pc104",
"awesome,cz", NULL, "grp:menu_toggle");
assert(keymap);

ctrl = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL);

kc = xkb_keymap_key_by_name(keymap, "LCTL");
keysyms_count = xkb_keymap_key_get_syms_by_level(keymap, kc, first_layout, 0, &keysyms);
assert(keysyms_count == 2);
assert(keysyms[0] == XKB_KEY_Control_L);
assert(keysyms[1] == XKB_KEY_ISO_Next_Group);

state = xkb_state_new(keymap);
assert(state);
layout = xkb_state_key_get_layout(state, KEY_LEFTCTRL + EVDEV_OFFSET);
assert(layout == 0);
xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_DOWN);
base_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED);
assert(base_mods == (1U << ctrl));
layout = xkb_state_key_get_layout(state, XKB_KEY_2 + EVDEV_OFFSET);
assert(layout == 1);
xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_UP);
base_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED);
assert(base_mods == 0);
layout = xkb_state_key_get_layout(state, XKB_KEY_2 + EVDEV_OFFSET);
assert(layout == 0);
xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_DOWN);
xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_UP);
layout = xkb_state_key_get_layout(state, XKB_KEY_2 + EVDEV_OFFSET);
assert(layout == 1);
xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_DOWN);
base_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED);
assert(base_mods == (1U << ctrl));
layout = xkb_state_key_get_layout(state, XKB_KEY_2 + EVDEV_OFFSET);
assert(layout == 0);
xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_UP);
base_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED);
assert(base_mods == 0);
layout = xkb_state_key_get_layout(state, XKB_KEY_2 + EVDEV_OFFSET);
assert(layout == 1);
xkb_state_unref(state);

assert(test_key_seq(keymap,
KEY_2, BOTH, XKB_KEY_2, NEXT,
KEY_LEFTCTRL, DOWN, XKB_KEY_Control_L, XKB_KEY_ISO_Next_Group, NEXT,
KEY_2, BOTH, XKB_KEY_ecaron, NEXT,
KEY_LEFTCTRL, UP, XKB_KEY_Control_L, XKB_KEY_ISO_Next_Group, NEXT,
KEY_COMPOSE, BOTH, XKB_KEY_ISO_Next_Group, NEXT,
KEY_2, BOTH, XKB_KEY_ecaron, NEXT,
KEY_LEFTCTRL, DOWN, XKB_KEY_Control_L, XKB_KEY_ISO_Next_Group, NEXT,
KEY_2, BOTH, XKB_KEY_2, NEXT,
KEY_LEFTCTRL, UP, XKB_KEY_Control_L, XKB_KEY_ISO_Next_Group, NEXT,
KEY_2, BOTH, XKB_KEY_ecaron, FINISH));

xkb_keymap_unref(keymap);
xkb_context_unref(context);
}

int
main(void)
{
Expand All @@ -239,6 +450,7 @@ main(void)
test_keymap();
test_numeric_keysyms();
test_multiple_keysyms_per_level();
test_multiple_actions_per_level();

return 0;
}

0 comments on commit 4075c7a

Please sign in to comment.