changes

Branch


Log

Author Commit Date CI Message
Pierre Le Marre 54d188c7 2025-10-21T13:40:06 build: Restrict Compose fallback test in cross-compiling Do not perform the test if the build machine cannot run host binaries. Instead fallback to detect if the `newlocale` lib is *known* to fail on missing locales, as we expect.
Pierre Le Marre bdf069f9 2025-10-20T17:24:58 Bump version to 1.12.2
Pierre Le Marre 22799562 2025-10-20T13:07:58 compose: No fallback if no missing locale detection Do not use `newlocale()` if it accepts missing locales. It happens with muslc, while glibc works as expected. It fixes the incorrect behavior of the fallback introduced in 135b3204a15838205c97e793cd41faa742d429e2.
Pierre Le Marre 3c0eb068 2025-10-17T14:50:07 Bump version to 1.12.1
Pierre Le Marre 939bf0e1 2025-10-17T11:57:53 xkbcomp: Never drop X11 canonical key types There are 4 mandatory *canonical key types* in the XKB protocol: - `ONE_LEVEL` - `TWO_LEVEL` - `ALPHABETIC` - `KEYPAD` They are always present in the keymap generated from xkeyboard-config. But since 31900860c65b88e4d10ad7dd00377e2815cca0f6 we drop unused key types by default, which may happen for the types hereinabove with e.g. 4+ level layouts like `es`. In theory these types are automatically filled by libX11 if missing, but there are some bugs in the X11 ecosystem that prevents the keymap to be properly uploaded in the X server, leading to errors when retrieving it with libxkbcommon-x11. See: https://gitlab.archlinux.org/archlinux/packaging/packages/libxkbcommon/-/issues/3 The following fixes were filed to fix the issues: - https://gitlab.freedesktop.org/xorg/lib/libx11/-/merge_requests/292 - https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2082 - https://github.com/xkbcommon/libxkbcommon/pull/871 However it’s not clear when new versions of libX11 and xserver will be released. So this commit is a hack to ensure that we do not drop the XKB canonical key types, as an effort to reduce breakage. WARNING: contrary to `xkbcomp`, we do not supply these types if they are missing, because a keymap that uses them (explicitly `type="…"` or implicitly with automatic types) without providing them is considered buggy. The only exception is if no key type is provided, a default one- level type `ONE_LEVEL` is provided and assigned to all keys.
Pierre Le Marre f4e247e5 2025-10-10T10:10:10 Bump version to 1.12.0
Pierre Le Marre 584e0690 2025-10-08T11:55:22 keysyms: Update using latest xorgproto xorgproto commit: 81931cc0fd4761b42603f7da7d4f50fc282cecc6 Relevant MR: https://gitlab.freedesktop.org/xorg/proto/xorgproto/-/merge_requests/103
Pierre Le Marre d0e6214c 2025-10-08T09:46:43 build: Enable using default XKB root from recent xkeyboard-config The *default* XKB root directory is now set from the *most recent* xkeyboard-config installed package, in case [multiple versions] are installed in parallel. It also try to use the package-specific XKB root (if available) rather than the X11 root, respectively defined by the pkg-config variables `xkb_root` (xkeyboard-config ≥ 2.45) and `xkb_base`. If no such package is found, it fallbacks to the historical X11 directory, as previously. [multiple versions]: https://xkeyboard-config.freedesktop.org/doc/versioning/
Pierre Le Marre 7c9f8668 2025-09-30T13:10:13 tools: Add option drop unused bits
Pierre Le Marre 31900860 2025-09-30T13:05:43 keymap: Make serialization of unused items optional When compiling a keymap from text, some items may be unnecessary in the final keymap, i.e. they do not affect the keymap behavior: - unused key types; - unused keysym interpretations. Deactivate the serialization of these items *by default* and add a new flag to enable it for debugging.
Pierre Le Marre 6e45c83c 2025-09-24T20:30:40 tools: Add option to disable pretty-printing
Pierre Le Marre 345f0c67 2025-09-24T20:28:00 keymap: Make pretty-printing optional This greatly improves the keymap serialization: 1.22× speedup and about 5% less allocations. The resulting keymap is also a bit faster to parse. Another improvement is that it eases keysym names migrations (removal and additions) by using only keysym numeric values. This requires some care, i.e. `NoSymbol` must be serialized with its name and not its value 0x0, because xkbcomp and libxkbcommon < 1.12 would interpret the numeric value as `XKB_KEY_0`.
Pierre Le Marre 9131711a 2025-08-21T13:09:04 keymap: Add xkb_keymap_get_as_string2() Enable to configure the keymap serialization.
Pierre Le Marre 1eb34399 2025-08-20T22:52:17 xkbcomp: Enable using the whole keycode range In 502e9e5bff3781cba09f3b33ec030522b549f4e5 we restricted the supported keycode range in order to avoid memory exhaustion and inefficient storage in sparse arrays. This solution enabled keycodes up to 0xfff, which seemed good enough at the time. However there are huge keycodes in use in the wild, e.g. in WebOS. So let’s enable the whole keycode range by using 2 methods of storage: - “Low” keycodes (≤ 0xfff): stored contiguously as before at indexes [0..num_keys_low); fast O(1) access. - “High” keycodes (> 0xfff): stored noncontiguously at indexes [num_keys_low..num_keys); slow access via binary search.
Pierre Le Marre 4d396f6d 2025-09-16T21:05:27 tools: Added KcCGST output in YAML
Pierre Le Marre 44fad8a0 2025-09-14T10:29:41 keysyms: Update to Unicode 17.0 See: https://www.unicode.org/versions/Unicode17.0.0/
Pierre Le Marre 135b3204 2025-08-16T12:59:20 compose: Add fallback for custom locales Before this commit, loading a Compose file based on the locale would fail if the locale is not in the X11 Compose locale registry. While there are workarounds (e.g. `~/.XCompose` file or `$XCOMPOSEFILE`), it does not work if the corresponding file has `include "%L"`. This commit adds the fallback `en_US.UTF-8` in case the locale is installed but not registered in the X11 Compose locale registry. The choice is motivated by the fact that most locales use `en_US.UTF-8` anyway. Ideally we should have a mechanism to extend the Compose locale registry at the *system* level. Mechanisms at the user level (e.g. custom Compose file, environment variable) are deemed sufficient. We could still improve it by first trying to fallback to the locale without the country bits, but there is no function to do such function in the stdlib and we do not want to mess with locales manually. Unfortunately is not possible to test it in our test suite. One can still check it works following these instructions: 1. Create a custom locale, e.g. `en_XX.UTF-8`. `glibc-i18ndata` or similar package may be required to get the required files in `/usr/share/i18n/`. `sudo localedef -i en_US -f UTF-8 en_XX.UTF-8` 2. `xkbcli compile-compose --verbose --locale en_XX.UTF-8`
Pierre Le Marre 0f9cefb1 2025-07-15T12:35:34 Bump version to 1.11.0
Pierre Le Marre 3ffb7e73 2025-07-16T19:43:27 doc: Add text format sections to release notes
Pierre Le Marre 13ae4a26 2025-08-06T20:07:16 tools: Add Compose support to how-to-type - Enable Compose support by default; disable it with `--disable-compose` - Some filters are used to avoid combinatorial explosion
Pierre Le Marre 39726cac 2025-08-06T20:29:26 Add xkb_keymap_mod_get_mask2() Retrospectively, `xkb_keymap_mod_get_mask()` should have used a modifier index rather that a modifier name in its type. Since we already published a version with this API, it’s too late to change that, so instead add a new function `xkb_keymap_mod_get_mask2()`.
Pierre Le Marre 6df45124 2025-08-05T10:19:48 tools: Add --keymap to xkbcli-how-to-type It enables to load the keymap from a file or stdin instead of resolving RMLVO names. Piping is also interesting for using with `dump-keymap-*` tools.
Pierre Le Marre 09e93fa0 2025-08-06T10:12:39 tools: Enable custom keymap with interactive-{x11,wayland} Added the `--keymap` option to enable providing the keymap to use instead of the one from the display server. Implies `--local-state`. Note that the other RMLVO options do not need to be implemented, since one can simply pipe a keymap from `xkbcli compile-keymap`. The `--keymap` option is also useful for users that do not have the input permissions to access evdev API.
Pierre Le Marre 0aa54741 2025-08-04T22:46:36 tools: Add --local-state for interactive-{x11,wayland} Enable to use a *local* state machine and ignore server updates for modifiers/groups. Only key press/release and new keymap events are used.
Pierre Le Marre 29579ad4 2025-08-04T12:35:25 tools: Add --verbose to all tools Added `--verbose` to: - `xkbcli interactive-wayland` - `xkbcli interactive-x11` - `xkbcli compile-compose` - `xkbcli how-to-type`
Pierre Le Marre 1e0c5790 2025-07-23T12:09:32 keysyms: Fix XF86MediaSelectAuxiliary typo
Pierre Le Marre f5d079f5 2025-08-04T09:58:42 tools: Improve interactive events output Improved the output of events for `xkbcli interactive-*` tools: - Added `--multiline` to enable multiline event output, which provides more details and does not have formatting limitations. - Added `--uniline` to enable uniline event output. While this is the current default, future versions may switch to multiline display.
Pierre Le Marre cce63b90 2025-08-04T09:48:32 tools: Print interactive state changes `xkbcli interactive-*` tools: print detailed state change events.
Pierre Le Marre d8caabf5 2025-08-04T09:30:48 tools: Print interactive key release event `xkbcli interactive-*` tools: - Print key release events. This is particularly useful when analyzing the output sent by another person, in order to know the exact key sequence.
Pierre Le Marre e9fd95a5 2025-07-23T10:01:45 keysyms: Update using latest xorgproto xorgproto commit: 7fc33fe6d9cf0abc9b62ee976e5cb7ddcd050d1f Relevant MR: https://gitlab.freedesktop.org/xorg/proto/xorgproto/-/merge_requests/93
Pierre Le Marre a83a482c 2025-07-18T11:27:52 tools: Add variants with automatic session type detection Added: - `xkbcli-interactive` - `xkbcli-dump-keymap`
Pierre Le Marre 93818226 2025-07-15T11:34:06 Add xkb_rmlvo_builder_ref()
Pierre Le Marre b21a58d0 2025-07-01T14:52:11 Add support for all level indices to LevelN constants Note that serialization must use numbers instead of names for levels > 8, to ensure backward compatibility.
Pierre Le Marre 58373807 2025-06-27T18:21:19 keysym: Do not convert UTF-32 to deprecated keysyms Before this commit, some code points could be converted to deprecated keysym. This is incorrect, because the relevant keysyms are all deprecated because their mapping to Unicode is uncertain! Ensure that `xkb_utf32_to_keysym()` never returns deprecated keysyms, because there is either another non-deprecated keysym or in last resort we always have the correct keysym available in the Unicode keysym range.
Pierre Le Marre 3d00222e 2025-06-21T18:26:34 keymap: Add option `unlockOnPress` for LatchMods() It mirrors the feature of `SetMods()`, so that `StickyKeys` can be implemented.
Pierre Le Marre d192b3b6 2025-06-19T21:57:46 keymap: Add option `unlockOnPress` for SetMods() It enables e.g. to deactivate `CapsLock` *on press* rather than on release, as in other platforms such as Windows. It fixes a [18-year old issue] inherited from the X11 ecosystem, by extending the [XKB protocol key actions]. As it is incompatible with X11, this feature is available only using the keymap text format v2. [18-year old issue]: https://gitlab.freedesktop.org/xkeyboard-config/xkeyboard-config/-/issues/74 [XKB protocol key actions]: https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Key_Actions
Pierre Le Marre ee87f6ed 2025-06-21T19:28:53 state: Fix broken latch not honoring clearLocks=no Before this commit, breaking a latch (modifier & group) would always clear locks, even if `clearLocks=no`.
Pierre Le Marre 94d8e341 2025-06-21T13:17:16 state: Fix LatchMods mutation to SetMods or LockMods Previously we use inlined version of the corresponding filter functions of the `SetMods()` and `LockMods()` actions, but they were incomplete and did not set some fields (`priv`, `refcnt`) properly. Also, it is error-prone: it requires discipline to keep it in sync. E.g. before this commit, converting to `LockMods()` would always try to unlock `CapsLock` due to the wrong value of the `priv` field. Fixed by using the corresponding filter functions directly, so that we always mutate the filter properly, as in `xkb_filter_group_latch_func`.
Peter Hutterer 7a7a3b38 2024-02-14T09:47:15 keymap: Canonically map unmapped virtual modifiers Traditionally, *virtual* modifiers were merely name aliases for *real* modifiers (X *core* modifiers), e.g. `NumLock` was usually mapped to `Mod2` (see `modifier_map` statement). Virtual modifiers that were never mapped to a real ones had no effect on the keymap state. xkbcommon already supports the concept of “pure” virtual modifiers, i.e. virtual modifiers that are *encoded* using the full 32-bit range, not just the first 8 bits corresponding to the real modifiers. But until this commit, one had to declare such mapping *explicitly*: e.g. `virtual_modifiers M = 0x100;`. This has at least two drawbacks: - Numerical values may look quite arbitrary and are not user-friendly. It’s OK in the resulting compiled keymap, but it requires careful sync between sections when developing KcCGST files. - If the modifier is *also* mapped *implicitly* using the traditional `vmodmap`/`modifier_map`, then both mappings are OR-combined. This patch enables to automatically map unmapped virtual modifiers to their *canonical* mapping, i.e. themselves: their corresponding virtual and real modifier masks are identical: `1u << mod_index`. Since this feature is incompatible with X11, this is guarded by requiring at least keymap text format **v2**. Note that for now, canonical virtual modifiers cannot be used in an interpret action’s `AnyOf()`. An interpret action for a canonical virtual modifier must be `AnyOfOrNone()` to take effect: virtual_modifiers APureMod, …; interpret a+AnyOfOrNone(all) { virtualModifier= APureMod; action= SetMods(modifiers=APureMod); }; The above adds a virtual modifier `APureMod` for keysym `a`. It will be canonical iff it is not mapped implicitly.
Pierre Le Marre 69c3d257 2025-06-17T16:43:05 keymap: Add parameter `latchOnPress` for LatchMods() Some keyboard layouts use `ISO_Level3_Latch` or `ISO_Level5_Latch` to define “built-in” dead keys: - they do not rely on the installation of custom Compose file; - they do not clash with other layouts. However, layout projects usually want the exact same behavior on all OS, but the XKB latch behavior (often misunderstood) also acts as a *set* modifier, which is not expected. The usual behavior of a dead key on Linux, macOS and Windows is: - latch on press; - deactivate as soon as another (non-modifier) key is pressed. Added the parameter `latchOnPress` to `LatchMods()` to enable the aforementioned behavior. As it is incompatible with X11, this feature is available only using the keymap text format v2. [XKB protocol key actions]: https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Key_Actions
Pierre Le Marre c58c7df1 2025-06-17T21:05:08 Serialize multiple actions per level to VoidAction() in v1 format When using `XKB_KEYMAP_FORMAT_TEXT_V1`, multiple actions per level are now serialized using `VoidAction()`, in order to maintain compatibility with X11.
Pierre Le Marre ee50e0c9 2025-06-12T20:14:50 keymap: Add option `unlockOnPress` for LockMods() It enables e.g. to deactivate CapsLock on press rather than on release, as in other platforms such as Windows. The specification of `LockMods()` is changed to: - On key *press*: - If `unlockOnPress` is true and some of the target modifiers were *locked* before the key press, then unlock them if `noUnlock` false. - Otherwise: - add target modifiers to *depressed* modifiers; - if `noLock` is false, add target modifiers to the *locked* modifiers. - On key *release*: - If `unlockOnPress` is true and triggered unlocking on key press, do nothing. - Otherwise: - remove modifiers from the *depressed* modifiers, if no other key that affect the same modifiers is down; - if `noUnlock` is false and if any target modifiers was locked before the key press, *unlock* them. It fixes a [12-year old issue] inherited from the X11 ecosystem, by extending the [XKB protocol key actions]. As it is incompatible with X11, this feature is available only using the keymap text format v2. [12-year old issue]: https://gitlab.freedesktop.org/xorg/xserver/-/issues/312 [XKB protocol key actions]: https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Key_Actions
Pierre Le Marre d9d82355 2025-06-12T09:13:27 keymap: Add option `lockOnRelease` for LockGroup() It enables to use e.g. the combination `Control + Shift` *alone* to switch layouts, while keeping the use of `Control + Shift + other key` (typically for keyboard shortcuts). The specification of `LockGroup()` is changed to: - On key *press*: - If `lockOnRelease` is set, then key press has no effect. - Otherwise: - if the `group` is absolute, key press sets the *locked* keyboard group to `group`; - otherwise, key press adds `group` to the *locked* keyboard group. In either case, the resulting *locked* and *effective* group is brought back into range depending on the value of the `GroupsWrap` control for the keyboard. - On key *release*: - If `lockOnRelease` is not set, then key release has no effect. - Otherwise, if any other key was *pressed* after the locking key, then key release has no effect. - Otherwise, it has the same effect than a key press *without* `lockOnRelease` set. This is really useful for people coming from other platforms, such as Windows. It fixes a [20-year old issue] inherited from the X11 ecosystem, by extending the [XKB protocol key actions]. As it is incompatible with X11, this feature is available only using the keymap text format v2. [20-year old issue]: https://gitlab.freedesktop.org/xorg/xserver/-/issues/258 [XKB protocol key actions]: https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Key_Actions
Pierre Le Marre da2af4d3 2025-06-17T12:08:59 xkbcli-list: Added `layout-specific` field for options
Pierre Le Marre 0106b357 2025-06-17T12:06:32 registry: Add rxkb_option_is_layout_specific() Enable to query if an option accepts layout index specifiers to restrict its application to the corresponding layouts.
Pierre Le Marre fab9d25b 2025-06-17T11:43:22 rules: Add support for layout-specific options Enabled specifying a layout index for each option, so that it applies only if the layout matches. The layout index is specified by appending immediately after the option name the `!` specifier delimiter and then the layout index, in decimal form and 1-indexed. Note that `!` was chosen instead of the usual `:` specifier delimiter, because some options contains `:`, e.g. `grp:menu_toggle`. `!` *cannot* clash with component names, because `!` is a token in the rules files and thus cannot be used as in component names. It is also vaguely similar to `:`, compared to e.g. `@` or `#`. Example: given the following rules: ! layout[any] option = symbol * opt1 = +s1:%i l2 opt2 = +s2:%i it may result in the following configurations: | Layout | Option | Symbols | | -------- | -------- | ------------ | | `l1` | `opt1` | `+s1:1` | | `l2` | `opt1` | `+s1:1` | | `l1` | `opt2` | `` | | `l2` | `opt2` | `+s2:1` | | `l1,l2` | `opt1` | `+s1:1+s1:2` | | `l1,l2` | `opt1!1` | `+s1:1` | | `l1,l2` | `opt1!2` | `+s1:2` | | `l1,l2` | `opt2` | `+s2:2` | | `l1,l2` | `opt2!1` | `` | | `l1,l2` | `opt2!2` | `+s2:2` |
Pierre Le Marre ef6a550f 2025-06-16T15:48:25 Add xkb_keymap_new_from_rmlvo() Use the new RMLVO builder API to compile keymaps.
Pierre Le Marre da5caabb 2025-06-16T15:45:42 Add RMLVO builder API Before this commit, the API to work with RMLVO was quite minimal: it only uses raw strings from the `xkb_rule_names` struct. However: - it forces the users to deal with error-prone string formatting; - it does not enforce tying together layouts and variants; - it limits adding new features by requiring defining delimiter characters and the corresponding parsing. Added the following API: - `xkb_rmlvo_builder_new()` - `xkb_rmlvo_builder_append_layout()` - `xkb_rmlvo_builder_append_option()` - `xkb_rmlvo_builder_unref()` There is no intermediate `layout` nor `option` object, in order to to keep the API simple. The only foreseen extension is enabling configuring layout-specific options.
Pierre Le Marre f7a61da7 2025-06-10T17:33:24 doc: Update new layout count ranges
Pierre Le Marre 44c8deb2 2025-05-07T10:20:25 Introduce keymap format v2 and make it the default for parsing - Added `XKB_KEYMAP_FORMAT_TEXT_V2`. - Made `xkb_keymap_new_from_names()` use the new keymap format. - Made the tools default to the new keymap format for input. This is in preparation for changes in the parsing & state handling. For now it changes nothing.
Pierre Le Marre 82ea2915 2025-05-06T17:22:22 tools: Add options to use explicit keymap format The default output keymap format is `XKB_KEYMAP_USE_ORIGINAL_FORMAT`.
Pierre Le Marre 58397e94 2025-05-06T18:05:30 Deprecate xkb_keymap_new_from_names() - Deprecate `xkb_keymap_new_from_names()` in favor of `xkb_keymap_new_from_names2()` - Add new changelog fragment type `deprecated`. - Change documentation to use the new function.
Pierre Le Marre 1a10f858 2025-05-06T18:05:06 Add xkb_keymap_new_from_names2 This is just `xkb_keymap_new_from_names()` with an explicit keymap format.
Pierre Le Marre 39b4b670 2025-06-06T18:40:29 Support including keymap components using %-expansion and absolute path Enable to use the same `include` features than *rules* files in *keymap components*: - *`%`-expansion*: `%H` home directory, `%S` sytem root and `%E` extra. - absolute file paths. This is useful if one wants to overwrite the system file with a user config (i.e. same name, but in `~/.config/xkb`), but still include the system file: ``` // File: ~/.config/xkb/symbols/de xkb_symbols "basic" { include "%S/de(basic)" key <AB01> { [z, Z] }; key <AD06> { [y, Y] }; } ```` Without the commit, using a mere `include "de(basic)"` would result in an include loop. Refactored by using the same code for rules and keymap components.
Pierre Le Marre 7888474d 2025-05-16T14:06:18 Bump version to 1.10.0
Jules Bertholet 7a2aa9c9 2024-12-20T22:53:11 Always retain later Compose sequence in case of conflict This ensures that it is always possible to override previous definitions, for example when `include`ing the system Compose file. Signed-off-by: Jules Bertholet <julesbertholet@quoi.xyz>
Pierre Le Marre 3a8bb1a1 2025-05-16T13:13:55 compose: Fix sequence not fully overriden Previously if a new sequence did not produce a keysym or a string, the corresponding property was not overriden, possibly leaking the previous entry. - Fixed by always writting all the properties. - Also try to reuse the previous string entry, if possible, so that we avoid allocating.
Pierre Le Marre ae80b244 2025-05-14T15:08:37 tools: Add --modmaps option to compile-keymap - Remove the `ENABLE_PRIVATE_APIS` guards on modmaps printing functions, since we use no private symbols. - Copy the `--print-modmaps` options from `interactive-evdev` into `compile-keymap` and rename it to `--modmaps`. This enables a feature similar to `xmodmap -pm`.
Pierre Le Marre b4c89600 2025-05-09T15:15:10 actions: Add VoidAction(), mirroring NoSymbol/VoidSymbol. Added `VoidAction()` action to match the keysym pair `NoSymbol` / `VoidSymbol`. It enables overriding a previous action and breaks latches. This is a libxkbcommon extension. When serializing it will be converted to `LockControls(controls=none,affect=neither)` for backward compatibility. We cannot serialize it to `NoAction()`, as it would be dropped in e.g. the context of multiple actions.
Pierre Le Marre 551cca2a 2024-12-03T10:12:03 state: Add server API for updating latched and locked mods & layout Up to now, the “server state” `xkb_state` API only offered one entry point to update the server state – `xkb_state_update_key`, which reflects the direct keyboard keys state. But some updates come out-of-band from keyboard input events stream, for example, a GUI layout switcher. The X11 XKB protocol has a request which allows for such updates, `XkbLatchLockState`[^1], but xkbcommon does not have similar functionality. So server applications ended up using `xkb_state_update_state` for this, but that’s a function intended for client applications, not servers. Add support for updating the latched & locked state of the mods and layout. Note that the depressed states cannot be updated in this way -- XKB does not expect them to be updated out of band. [^1]: https://www.x.org/releases/X11R7.7/doc/kbproto/xkbproto.html#Querying_and_Changing_Keyboard_State Fixes: #310 Signed-off-by: Ran Benita <ran@unusedvar.com> Co-authored-by: Ran Benita <ran@unusedvar.com> Co-authored-by: Pierre Le Marre <dev@wismill.eu>
Pierre Le Marre 7cd1180b 2025-05-06T11:07:47 modifiers: Add xkb_keymap_mod_get_mask() Added a dedicated API to query modifier masks rather than relying on a hack using `xkb_state_update_mask` and `xkb_state_serialize_mods`. Furthermore, this hack may not work in the future if we remove virtual mods resolution in `xkb_state_update_mask` to avoid corner-cases issues.
Pierre Le Marre 9fab3948 2025-05-09T00:05:31 doc: Deprecate legacy modifiers names The following modifiers names in `xkbcommon/xkbcommon-names.h` are now deprecated: - `XKB_MOD_NAME_ALT`: use `XKB_VMOD_NAME_ALT` instead. - `XKB_MOD_NAME_LOGO`: use `XKB_VMOD_NAME_SUPER` instead. - `XKB_MOD_NAME_NUM`: use `XKB_VMOD_NAME_NUM` instead.
Pierre Le Marre 1b402b06 2025-04-06T18:45:05 doc: Introduce the “deprecated” changelog fragment type
Ran Benita a3f1a9d3 2025-02-04T20:45:38 xkbcomp/parser: enable Bison detailed syntax error It's not much, but instead of xkbcommon: ERROR: [XKB-769] (unknown file):5:25: syntax error we get xkbcommon: ERROR: [XKB-769] (unknown file):5:25: syntax error, unexpected +, expecting INTEGER which is at least a little helpful. Signed-off-by: Ran Benita <ran@unusedvar.com>
Ran Benita e6aec067 2025-04-29T17:14:01 build: drop support for byacc It doesn't support `%define parse.error detailed` which we want to use. If needed, we can probably bring back support using some macro hackery. Signed-off-by: Ran Benita <ran@unusedvar.com>
Pierre Le Marre dddffd51 2025-05-05T13:22:57 state: Fix virtual modifiers with non-real mod mapping Currently there are 2 issues with the handling of virtual modifiers in the keyboard state: 1. We assume that the input modifiers masks encode the indexes of all the modifiers of the keymap, but this is true only for the *real* modifiers (at least in xkbcommon and X11). Indeed, since the virtual modifiers *indexes* are implementation-specific, the input modifier masks merely *encode* the modifiers via their *mapping*. Consider the following keymap: ```c xkb_keymap { xkb_compat { virtual_modifiers M1 = 0x100; }; xkb_types { virtual_modifiers M2 = 0x200; }; }; ``` Now to illustrate, consider the following 2 implementation variants of libxkbcommon (assuming indexes 0-7 are the usual real modifiers): 1. Process `xkb_compat` then `xkb_types`. M1 and M2 have the respective indexes 8 and 9 and map to themselves (with the current assumption about mask denotation). 2. Process `xkb_types` then `xkb_compat`. M1 and M2 have the respective indexes 9 and 8 and map to each other. With the current `xkb_state_update_mask`, implementation 2 will swap M1 and M2 (compared to impl. 1) at each update! Indeed, we can see that `xkb_state_serialize_mods` doesn’t roundtrip via `xkb_state_update_mask`. 2. We assume that modifier masks use only bits denoting modifiers in the keymap, but when parsing the keymap we accept explicit virtual modifiers mapping of arbitrary values. E.g. if `M1` is the only virtual modifier and it is defined by: ```c virtual_modifiers M1 = 0x80000000; // 1 << (32 - 1) ``` then the 32th bit of a modifier mask input does *not* denote the 32th virtual modifier of the keymap, but merely the encoding of the mapping of `M1`. So when calling `xkb_state_update_mask`, we may discard some bits of the modifiers masks and end up with an incorrect state. These 2 issues may break interoperability with other implementations of XKB (e.g. kbvm) and make pure virtual modifiers handling fragile. We introduce the notion of *canonical state modifier mask*: the mask with the smallest population count that denotes all bits used to encode the modifiers in the keyboard state. It is equal to the bitwise OR of real modifiers mask and all the virtual modifiers mappings. This commit fixes the 2 issues by making *weaker* assumptions about the input modifier masks: 1. Modifiers may map to arbitrary values, not only real modifiers. 2. Input modifier masks merely encode modifiers via their *mapping*: - *real* modifiers map to themselves; - *virtual* modifiers map to the bitwise OR of their *explicit* mapping (via `virtual_modifiers`) and their *implicit* mapping (via keys’ real and virtual modmaps). - modifiers indexes are implementation-specific. Since the implementation before this commit also resolved virtual modifiers to their mappings, we continue doing so, but using only the bits that are *not* set in the canonical state modifier mask, so that we enable roundtrip of `xkb_state_serialize_mods` via `xkb_state_update_mask`. 3. Input modifier masks do not denote modifiers indexes (apart from real modifiers), so it is safe to discard only the bits that are not set in the canonical state modifier mask.
Pierre Le Marre dd642359 2025-05-07T00:06:10 Bump version to 1.9.2
Pierre Le Marre d5b779e1 2025-05-06T21:07:28 keymap: Fix empty compat interpretation map serialization X11’s `xkbcomp` requires at least one compat interpretation entry.
Pierre Le Marre 87f9ac76 2025-05-06T21:02:23 keymap: Fix empty compat interpretation statement serialization Statements such as `interpret VoidSymbol {};` can cannot be parsed by X11’s `xkbcomp`. Fixed by using a dummy action.
Pierre Le Marre 230b6a6a 2025-05-06T14:35:26 Fix key type map entry with unbound vmod not ignored Currently we only ignore key type map entries with non-zero mods and with a zero modifier mask. However, the XKB protocol states ([source]): > Map entries which specify unbound virtual modifiers are not considered. So we currently handle `map[Unbound]` key type map entries (all modifiers unbound) but not `map[Bound+Unbound]` entries (mix of bound and unbound modifiers). Fixed by properly checking unbound modifiers on each key type map entry. This also fixes a test that was accidentally passing. [source]: https://www.x.org/releases/X11R7.7/doc/kbproto/xkbproto.html#:~:text=Map%20entries%20which%20specify%20unbound%20virtual%20modifiers,not%20considered
Pierre Le Marre 7df431ac 2025-05-02T19:44:15 Bump version to 1.9.1
Pierre Le Marre cd512b8f 2025-05-02T19:21:09 x11: Fix capitalization transformation
Pierre Le Marre ee1a98c5 2025-04-15T20:45:27 Bump version to 1.9.0 Signed-off-by: Ran Benita <ran@unusedvar.com>
Pierre Le Marre 38322758 2025-04-12T13:06:05 doc: Include and merge modes
Pierre Le Marre 9b0b8c68 2025-04-15T19:53:28 xkbcomp: Stricter handling of default map include Before this commit, including a *default* map, i.e. without an explicit section name (e.g. `include "au"` vs `include "au(basic)"`) would match the first section of the first matching file in the XKB include paths, even if this section is not an *explicit* default map (i.e. tagged with `default`) but an *implicit* default map (i.e. the first map of the file, i.e. a weak match). It makes user configuration risky: say a user wants to create a custom version `au(custom)` of the `au` layout: - `./config/xkb/symbols/au`: custom layout in section “custom”. - `/usr/share/X11/xkb/symbols/au`: system layout, with *default* section “basic”. In this setup *any* layout that imports the default map from `au` would in fact import the *implicit* default map `au(custom)` instead of the *explicit* default map `au(basic)`. This incorrect behavior may thus break setups with multiple layouts. This is especially true for symbols files such as: `pc`, `us` or `latin`. Fixed by trying harder to found the exact default map, defaulting to the old behavior (weak match) only if no *explicit* default map (exact match) has been found in the XKB include paths.
Pierre Le Marre 9ede705b 2025-04-13T09:50:18 state: Capitalization transformation in xkb_state_key_get_syms Previously `xkb_state_key_get_syms()` did not perform capitalization tranformation, while `xkb_state_key_get_one_sym()` does perform it. This is unfortunate if we want to promote the use of multiple keysyms per levels. The API make it difficult to change now though: we return a pointer to an immutable array rather than filling a buffer. While we could use an internal buffer in `xkb_state`, this option would limit the API to *sequential* calls of `xkb_state_key_get_syms()` or require some buffer handling (e.g. rotation). Instead we now store the capitalization directly in `xkb_level`. We modified `xkb_level` like so (see below for discussion about the size): ```diff struct xkb_level { - unsigned int num_syms; + uint16_t num_syms; - unsigned int num_actions; + uint16_t num_actions; + union { + /** num_syms == 1: Upper keysym */ + xkb_keysym_t upper; + /** num_syms > 1: Indicate if `syms` contains the upper case + * keysyms after the lower ones. */ + bool has_upper; + }; union { xkb_keysym_t sym; /* num_syms == 1 */ xkb_keysym_t *syms; /* num_syms > 1 */ } s; union { union xkb_action action; /* num_actions == 1 */ union xkb_action *actions; /* num_actions > 1 */ } a; }; ``` - When `level.num_syms` <= 1, we store the upper keysym in `level.upper`. - Else if there no cased syms, we set `level.has_upper` to false. - Else if there are some cased syms, we set `level.has_upper`` to `true` and we double the original size of `level.s.syms`, but *without* modifying `level.num_syms`. We then append the transformed keysyms right after the original ones, so that we can access them by a simple pointer operation: `level.s.syms + level.num_syms`. The memory footprint is *unchanged*, thanks to the reduced fields for actions and keysyms counts.
Pierre Le Marre 66f71890 2025-03-31T08:01:29 symbols: Enable writing keysyms list as UTF-8 strings Each Unicode code point of the string will be translated to their respective keysym, if possible. An empty string denotes `NoSymbol`. When such conversion is not possible, this will raise a syntax error. This introduces the following syntax: ```c // Empty string = `NoSymbol` key <1> {[""]}; // NoSymbol // Single code point = single keysym key <2> {["é"]}; // eacute // String = translate each code point to their respective keysym key <3> {["sßξك🎺"]}; // {s, ssharp, Greek_xi, Arabic_kaf, U1F3BA} // Mix string and keysyms key <4> {[{"ξ", Greek_kappa, "β"}]}; // { Greek_xi, Greek_kappa, Greek_beta} ``` It can also be used wherever a keysym is required, e.g. in `interpret` and `modifier_map` statements. In these cases a single keysym is expected, so the string should contain *exactly one* Unicode code point.
Pierre Le Marre ead3ce77 2025-03-28T21:44:27 scanner: Enable LRM and RLM marks for BiDi text Enable displaying bidirectional text in XKB files using: - U+200E LEFT-TO-RIGHT MARK - U+200F RIGHT-TO-LEFT MARK We now parse these marks as white space. As such, they are dropped; note that a later serialization may not display correctly without the marks, although it will parse. References: - https://www.w3.org/International/articles/inline-bidi-markup/uba-basics - https://www.w3.org/International/questions/qa-bidi-unicode-controls - https://www.unicode.org/reports/tr31/#Whitespace - https://www.unicode.org/reports/tr55/
Pierre Le Marre bc3e464b 2025-04-09T12:35:05 keysyms: Fix Unicode handling - `xkb_utf32_to_keysym`: Allow [Unicode noncharacters]. There is no requirement to drop them and this would be the only function of our API doing so. From the Unicode Standard 16.0, section 23.7 “Noncharacters”: > Applications are free to use any of these noncharacter code points > internally. They have no standard interpretation when exchanged > outside the context of internal use. However, they are not illegal > in interchange, nor does their presence cause Unicode text to be > ill-formed. > If a noncharacter is received in open interchange, an application is > not required to interpret it in any way. It is good practice, > however, to recognize it as a noncharacter and to take appropriate > action, such as replacing it with `U+FFFD` REPLACEMENT CHARACTER, > to indicate the problem in the text. The key part is: > an application is not required to interpret it in any way Since we handle the reverse conversion with `xkb_keysym_to_utf32` just fine, I do not see a good motivation to keep this asymmetry. This is the only function with a special case for these code points. - `xkb_keysym_from_name`: - Unicode format `UNNNN`: allow control characters C0 and C1 and use `xkb_utf32_to_keysym` for the conversion when `NNNN < 0x100`, for backward compatibility. - Numeric hexadecimal format `0xNNNN`: *unchanged*. Contrary to the Unicode format, it does not normalize any keysym values in order to enable roundtrip with `xkb_keysym_get_name`. Also added tests to ensure various properties and consistency. Note about *surrogates*: they are valid valid *code points* but invalid Unicode *scalar values*, i.e. they cannot be encoded in any Unicode encoding form (UTF-8, UTF-16, UTF-32). So their corresponding Unicode keysyms are valid, but: - cannot be used as input of `xkb_keysym_to_utf32` nor `xkb_keysym_to_utf8` - cannot result as output of `xkb_utf32_to_keysym`. Otherwise they are valid e.g. in the Unicode keysym notation. [Unicode noncharacters]: https://en.wikipedia.org/wiki/Universal_Character_Set_characters#Noncharacters
Pierre Le Marre 36442baa 2025-04-03T15:01:46 xkbcomp: Support multiple actions in interpret Before this commit we supported multiple actions per level, but not in *interpret* statements. Let’s fix this asymmetry, so we can equivalently assign all actions sets either implicitly or explicitly.
Pierre Le Marre 3d79f459 2025-03-29T11:46:34 xkbcomp: Add Unicode code point escape sequence \u{NNNN} Unicode code point escape sequences `\u{NNNN}` are replaced with the UTF-8 encoding of their corresponding code point `U+NNNN`, if legal. Supported Unicode code points are in the range `1‥0x10ffff`. Note that we will reject the `U+0000` NULL code point, as we reject it in the octal escape sequence `\0`. This is intended mainly for the upcoming feature to write keysyms as UTF-8 encoded strings. It can be used for various reasons: - avoid encoding issues; - avoid issue with font rendering (e.g. Asian scripts); - make white space or zero-width characters more readable.
Pierre Le Marre 7d91a753 2025-03-29T12:24:39 xkbcomp: Enable xkbcomp-style octal escape sequences Xorg xkbcomp only parses octal sequences with `\0`, while xkbcommon does not force the `0` prefix of the numeric part. However, we only parsed up to to 3 digits, which does not allow to parse e.g. `\0377` while `\377` parses fine. Fixed by parsing up to 4 octal digits, while checking the result fits into a byte.
Pierre Le Marre aa8b572e 2025-03-29T12:04:26 keymap serialization: Ensure escaping relevant chars Previously we would write characters without any escaping in some cases (e.g.: names of indicators, types and groups). E.g. the string "new\nline" would be serialized as: "new line" which would raise a syntax error if parsed. Fixed by escaping any string that was not escaped after parsing (e.g. the section names are safe already).
Pierre Le Marre 44480f7c 2025-04-01T08:28:02 xkbcomp: Enable lists of keysyms and actions {} and {a} Motivations: - Follow the principle of least astonishment; - Ensure consistency; - Enhance the use of custom defaults; - Facilitate the tests. There is some ambiguity because we use `{}` to denote both an empty list of keysyms and an empty list of actions. But as soon as we get a keysym or an action, we know whether it is a `MultiKeySymList` or a `MultiActionList`. So we just count the `{}` at the *beginning* using `NoSymbolOrActionList`, then replace it by the relevant count of `NoSymbol` or `NoAction()` once the ambiguity is solved. If not, this is a list of empties of *some* type: we drop those empties and delegate the type resolution using `ExprEmptyList()`.
Pierre Le Marre e09cbe66 2025-04-02T10:46:06 symbols: Fix handling of empty keys Before this commit, the following symbols: ```c xkb_symbols { virtual_modifiers M1, M2; key <A> {}; key <B> { [] }; key.vmods = M1; key <C> {}; key <D> { vmods = M2 }; }; ``` would be equivalent to: ```c xkb_symbols { virtual_modifiers M1,M2; key <B> { [ NoSymbol ] }; }; ``` `<B>` entry could be skipped but is harmless. However, `<C>` and `<D>` are missing, which would lead to the mapping resolution of `M1` and `M2` failing. After this commit, it is equivalent to: ```c virtual_modifiers M1,M2; key <C> { vmods = M1 }; key <D> { vmods = M2 }; ``` Empty keys are skipped entirely, but any explicit field: - is taken into account: previously they would be skipped if there were no group; - forces the key to be printed at serialization.
Pierre Le Marre 2e0245f8 2025-04-02T10:45:44 xkbcomp: Enable more empty lists - Empty `interpret` - Empty key `type` - Empty `indicator` Motivations: - Follow the principle of least astonishment; - Ensure consistency; - Enhance the use of custom defaults; - Facilitate the tests.
Pierre Le Marre 6881fb32 2025-04-01T08:28:02 xkbcomp: Drop trailing NoSymbol and NoAction() This brings us closer to what `xkbcomp` outputs. One should use the explicit `VoidSymbol` instead of `NoSymbol`, in order to avoid dropping empty levels. This may affect keys that rely on an *implicit* key type. Example: - Input: ```c key <> { [a, A, NoSymbol] }; ``` - Compilation with xkbcommon \< 1.9.0: ```c key <> { type= "FOUR_LEVEL_SEMIALPHABETIC", [a, A, NoSymbol, NoSymbol] }; ``` - Compilation with xkbcommon ≥ 1.9.0: ```c key <> { type= "ALPHABETIC", [a, A] }; ```
Pierre Le Marre 343c49cc 2025-03-30T09:54:02 doc: Optional components
Pierre Le Marre 23598fa1 2025-03-25T22:52:06 Enable merge mode “replace” in include statements Previously only the merge modes “override” and “augment” were available in include statements, using the prefix ‘+’ and ‘|’ respectively. While on one hand `replace` include statement can be used in keymap files, on the other hand *rules* files have no way to express the *replace* mode. This commit enables the merge mode “replace” using the prefix `^`. This prefix was chosen due to its similarity with the `XOR` bit operator, which convey *mutual exclusion*. Other candidates: - `!` conveys some kind of higher precedence, akin to CSS `!important`. But it conflicts with the section header `!`, which is a token in the current parser. It would require special handling, not worth it. It also convey the meaning of negation, which is confusing. - `&` has the advantage of not corresponding to a token in the rules parser. `^` seems however to stand out more and it is less likely to trigger erroneous comparison with `|` and `&` bit operators.
Pierre Le Marre 6fc6e64b 2025-03-26T10:35:22 rules: Added extended wild cards <none>, <some> and <any> Added the following wild cards to the rules file syntax, in addition to the current `*` legacy wild card: - `<none>`: Match *empty* value. - `<some>`: Match *non-empty* value. - `<any>`: Match *any* (optionally empty) value. Its behavior does not depend on the context, contrary to the legacy wild card `*`. This will enable writing much simpler rules, see [!764] for an example of tricky rules in the `xkeyboard-config` project, that would benefit from the new wild cards. [!764]: https://gitlab.freedesktop.org/xkeyboard-config/xkeyboard-config/-/merge_requests/764 The verbose wild cards are preferred to single characters: - More intuitive: self-explanatory. - Does not steal syntax from other token. - Extensible syntax, should we need it. A previous proposal used the characters (`!`, `+`, `?`) for their similarity with the corresponding syntax of regular expressions (negative assertion & quantifiers), in line with `*`. But `!` is not that intuitive after all and conflict with its role as section header. Furthermore, `+` is also used as a merge mode. Finally, nothing beats whole short words for readability.
Pierre Le Marre 500b260b 2025-03-28T09:38:58 xkbcomp: Fix parser failure on floating-point numbers Before this commit we used `strtold`, which depends on the locale. But the XKB syntax is fixed and uses a period as decimal separator. So ensure the syntax is correct without relying on `strtold` and truncate the result, as the parser does not use floating-point numbers.
Pierre Le Marre d7e112fe 2025-03-29T19:44:13 registry: Added support for libxml2 2.14+ `libxml2-2.14+` now disallows parsing trailing `NULL` bytes, so don’t. This is backward-compatible with previous versions of the library.
Pierre Le Marre cc95f217 2025-03-25T11:15:45 xkbcomp: Fix whichGroupState serialization This indicator field was previously looked up in the wrong table, resulting the erroneous serialization `(null)`.
Pierre Le Marre 955eef14 2025-03-28T06:30:05 tools: Ensure to honor user locale This is just good practice, but it is also necessary if we want to facilitate the discovery of issues with locales in libxkbcommon.
Pierre Le Marre 275ffa66 2025-03-13T21:28:35 tools: Make --kccgst xkbcli-compile-keymap option public The new public option `--kccgst` enables to display the result of RMLVO resolution to KcCGST components. This option has the same function than `setxkbmap -print`. This is particularly useful for debugging issues with the rules. Before this commit it was a private API. This commit enables us to remove the *internal* version of `xkbcli-compile-keymap`.
Pierre Le Marre 8e92f25e 2025-03-13T21:26:59 rules: Added xkb_components_names_from_rules() This is mainly for debugging purposes and to enable displaying KcCGST values from RMLVO resolution in `xkbcli compile-keymap --kccgst`.
Pierre Le Marre b3465081 2025-03-12T00:20:39 Bump version to 1.8.1 and update changelog
Julian Orth cb3565b1 2025-03-07T17:59:33 keymap: Fix segfault due to invalid group wrapping The modular arithmetic is incorrect for negative values, e.g. for num_groups = 1. It triggers a segfault for the following settings: - layouts count (per key or total) N: `N > 0`, and - layout index n: `n = - k * N` (`k > 0`) % returns the *remainder* of the division, not the modulus (see C11 standard 6.5.5 “Multiplicative operators”: a % b = a - (a/b)*b. While both operators return the same result for positive operands, they do not for e.g. a negative dividend: remainder may be negative (in the open interval ]-num_groups, num_groups[) while the modulus is always positive. So if the remainder is negative, we must add `num_groups` to get the modulus. Fixes: 67b03cea ("state: correctly wrap state->locked_group and ->group") Signed-off-by: Julian Orth <ju.orth@gmail.com> Co-authored-by: Julian Orth <ju.orth@gmail.com> Co-authored-by: Pierre Le Marre <dev@wismill.eu>
Pierre Le Marre 5cfd36ab 2025-02-14T10:35:49 tools: Do not load names from the environment by default Our tools are debugging tools and as such we need to have complete control to be able to reproduce setups. This is not currently the case, as we do not use `XKB_CONTEXT_NO_ENVIRONMENT_NAMES` by default nor can we set it. So it is very easy to forget about the various `XKB_DEFAULT_*` environement variables for the default RMLVO values, then to get puzzled by unexpected results. Added to that, these environment variables do not work correctly in `xkbcli-compile-xeymap`: calling the tool without RMLVO values will use these variables only if the RMLVO values are set explicitly empty or if the various *constants* `DEFAULT_XKB_*` are empty. This is unexpected, as the environment variables should *always* be used unless: - `XKB_CONTEXT_NO_ENVIRONMENT_NAMES` is used (not the case here); - the variable is empty; in this case the constants `DEFAULT_XKB_*` are used. Fixed by the following *breaking change*: make the tools use `XKB_CONTEXT_NO_ENVIRONMENT_NAMES` *by default*, unless the new `--enable-environment-names` option is used. We also make `rmlvo` incompatible with `--enable-environment-names` for now in the public tool, as else it requires a private API.
Ran Benita e120807b 2025-01-29T15:35:22 Update license notices to SDPX short identifiers + update LICENSE Fix #628. Signed-off-by: Ran Benita <ran@unusedvar.com>