Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experiment: Add new real modifiers #447

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/keymap-priv.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,29 @@
static void
update_builtin_keymap_fields(struct xkb_keymap *keymap)
{
/* Predefined (AKA real, core, X11) modifiers. The order is important! */
/* Predefined (AKA real) modifiers. The order is important!
* Indeed, the modifier position defines the bit used to encode it.
* We use explicit indexes here to facilitate debugging. */
static const char *const builtin_mods[] = {
/* Core/X11 modifiers */
[0] = "Shift",
[1] = "Lock",
[2] = "Control",
[3] = "Mod1",
[4] = "Mod2",
[5] = "Mod3",
[6] = "Mod4",
[7] = "Mod5"
[7] = "Mod5",
/* xkbcommon extension */
[8] = "Mod6",
whot marked this conversation as resolved.
Show resolved Hide resolved
[9] = "Mod7",
[10] = "Mod8",
[11] = "Mod9",
[12] = "Mod10"
};

_Static_assert(ARRAY_SIZE(builtin_mods) == MOD_REAL_MAX);

for (unsigned i = 0; i < ARRAY_SIZE(builtin_mods); i++) {
keymap->mods.mods[i].name = xkb_atom_intern(keymap->ctx,
builtin_mods[i],
Expand Down
16 changes: 13 additions & 3 deletions src/keymap.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@
#define XKB_MAX_GROUPS 4

/* Don't allow more modifiers than we can hold in xkb_mod_mask_t. */
#define XKB_MAX_MODS ((xkb_mod_index_t) (sizeof(xkb_mod_mask_t) * 8))
#define XKB_MAX_MODS ((xkb_mod_index_t) (sizeof(xkb_mod_mask_t) * CHAR_BIT))

/* Don't allow more leds than we can hold in xkb_led_mask_t. */
#define XKB_MAX_LEDS ((xkb_led_index_t) (sizeof(xkb_led_mask_t) * 8))
#define XKB_MAX_LEDS ((xkb_led_index_t) (sizeof(xkb_led_mask_t) * CHAR_BIT))

/* Special value to handle modMap None {…} */
#define XKB_MOD_NONE 0xffffffffU
Expand All @@ -118,7 +118,17 @@ enum mod_type {
MOD_VIRT = (1 << 1),
MOD_BOTH = (MOD_REAL | MOD_VIRT),
};
#define MOD_REAL_MASK_ALL ((xkb_mod_mask_t) 0x000000ff)

/* Count of real modifiers */
#define MOD_REAL_MAX 13
#define MOD_REAL_MAX_X11 8

/* Ensure we can encode the modifier mask in xkb_mod_mask_t */
_Static_assert(MOD_REAL_MAX <= XKB_MAX_MODS);

/* Mask for all real modifiers */
#define MOD_REAL_MASK_ALL ((xkb_mod_mask_t) ((1u << MOD_REAL_MAX) - 1))
#define MOD_REAL_MASK_ALL_X11 ((xkb_mod_mask_t) ((1u << MOD_REAL_MAX_X11) - 1))

enum xkb_action_type {
ACTION_TYPE_NONE = 0,
Expand Down
3 changes: 2 additions & 1 deletion src/text.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,8 @@ ModMaskText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
if (mask == 0)
return "none";

if (mask == MOD_REAL_MASK_ALL)
if (mask == MOD_REAL_MASK_ALL ||
mask == MOD_REAL_MASK_ALL_X11 /* hack for X11 compatibility */)
return "all";

xkb_mods_enumerate(i, mod, mods) {
Expand Down
164 changes: 164 additions & 0 deletions test/data/keymaps/real-modifiers.xkb
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
xkb_keymap {
xkb_keycodes "test" {
minimum = 8;
maximum = 255;
<LVL3> = 92;
<LFSH> = 50;
<RTSH> = 62;
<LALT> = 64;
<RALT> = 108;
<LWIN> = 133;
<RWIN> = 134;
<LCTL> = 37;
<RCTL> = 105;
<CAPS> = 66;

<AD01> = 24;
<AD02> = 25;
<AD03> = 26;
<AD04> = 27;
<AD05> = 28;
<AD06> = 29;
<AD07> = 30;
<AD08> = 31;
<AD09> = 32;
};

xkb_types "complete" {
// Define a buch of virtual modifier to test mappings to Mod5-Mod10 real
// modifiers. VMod11 will be mapped to Mod5+Mod6.
virtual_modifiers VMod5,VMod6,VMod6,VMod7,VMod8,VMod9,VMod10,VMod11;

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 "SOOO_MANY_LEVELS" {
modifiers = Shift+VMod5+VMod6+VMod6+VMod7+VMod8+VMod9+VMod10+VMod11;
map[Shift] = 2;
map[VMod5] = 3;
map[VMod6] = 4;
map[VMod6+Shift] = 5;
map[VMod7] = 6;
map[VMod8] = 7;
map[VMod9] = 8;
map[VMod10] = 9;
map[VMod11] = 10;
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";
};
};
xkb_compatibility "complete" {
interpret.useModMapMods= AnyLevel;
interpret.repeat= False;
interpret.locking= False;

virtual_modifiers VMod5,VMod6,VMod7,VMod8,VMod9,VMod10,VMod11;

interpret Any+AnyOf(all) {
action = SetMods(modifiers=modMapMods,clearLocks);
};

// Define some letter keysyms as custom modifiers
interpret Q {
useModMapMods = level1;
virtualModifier = VMod5;
action = SetMods(modifiers=VMod5);
};
interpret W {
useModMapMods = level1;
virtualModifier = VMod6;
action = SetMods(modifiers=VMod6);
};
interpret E {
useModMapMods = level1;
virtualModifier = VMod7;
action = SetMods(modifiers=VMod7);
};
interpret R {
useModMapMods = level1;
virtualModifier = VMod8;
action = SetMods(modifiers=VMod8);
};
interpret T {
useModMapMods = level1;
virtualModifier = VMod9;
action = SetMods(modifiers=VMod9);
};
interpret Y {
useModMapMods = level1;
virtualModifier = VMod10;
action = SetMods(modifiers=VMod10);
};
interpret U {
useModMapMods = level1;
virtualModifier = VMod11;
action = SetMods(modifiers=VMod11);
};
interpret I {
useModMapMods = level1;
virtualModifier = VMod11;
action = SetMods(modifiers=VMod11);
};
};
xkb_symbols {
name[group1]="Test";

// Map the modifiers. The letter keysyms only serve to map
// the modifier actions (see interpret entries above).

key <LFSH> { [Shift_L] };
modifier_map Shift { <LFSH> };

// virtual modifier: VMod5
key <AD01> { [Q] };
modifier_map Mod5 { <AD01> };

// virtual modifier: VMod6
key <AD02> { [W] };
modifier_map Mod6 { <AD02> }; // real modifier not supported by X11

// virtual modifier: VMod7
key <AD03> { [E] };
modifier_map Mod7 { <AD03> }; // real modifier not supported by X11

// virtual modifier: VMod8
key <AD04> { [R] };
modifier_map Mod8 { <AD04> }; // real modifier not supported by X11

// virtual modifier: VMod9
key <AD05> { [T] };
modifier_map Mod9 { <AD05> }; // real modifier not supported by X11

// virtual modifier: VMod10
key <AD06> { [Y] };
modifier_map Mod10 { <AD06> }; // real modifier not supported by X11

// virtual modifier: VMod11 (Mod5+Mod6)
key <AD07> { [U] };
modifier_map Mod5 { <AD07> };
key <AD08> { [I] };
modifier_map Mod6 { <AD08> }; // real modifier not supported by X11

// Key to test that all the levels work
key <AD09> {
type[Group1]="SOOO_MANY_LEVELS",
symbols[Group1]=[1,2,3,4,5,6,7,8,9,A]
};

};
};
96 changes: 96 additions & 0 deletions test/modifiers.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

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

// Standard real modifier masks
#define ShiftMask (1 << 0)
Expand All @@ -39,6 +40,12 @@
#define Mod3Mask (1 << 5)
#define Mod4Mask (1 << 6)
#define Mod5Mask (1 << 7)
#define Mod6Mask (1 << 8)
#define Mod7Mask (1 << 9)
#define Mod8Mask (1 << 10)
#define Mod9Mask (1 << 11)
#define Mod10Mask (1 << 12)
#define HighestRealMask Mod10Mask
#define NoModifier 0

static void
Expand Down Expand Up @@ -151,10 +158,99 @@ test_modmap_none(void)
xkb_context_unref(context);
}

static void
test_real_mods(void)
{
struct xkb_context *context = test_get_context(0);
struct xkb_keymap *keymap;
const struct xkb_key *key;
xkb_keycode_t keycode;

keymap = test_compile_file(context, "keymaps/real-modifiers.xkb");
assert(keymap);

keycode = xkb_keymap_key_by_name(keymap, "AD01");
assert(keycode != XKB_KEYCODE_INVALID);
key = XkbKey(keymap, keycode);
assert(key->modmap == Mod5Mask);
/* Test that VMod5 is the first defined virtual modifier */
assert(key->vmodmap == HighestRealMask << 1);

keycode = xkb_keymap_key_by_name(keymap, "AD02");
assert(keycode != XKB_KEYCODE_INVALID);
key = XkbKey(keymap, keycode);
assert(key->modmap == Mod6Mask);
/* Test that VMod5 is the second defined virtual modifier */
assert(key->vmodmap == HighestRealMask << 2);

/* Test that we get the expected keysym for each level of KEY_O (<AD09>).
* Most levels require support of the real modifiers Mod6-Mod10. */
assert(test_key_seq(keymap,
/* Level 1 */
KEY_O, BOTH, XKB_KEY_1, NEXT,
/* Level 2 */
KEY_LEFTSHIFT, DOWN, XKB_KEY_Shift_L, NEXT,
KEY_O, BOTH, XKB_KEY_2, NEXT,
KEY_LEFTSHIFT, UP, XKB_KEY_Shift_L, NEXT,
/* Level 3 (VMod5 = Mod5) */
KEY_Q, DOWN, XKB_KEY_Q, NEXT,
KEY_O, BOTH, XKB_KEY_3, NEXT,
KEY_Q, UP, XKB_KEY_Q, NEXT,
/* Level 4 (VMod6 = Mod6) */
KEY_W, DOWN, XKB_KEY_W, NEXT,
KEY_O, BOTH, XKB_KEY_4, NEXT,
/* Level 5 (VMod6 + Shift = Mod6 + Shift) */
KEY_LEFTSHIFT, DOWN, XKB_KEY_Shift_L, NEXT,
KEY_O, BOTH, XKB_KEY_5, NEXT,
KEY_LEFTSHIFT, UP, XKB_KEY_Shift_L, NEXT,
KEY_W, UP, XKB_KEY_W, NEXT,
/* Level 6 (VMod7 = Mod7) */
KEY_E, DOWN, XKB_KEY_E, NEXT,
KEY_O, BOTH, XKB_KEY_6, NEXT,
KEY_E, UP, XKB_KEY_E, NEXT,
/* Level 7 (VMod8 = Mod8) */
KEY_R, DOWN, XKB_KEY_R, NEXT,
KEY_O, BOTH, XKB_KEY_7, NEXT,
KEY_R, UP, XKB_KEY_R, NEXT,
/* Level 8 (VMod9 = Mod9) */
KEY_T, DOWN, XKB_KEY_T, NEXT,
KEY_O, BOTH, XKB_KEY_8, NEXT,
KEY_T, UP, XKB_KEY_T, NEXT,
/* Level 9 (VMod10 = Mod10) */
KEY_Y, DOWN, XKB_KEY_Y, NEXT,
KEY_O, BOTH, XKB_KEY_9, NEXT,
KEY_Y, UP, XKB_KEY_Y, NEXT,
/* Level 10 using KEY_U (VMod11 = Mod5 + Mod6) */
KEY_U, DOWN, XKB_KEY_U, NEXT,
KEY_O, BOTH, XKB_KEY_A, NEXT,
KEY_U, UP, XKB_KEY_U, NEXT,
/* Level 10 using KEY_I (VMod11 = Mod5 + Mod6) */
KEY_I, DOWN, XKB_KEY_I, NEXT,
KEY_O, BOTH, XKB_KEY_A, NEXT,
KEY_I, UP, XKB_KEY_I, NEXT,
/* Level 10 using KEY_Q + KEY_W
* VMod5 + VMod6 = Mod5 + Mod6 = VMod11 */
KEY_Q, DOWN, XKB_KEY_Q, NEXT,
KEY_W, DOWN, XKB_KEY_W, NEXT,
KEY_O, BOTH, XKB_KEY_A, NEXT,
KEY_W, UP, XKB_KEY_W, NEXT,
KEY_Q, UP, XKB_KEY_Q, NEXT,
/* Invalid level, fallback to base level */
KEY_W, DOWN, XKB_KEY_W, NEXT,
KEY_E, DOWN, XKB_KEY_E, NEXT,
KEY_O, BOTH, XKB_KEY_1, NEXT,
KEY_E, UP, XKB_KEY_E, NEXT,
KEY_W, UP, XKB_KEY_W, FINISH));

xkb_keymap_unref(keymap);
xkb_context_unref(context);
}

int
main(void)
{
test_modmap_none();
test_real_mods();

return 0;
}
Loading