diff options
author | Wismill <dev@wismill.eu> | 2023-05-01 22:30:41 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-01 23:30:41 +0300 |
commit | 5b5b67f28ccfe1fe69ec5569c90f1752de323a08 (patch) | |
tree | 09c02e8aa8d7fe495109823ee5848cdc01becb96 /src | |
parent | 0e9c2ec97e8f5280171002834243104b9f53a772 (diff) | |
download | xorg-lib-libxkbcommon-5b5b67f28ccfe1fe69ec5569c90f1752de323a08.tar.gz |
Add support for modmap None (#291)
Unlike current xkbcommon, X11’s xkbcomp allows to remove entries in
the modifiers’ map using “modifier_map None { … }”.
“None” is translated to the special value “XkbNoModifier” defined in
“X11/extensions/XKB.h”. Then it relies on the fact that in "CopyModMapDef",
the following code:
1U << entry->modifier
ends up being zero when “entry->modifier” is “XkbNoModifier” (i.e. 0xFF).
Indeed, it relies on the overflow behaviour of the left shift, which in
practice resolves to use only the 5 low bits of the shift amount, i.e.
0x1F here. Then the result of “1U << 0xFF” is cast to “char”, i.e. 0.
This is a good trick but too magical, so in libxkbcommon we will use
an explicit test against our new constant XKB_MOD_NONE.
Diffstat (limited to 'src')
-rw-r--r-- | src/keymap.h | 3 | ||||
-rw-r--r-- | src/text.c | 3 | ||||
-rw-r--r-- | src/xkbcomp/ast.h | 1 | ||||
-rw-r--r-- | src/xkbcomp/symbols.c | 32 |
4 files changed, 30 insertions, 9 deletions
diff --git a/src/keymap.h b/src/keymap.h index 7c5341d..f7ea5bd 100644 --- a/src/keymap.h +++ b/src/keymap.h @@ -109,6 +109,9 @@ /* 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)) +/* Special value to handle modMap None {…} */ +#define XKB_MOD_NONE 0xffffffffU + /* These should all go away. */ enum mod_type { MOD_REAL = (1 << 0), @@ -216,6 +216,9 @@ ModIndexText(struct xkb_context *ctx, const struct xkb_mod_set *mods, if (ndx == XKB_MOD_INVALID) return "none"; + if (ndx == XKB_MOD_NONE) + return "None"; + if (ndx >= mods->num_mods) return NULL; diff --git a/src/xkbcomp/ast.h b/src/xkbcomp/ast.h index 6c51ce4..8b0901f 100644 --- a/src/xkbcomp/ast.h +++ b/src/xkbcomp/ast.h @@ -303,6 +303,7 @@ typedef struct { typedef struct { ParseCommon common; enum merge_mode merge; + // NOTE: Can also be “None”, rather than a modifier name. xkb_atom_t modifier; ExprDef *keys; } ModMapDef; diff --git a/src/xkbcomp/symbols.c b/src/xkbcomp/symbols.c index eb78412..f990529 100644 --- a/src/xkbcomp/symbols.c +++ b/src/xkbcomp/symbols.c @@ -162,6 +162,8 @@ ClearKeyInfo(KeyInfo *keyi) typedef struct { enum merge_mode merge; bool haveSymbol; + // NOTE: Can also be XKB_MOD_NONE, meaning + // “don’t add a modifier to the modmap”. xkb_mod_index_t modifier; union { xkb_atom_t keyName; @@ -1152,14 +1154,21 @@ HandleModMapDef(SymbolsInfo *info, ModMapDef *def) xkb_mod_index_t ndx; bool ok; struct xkb_context *ctx = info->ctx; - - ndx = XkbModNameToIndex(&info->mods, def->modifier, MOD_REAL); - if (ndx == XKB_MOD_INVALID) { - log_err(info->ctx, - "Illegal modifier map definition; " - "Ignoring map for non-modifier \"%s\"\n", - xkb_atom_text(ctx, def->modifier)); - return false; + const char *modifier_name = xkb_atom_text(ctx, def->modifier); + + if (istreq(modifier_name, "none")) { + // Handle special "None" entry + ndx = XKB_MOD_NONE; + } else { + // Handle normal entry + ndx = XkbModNameToIndex(&info->mods, def->modifier, MOD_REAL); + if (ndx == XKB_MOD_INVALID) { + log_err(info->ctx, + "Illegal modifier map definition; " + "Ignoring map for non-modifier \"%s\"\n", + xkb_atom_text(ctx, def->modifier)); + return false; + } } ok = true; @@ -1523,7 +1532,12 @@ CopyModMapDefToKeymap(struct xkb_keymap *keymap, SymbolsInfo *info, } } - key->modmap |= (1u << entry->modifier); + // Handle modMap None + if (entry->modifier != XKB_MOD_NONE) { + // Convert modifier index to modifier mask + key->modmap |= (1u << entry->modifier); + } + return true; } |