changes/api


Log

Author Commit Date CI Message
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 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 76740e0c 2025-01-30T14:21:00 Bump version to 1.8.0 and update changelog
Pierre Le Marre c85c9bdc 2025-01-27T17:15:06 symbols: Allow levels with different keysyms and actions counts Contrary to groups, there is no reason for levels to restrict the same count of keysyms and actions.
Pierre Le Marre 27ac30b2 2025-01-27T17:13:44 symbols: Normalize levels by dropping NoSymbol & NoAction
Pierre Le Marre b0d9a790 2025-01-15T12:03:10 vmods: Fix explicit vmods not dumped
Jules Bertholet 3fdd822d 2025-01-16T02:21:29 state: Fix mods not being independently cleared (#584) The modifiers filters should ensure minimal interaction between them, but currently the Latch mod filters are overzealous and mess with the mods from other filters set to be cleared, resulting in some modifiers permanently set. Fixed by clearing mods properly with `OR` rather than direct setting of `state::clear_mods`. While we are at it, `state::set_mods` should be `OR`ed as well. This should not have any impact for now, but this is more future-proof. Fixes #583 Co-authored-by: Jules Bertholet <julesbertholet@quoi.xyz> Co-authored-by: Pierre Le Marre <dev@wismill.eu>
Pierre Le Marre 6c6dbf32 2025-01-07T11:19:30 state: Fix LatchGroup action with latchToLock disabled A `LatchGroup` action with the `latchToLock`` option disabled can apply its latch effect multiple times.
Pierre Le Marre 325ba10e 2025-01-07T16:27:50 state: Fix LEDs driven by the group state When the indicator field `whichGroupState` is set to `Base` or `Latched`, the group masks should be considered only as boolean values as per the XKB specification.
Pierre Le Marre 93b75c63 2024-12-22T17:49:24 x11: Keep level when the keysym is undefined but not the action When getting the keymap from X11, the following: ``` key <AD01> { actions=[SetGroup(2)] }; ``` is currently converted to: ``` key <AD01> { }; ``` This commit fixes dropping a defined action when the keysym is undefined
Pierre Le Marre b9b4ab47 2024-12-09T09:21:01 keysyms: Add sharp S upper case mapping exception The case mapping `ssharp` ß ↔ `U1E9E` ẞ was added in 13b30f4f0dccc08dfea426d73570b913596ed602 but was broken: - For the lower case mapping it returned the keysym `0x10000df`, which is an invalid Unicode keysym. - For the upper case mapping it returned the upper Unicode code point rather than the corresponding keysym. It did accidentally enable the detection of alphabetic key type for the pair (ß, ẞ) though. However this detection was accidentally removed in 5c7c79970a2800b6248e829464676e1f09c5f43d (v1.7) with an attempt to fix the wrong keysym case mapping. Finally both the *lower* case mapping and the key type detection were fixed for good when we implemented the complete Unicode simple case mappings and corresponding tests in e83d08ddbc9851944c662c18e86d4eb0eff23e68. However, the *upper* case mapping `ssharp` → `U1E9E` remained disabled. Indeed, ẞ is a relatively recent addition to Unicode (2008) and had no official recommendation, until recently. So while the lower mapping ẞ→ß exists in Unicode, its converse upper mapping does not. Yet since 2017 the Council for German Orthography (Rat für deutsche Rechtschreibung) recommends[^1] ẞ as the capitalization of ß. Due to its stability policies, the Unicode Character Database (UCD) that we use to generate our keysym case mappings (via ICU) cannot update the simple case mapping of ß. Discussions are currently ongoing in the Unicode mailing list[^2] and CLDR[^3] about how to deal with the new recommended case mapping. However, the discussions are oriented on text-processing and compatibility mappings, while libxkbcommon is on a rather lower level. It seems that the slow adoption of ẞ is partly due to the difficulty to type it. Since ẞ is used only for ALL CAPS casing, the expectation is to type it using CapsLock. While our detection of alphabetic key types works well[^4] for the pair (ß,ẞ), the *internal capitalization* currently does not work and is fixed by this commit. Added the ß → ẞ upper mapping: - Added an exception in the generation script - Fixed tests - Added documentation of the exceptions in `xkbcommon.h` - Added/updated log entries [^1]: https://www.rechtschreibrat.com/regeln-und-woerterverzeichnis/ [^2]: https://corp.unicode.org/pipermail/unicode/2024-November/011162.html [^3]: https://unicode-org.atlassian.net/browse/CLDR-17624 [^4]: Except libxkbcommon 1.7, see the second paragraph.
Pierre Le Marre e0130e30 2024-11-18T20:08:56 state: Add vmod support for xkb_state_mod_mask_remove_consumed
Pierre Le Marre 5fbc0ec7 2024-10-14T16:05:52 state: Support querying whether virtual mods are consumed Previously it was not possible to query the status of virtual modifiers with the following functions: - `xkb_state_mod_index_is_consumed` - `xkb_state_mod_index_is_consumed2` Note that it may *overmatch* if some modifier mappings overlap. For example, the default “us” PC layout maps both “Alt” and “Meta” to the real modifier “Mod1”; thus “Mod1”, “Alt” and “Meta” modifiers will return the same result with these functions.
Pierre Le Marre 31a841ae 2024-10-14T16:05:35 state: support querying whether virtual modifiers are active Previously it was not possible to query the status of virtual modifiers with the following functions: - `xkb_state_mod_index_is_active` - `xkb_state_mod_indices_are_active` - `xkb_state_mod_name_is_active` - `xkb_state_mod_names_are_active` Note that it may *overmatch* if some modifier mappings overlap. For example, the default “us” PC layout maps both “Alt” and “Meta” to the real modifier “Mod1”; thus “Mod1”, “Alt” and “Meta” modifiers will return the same result with these functions.
Pierre Le Marre 2ba9daf1 2024-09-23T16:20:37 mods: Add more built-in names Added support for the following virtual modifiers: - `Alt` - `Meta` - `NumLock` - `Super` - `Hyper` - `LevelThree` - `LevelFive` - `ScrollLock`
Pierre Le Marre 43b26bd7 2024-11-29T08:51:41 keysyms: Update to Unicode 16.0
Sebastian Keller a47961b1 2024-10-12T16:43:46 registry: Restore default libxml2 error handler after parsing Leaving the custom error handler could have resulted in a crash after the context has been freed. Closes: https://github.com/xkbcommon/libxkbcommon/issues/529
Pierre Le Marre b1da948a 2024-10-08T19:43:18 symbols: Add doc for multiple actions
Pierre Le Marre 7c4c718b 2024-09-30T06:13:38 Allow only the first group in symbols sections when using RMLVO Currently `xkb_keymap_num_layouts` may return a greater number than the number of layouts configured using RMLVO, because we allow symbols sections to define various groups per key. This is unintuitive and kind of buggy: groups should be added via rules by setting an explicit `:n` modifier. Fix: when parsing a keymap using RMLVO resolution: - Get the expected layouts count from the resulting KcCGST. - Drop the groups after the first one in included symbols sections. This will ensure that a symbol section can only define one group per key. Notes: - Compiling a keymap string directly is unaffected. - RMLVO resolution may still produce more groups than the input layouts. Indeed, some legacy rules in xkeyboard-config rely on this to insert automatically a US layout before the given non-Latin one, resulting in two layouts while only one was given.
Pierre Le Marre 948f7a59 2024-10-09T08:34:27 symbols: Skip interprets only for groups with explicit actions Previously setting explicit actions for a group in symbols files made the parser skip compatibility interpretations for the corresponding *whole* key, so the other groups with *no* explicit actions could result broken on some levels. In the following example, `<RALT>` would have an action on group 2, because it is explicit, but none on group 1 because interpretation are also skipped there as a side effect: ```c key <RALT> { symbols[1]= [ ISO_Level3_Shift ], symbols[2]= [ ISO_Level3_Shift ], actions[2]= [ SetMods(modifiers=LevelThree) ] }; ``` Fixed by skipping interpretations *only* for groups with explicit actions. We still set `key->explicit |= EXPLICIT_INTERP` if at least one group has explicit actions. In such case, when dumping a keymap, we will write explicit actions for *all* groups, in order to ensure that X11 and previous versions of libxkbcommon can parse the keymap as intended. One side effect is that no interpretation will be run on this key anymore, so we may have to set some extra fields explicitly: repeat, virtualMods. Thus the previous example would be bumped as: ```c key <RALT> { repeat= No, symbols[1]= [ ISO_Level3_Shift ], actions[1]= [ SetMods(modifiers=LevelThree,clearLocks) ], symbols[2]= [ ISO_Level3_Shift ], actions[2]= [ SetMods(modifiers=LevelThree) ] }; ```
Pierre Le Marre 1d897502 2024-10-04T08:09:28 keysyms: Update using latest xorgproto xorgproto commit: d7ea44d5f04cc476dee83ef439a847172f7a6bd1 Relevant MR: https://gitlab.freedesktop.org/xorg/proto/xorgproto/-/merge_requests/91
Pierre Le Marre 4ea9d431 2023-11-16T17:12:03 rules: Add support for :all qualifier Some layout options require to be applied to every group to maintain consistency (e.g. a group switcher). Currently this must be done manually for all layout indexes. This is error prone and prevents the increase of the maximum group count. This commit introduces the `:all` qualifier for KcCGST values. When a rule with this qualifier is matched, it will expands the qualified value (and its optional merge mode) for every layout, e.g. `+group(toggle):all` (respectively `|group(toggle)`) would expand to `+group(toggle):1+group(toggle):2` (respectively `|group(toggle):1|group(toggle):2`) if there are 2 layouts, etc. If there is no merge mode, it defaults to *override* `+`, e.g. `x:all` expands to `x:1+x:2+x:3` for 3 layouts. Note that only the qualified *value* is expanded, e.g. `x+y:all` expands to `x+y:1+y:2` for 2 layouts. `:all` can be used in combination with special layout indexes. Since this can lead to an unexpected behaviour, a warning will be raised.
Pierre Le Marre cdafba4f 2024-09-24T15:23:16 rules: Add support for index ranges There is a lot of repetition in the current rules files provided by xkeyboard-config, because the MLVO mappings need to match on the exact layout/variant index. This also prevents to increase the number of maximum groups, because it does not scale. We introduces the following new special layout/variant indexes: - “single”: matches a single layout; same as with no index. - “first”: matches the first layout/variant, no matter how many layouts are in the RMLVO configuration. It allows to merge `layout` and `layout[1]` patterns. - “later”: matches all but the first layout. This is an index range. - “any”: matches layout at any position. This is an index range. We also introduces the new `%i` expansion, which correspond to the index of the matched layout in a mapping with an index range. Example: layout[later] = symbols my_layout = +my_symbols:%i * = +%l[%i]:%i Let’s have a look at concrete examples from xkeyboard-config: ! model layout = symbols * * = pc+%l%(v) ! model layout[1] = symbols * * = pc+%l[1]%(v[1]) ! model layout[2] = symbols * * = +%l[2]%(v[2]) ! model layout[3] = symbols * * = +%l[3]%(v[3]) ! model layout[4] = symbols * * = +%l[4]%(v[4]) ! layout option = symbols * grp:toggle = +group(toggle) ! layout[1] option = symbols * grp:toggle = +group(toggle):1 ! layout[2] option = symbols * grp:toggle = +group(toggle):2 ! layout[3] option = symbols * grp:toggle = +group(toggle):3 ! layout[4] option = symbols * grp:toggle = +group(toggle):4 With this commit we can now simplify it into: ! model layout[first] = symbols * * = pc+%l[%i]%(v[%i]) ! model layout[later] = symbols * * = +%l[%i]%(v[%i]):%i ! layout[any] option = symbols * grp:toggle = +group(toggle):%i The latter rule will work even if we increase XKB_MAX_GROUPS, whereas the former would require to add the missing entries for the new groups. In order to maintain consistent rules, we now disallow layout and variant to have different indexes. For example, the following mapping are now invalid: - layout variant[1] - layout[1] variant[2] - layout[1] variant - layout[first] variant[1] - layout[first] variant - layout variant[any] - etc.
Pierre Le Marre 7697c712 2024-09-16T16:09:11 rules: Resolve relative include statements using XKB paths Contrary to keymap files, the `! include` statement in rules does not lookup include paths added to `xkb_context`. So it is not possible e.g. to import another file in the same folder without using an absolute path. - Added path utils: `is_absolute(path)`. - Added XKB paths lookup to enable e.g. `! include evdev` to work. - Added test.
Pierre Le Marre 44df6eee 2024-09-23T07:27:48 Add new warnings for deprecated keysyms Add 2 new warnings: - Deprecated keysym name (typo, historical alias, etc.); - Deprecated keysym (all names and forms). Guard deprecated keysym tests with verbosity level ≥2, so they are run only when actually needed.
Pierre Le Marre e4269202 2024-09-20T10:41:00 keysyms: Fix off-by-one XKB_KEYSYM_NAME_MAX_SIZE The constant did not account for the terminating `NULL` byte and this was sadly not caught by the tests. Fixed the invalid value, the corresponding script and the tests.
Pierre Le Marre 05ba96db 2024-08-20T16:41:38 rules: Fix wild card handling The handling of wild card `*` is different in libxkbfile and X server: wild card matches empty strings for model and option but not for layout nor variant, while in libxkbcommon wild cards always match empty strings. See: - https://gitlab.freedesktop.org/xorg/lib/libxkbfile/-/blob/bf985c68acb1244f51ec91414532a2347fbc1c4c/src/maprules.c#L687 - https://gitlab.freedesktop.org/xorg/lib/libxkbfile/-/blob/bf985c68acb1244f51ec91414532a2347fbc1c4c/src/maprules.c#L712 The difference of handling between the components is unfortunately not documented, but we should follow the behavior of the original implementations for consistency. - Fixed by implementing the same behavior than libxkbfile. - Added tests and fixed failing tests. - Improve the documentation of rules to highlight the special behavior.
Martin Rys 9af1f9f2 2024-09-02T14:18:21 Add XKB_LED_NAME_COMPOSE and XKB_LED_NAME_KANA
Pierre Le Marre e9bd7de4 2024-07-04T16:22:13 state: Add support for group latch action Surprisingly, the latch group action was not yet implemented. Added tests to ensure we get the tricky bits right.
Pierre Le Marre e83d08dd 2024-02-23T17:10:15 keysyms: Fast and complete case mappings (Unicode 15.1) The current code to handle keysym case mappings is quite complex and slow. It is also incomplete, as it does not cover recent Unicode database. Finally, it does not handle title case correctly. It would be easier if we were to use only a lookup table, but a trivial implementation would lead to a huge array: the cased characters range from `U+0041` to `U+`1F189, i.e. a span of 127 304 elements. Thus we need some tricks to compress the lookup table. We based our work on the post: https://github.com/apankrat/notes/blob/3c551cb028595fd34046c5761fd12d1692576003/fast-case-conversion/README.md The compression algorithm is roughly: 1. Compute the delta between the characters and their mappings. 2. Split the delta array in chunk of a given size. 3. Rearrange the order of the chunks in order to optimize consecutive chunks overlap. 4. Create a data table with the reordered chunks and an index table that maps the original chunk index to its offset in the data table. The compression algorithm is then applied a second time to the previous index table. The complete algorithm optimizes the two chunk sizes in order to get the lowest total data size. The mappings were generated using CPython 3.12.4, PyICU 2.13, PyYaml 6.0.1 and ICU 75.1. Also: - Added explicit list of named keysyms and their case mappings. - Added benchmark for case mappings. - Rework ICU tests. Note: 13b30f4f0dccc08dfea426d73570b913596ed602 introduced a fix for sharp S `U+00DF`. With the new implementation, the *conversion* functions `xkb_keysym_to_{lower,upper}` leave it *unchanged*, while the *predicate* functions `xkb_keysym_is_{lower,upper_or_title}` produce the expected results: ```c xkb_keysym_to_upper(XKB_KEY_ssharp) == XKB_KEY_ssharp; xkb_keysym_to_lower(XKB_KEY_ssharp) == XKB_KEY_ssharp; xkb_keysym_to_lower(XKB_KEY_Ssharp) == XKB_KEY_ssharp; xkb_keysym_is_lower (XKB_KEY_ssharp) == true; xkb_keysym_is_upper_or_title(XKB_KEY_Ssharp) == true; ```
Pierre Le Marre addf73c5 2024-07-12T09:17:34 keysyms: Require only 5 bytes for UTF-8 encoding Require only 5 bytes for the buffer of `xkb_keysym_to_utf8`, as UTF-8 encodes code points on up to 4 bytes + 1 byte for the NULL-terminating byte. Previous standard [RFC 2279] (1998) required up to 6 bytes per code point, but has been superseded by [RFC 3629] (2003). [RFC 2279]: https://datatracker.ietf.org/doc/html/rfc2279 [RFC 3629]: https://datatracker.ietf.org/doc/html/rfc3629
Pierre Le Marre 737706fe 2024-03-07T10:08:16 doc: Use towncrier to handle release notes Towncrier is a utility to produce useful, summarized news files. See: - https://pypi.org/project/towncrier/ - https://towncrier.readthedocs.io Custom configuration for xkbcommon: - New fragments are located in the `changes` directory. - 3 sections: - API: `changes/api` - Tools: `changes/tools` - Build System: `changes/build` - 3 news fragments: - Breaking changes: `.breaking` - New: `.feature` - Fixes: `.bugfix` `NEWS` is renamed to `NEWS.md` because the tool requires `.md` extension to write in markdown format.