|
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.
|
|
fcc95275
|
2025-10-17T11:56:48
|
|
xkbcomp: Rename fallback key type to ONE_LEVEL
This is the name of this canonical key type in the XKB protocol.
|
|
837dbb46
|
2025-10-09T18:10:22
|
|
Fix C11 syntax
Label followed by declaration requires C23.
|
|
6876e99d
|
2025-10-09T11:27:18
|
|
keymap: Fixed action comparison
Before this commit there were 2 issues in action comparison:
- Private actions comparison wrongly compared pointers;
- Custom action types were mistakenly interpreted as errors and thus
always failed comparison.
Also added assertions on the action type enum so that the relevant code
must be updated when the enum changes.
|
|
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.
|
|
e3ef7a47
|
2025-09-24T20:29:22
|
|
keymap: Warn for numeric keysyms only at high verbosity
Now that the default serialization uses the numeric format for keysyms,
the warning should be enabled only at maximum verbosity.
|
|
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`.
|
|
9131711a
|
2025-08-21T13:09:04
|
|
keymap: Add xkb_keymap_get_as_string2()
Enable to configure the keymap serialization.
|
|
181bc9ec
|
2025-09-24T20:10:00
|
|
xkbcomp: Fix numeric keysym parsing
Keysyms written as single decimal digits are interpreted in the range
`XKB_KEY_0`..`XKB_KEY_9`, consistent with the general interpretation
`<name>` -> `XKB_KEY_<name>`, e.g.:
- `1` → `XKB_KEY_1`
- `a` → `XKB_KEY_a`
However, before this commit integers in the range 0..9 in *any format*
were treated as digit keysyms, which is wrong if the number is written
with 2+ characters. E.g. the following were wrongly treated as the
keysym digit `XKB_KEY_1`: `01`, `0x1`.
Fixed by introducing a new token type to handle this corner case.
This is a preparatory work to enable serializing keysyms as numbers.
|
|
b09aa7c6
|
2025-09-21T19:05:27
|
|
xkbcomp: Drop the key name LUT after compilation
Since it is not usual to lookup for keys by their names, we can drop it
to save allocations (about 2KiB on usual keymaps).
We use an union of the LUT with the aliases array and try to reuse the
memory allocated by the LUT. We only do so if the space is trivially
available: either before the first alias entry or after the last entry,
which is possible in practice, so that we get the best performance. Else
we allocate a new array.
|
|
4421a358
|
2025-09-22T10:49:18
|
|
xkbcomp: Use keycode name LUT for xkb_symbols
Replace linear search with O(1).
On my setup I get 1.05x speedup compared to previous commit and
1.09x speedup compared to 44fad8a067d221ec0365455bc00c4c3c94bca0ad
(no keycode name LUT).
|
|
79741554
|
2025-09-20T15:21:16
|
|
xkbcomp: Enable aliases to override keys
Contrary to Xorg’s xkbcomp, keys and aliases share the same
namespace. So we need to resolve name conflicts as they arise,
while xkbcomp will resolve them just before copying aliases into
the keymap.
The following example:
xkb_keycodes {
<A> = 8;
<B> = 9;
alias <B> = <A>;
};
will resolve in libxkbcommon to:
xkb_keycodes {
<A> = 8;
alias <B> = <A>;
};
while in Xorg’s xkbcomp:
xkb_keycodes {
<A> = 8;
<B> = 9;
};
The former does result in the intended mapping.
In practice, there is no such conflict in xkeyboard-config.
Another corner case is that now an alias can override a key even if
proved invalid aftwerwards, e.g.:
xkb_keycodes {
<A> = 1;
<B> = 2;
alias <B> = <C>; /* Override key, even if invalid entry */
};
results in:
xkb_keycodes {
<A> = 1;
};
This should be considered a bug in either the keycodes or rules files,
not libxkbcommon.
|
|
b833d193
|
2025-09-15T14:07:05
|
|
xkbcomp: Use keycode name LUT for xkb_keycodes
Replace linear search of keycode names with O(1).
Given that:
- the number of atoms is usually < 1k;
- the keycode section usually appears first;
then the first atoms will be mostly the keycodes and their aliases,
so we can achieve O(1) lookup of the key names by using a simple
atom → keycode array.
The LUT will be used also to process `xkb_symbols` for further speedup.
On my setup I get a 1.039x speedup at the costs of less than 1%
additional allocations.
|
|
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.
|
|
3203a010
|
2025-08-13T17:06:20
|
|
tools: Add internal introspection
This tool enables simple analysis of XKB files with a YAML or DOT output:
- resolve XKB paths;
- list sections of a file;
- list the includes of each section;
- optionally process each include recursively.
Additionally, the RDF Turtle output enables to query using the powerful
SPARQL language.
The tool is for internal use only for now, so that we can test it in
various use cases before deciding if making it public.
|
|
0a874a3a
|
2025-08-13T17:02:21
|
|
include: Enable to return the resolved path
|
|
87042776
|
2025-08-21T19:30:37
|
|
logging: Encode verbosity values in an enum
This enables to provide semantics and to ensure we use the values
uniformly in the code base.
While one could expect that verbosity `0` silences the logging, it
is actually our default verbosity level for a long time. So this
commit does not change that in order to avoid possible breakage.
Silencing the logging is achieved by using a negative value for the
verbosity level.
|
|
6fac73f3
|
2025-08-02T09:49:44
|
|
log: Fix NULL string
Fixed regression introduced in 05d13d5f41d94c7776456d856fccb5969e8f5b0a.
|
|
dc63e5f8
|
2025-07-07T12:28:24
|
|
Ensure config.h is always included first
While `config.h` may not be necessary in every file, it ensures
consistency and makes code refactoring safer.
|
|
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.
|
|
e73d1a4d
|
2025-07-01T13:05:44
|
|
Add support for all layout indices to GroupN constants
This commit enables to use the pattern `Group<INDEX>` for any valid
group index `<INDEX>`.
Note that the original code in xkbcomp allows constants up to
`Group8`, but then will fail if the resulting group is > 4.
There does not seem to be any use case for this for such “feature”;
it seems rather to be a relic from times were the 4-groups limit
was not hopelessly fixed in X.
So for consistency in our code base, starting with this commit we now
disallow `Group5`..`Group8` for keymap format v1, since it is limited
to 4 groups.
Also fixed a regression in the serialization of group action, when
the group is relative.
|
|
84914512
|
2025-07-01T18:37:22
|
|
chore: Rename indexes to indices
Before this commit there was a mix between the two forms.
While “indexes” is correct, “indices” is more usual and also
the historical form used in this project.
|
|
05d13d5f
|
2025-06-26T16:58:50
|
|
include: Fix infinite loop
Fixed including an absolute path with no default map triggering an
infinite loop.
|
|
3d00222e
|
2025-06-21T18:26:34
|
|
keymap: Add option `unlockOnPress` for LatchMods()
It mirrors the feature of `SetMods()`, so that `StickyKeys` can be
implemented.
|
|
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
|
|
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.
|
|
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
|
|
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.
|
|
4f2fa718
|
2025-06-17T16:47:20
|
|
dump: Fix typo
Fixed copy-paste error. It worked for now, as both struct have the
same first fields, but it is obviously semantically incorrect and
not future-proof.
|
|
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
|
|
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
|
|
c4c531da
|
2025-06-17T11:43:50
|
|
rules: Add layout-specific options for RMLVO builder
Change the signature of `xkb_rmlvo_builder_append_layout()` to accept
an array of options.
Also add tests for layout-specific options.
|
|
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` |
|
|
52a4d9b0
|
2025-06-17T11:03:12
|
|
rules: Require layout or variant to enable %i expansion
Before this commit, the following rule would always match:
! model = symbols
* = s:%i
and set symbols to `s:1`, but the `:%i` is aimed to be used only when
the rules header specifies the layout or the variant.
Let’s be strict and disallow matching this kind of buggy rule. Emit
an error message so that we can detect it.
|
|
ef6a550f
|
2025-06-16T15:48:25
|
|
Add xkb_keymap_new_from_rmlvo()
Use the new RMLVO builder API to compile keymaps.
|
|
2906c7ec
|
2025-06-14T13:19:41
|
|
rules: Fix parsing group index
There was a typo that made parsing hexadecimal instead of the expected
decimal format.
|
|
80b8d9d1
|
2025-06-10T17:34:15
|
|
dump: Adapt groups count to keymap format
|
|
62fe73cb
|
2025-06-10T17:33:14
|
|
parser: Raise the layout limit to 32
|
|
2535a3f9
|
2025-06-11T15:55:25
|
|
rules: Convert macros into enums & inline functions
This provides semantics and better type-check.
|
|
9f3078eb
|
2025-06-10T15:46:31
|
|
dump: Use explicit format
|
|
0f89ad97
|
2025-06-09T19:26:13
|
|
dump: Always use numeric group indexes
The upcoming raise of the maximum groups count will require to use
numeric group indexes instead of the syntax `GroupN` if groups > 8.
Let’s not bother with handling two cases (group count ≤ 8 or > 8) and
always serialize group indexes as numeric values.
|
|
16c079d6
|
2025-06-06T20:27:45
|
|
chore: Rename is_absolute to is_absolute_path
|
|
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.
|
|
324984f1
|
2025-05-17T06:49:49
|
|
xkbcomp: Fix log for unknown default field
|
|
fb9fec18
|
2025-05-10T10:18:38
|
|
xkbcomp: Checked arithmetic
Use a polyfill for C23 checked arithmetic. This is a bit paranoid, as we
expect the user to use only 32 bit integers, so the signed 64 bit integer
we use to store the result should be more than enough.
Use jtckdint v1.0:
- repository: https://github.com/jart/jtckdint
- commit: 339450d13d8636f05dcb71ba36efddb226db481e
- removed all C++-specific code
|
|
61d8ec67
|
2025-05-12T18:20:47
|
|
misc: Fix string format specifiers
Ensure better portability.
|
|
3031f6c3
|
2025-05-12T10:38:15
|
|
misc: Always use `unsigned` with `int`
Better semantics & facilitate search.
|
|
01742b77
|
2025-05-12T20:40:59
|
|
misc: Ensure explicit conversion in gperf code
|
|
556d00a0
|
2025-05-12T17:52:12
|
|
keymap: Ensure proper type for layouts count
|
|
3bfc1bc1
|
2025-05-12T18:52:05
|
|
misc: Ensure proper type for darray size
|
|
1d361b8f
|
2025-05-12T10:01:10
|
|
scanner: Ensure proper type for string length
|
|
13e7114d
|
2025-05-12T09:08:49
|
|
rules: Ensure proper type of MLVO and KcCGST indexes
|
|
ac2aa2df
|
2025-05-12T07:47:03
|
|
keymap: Ensure proper type for LEDs count
|
|
903c16da
|
2025-05-12T07:42:32
|
|
keymap: Ensure proper type for key types counts
|
|
c3953a96
|
2025-05-12T07:37:29
|
|
keymap: Ensure proper type for key codes aliases
|
|
2617ebc5
|
2025-05-12T07:32:04
|
|
keymap: Ensure proper type for modifiers count
|
|
41bb797d
|
2025-05-12T07:31:33
|
|
symbols: Ensure proper type for keysyms count
|
|
f7c94bfc
|
2025-05-12T07:08:11
|
|
symbols: Ensure proper type for levels count
|
|
2f4d30c2
|
2025-05-12T07:07:50
|
|
context: Ensure proper type for include paths count
|
|
10457563
|
2025-05-12T06:41:28
|
|
keymap: Ensure proper type for actions count
|
|
3911f786
|
2025-05-12T07:06:42
|
|
keymap: Ensure proper type for num_sym_interprets
|
|
9951184e
|
2025-05-10T10:15:54
|
|
actions: Properly reset type to NoAction on error
If we do not reset the type, the action may lready have been initialized
to with a default action and thus will not be ignored.
|
|
22d27277
|
2025-05-10T10:12:31
|
|
actions: Reject arguments if they are not expected
`NoAction`, `VoidAction` and `TerminateServer` do not accept arguments.
|
|
d239a3f0
|
2025-05-11T11:42:20
|
|
actions: Improve unsupported legacy X11 actions handling
- Display a warning
- Document drawbacks of degrading to `NoAction()`
|
|
137c5e90
|
2025-05-11T12:37:23
|
|
actions: Improve unknown action logging
|
|
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.
|
|
845d2fee
|
2025-05-09T16:45:36
|
|
xkbcomp: Fix affect field wrongly accepted in SetControls() action
|
|
662ce937
|
2024-12-03T10:09:10
|
|
state: Avoid keycode lookup when key ref is available
|
|
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>
|
|
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>
|
|
c2d3694b
|
2025-05-06T07:01:01
|
|
xkbcomp: Do not discard extra bits in vmod masks
Since we accept numeric values for the vmod mask in the keymap, we may
have extra bits set that encode *no* real/virtual modifier. Keep them
unchanged for consistency.
E.g. the following keymap:
xkb_keymap {
xkb_keycodes { <a> = 38; };
xkb_symbols {
virtual_modifiers X = 0xf0000000;
key <a> { [ SetMods(mods = 0x00001100) ] };
};
};
would compile to:
xkb_keymap {
xkb_keycodes { <a> = 38; };
xkb_symbols {
virtual_modifiers X = 0xf0000000;
// Internal state
key <a> { [ SetMods(mods = 0xf0001000) ] };
// Serialization
key <a> { [ SetMods(mods = 0x00001100) ] };
};
};
|
|
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.
|
|
d5b779e1
|
2025-05-06T21:07:28
|
|
keymap: Fix empty compat interpretation map serialization
X11’s `xkbcomp` requires at least one compat interpretation entry.
|
|
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.
|
|
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
|
|
8bc60ee3
|
2025-05-05T13:20:45
|
|
modifiers: Minor optimization
It has low impact, but it also adds better semantics.
|
|
411e9a6f
|
2025-04-28T06:56:19
|
|
ExprKeySym: add comment about error recovery
|
|
76683d92
|
2025-04-29T11:37:46
|
|
symbols: Fix clang-tidy false positive
|
|
95c5c859
|
2025-03-25T05:50:02
|
|
xkbcomp: Quote erroneous field in logging
|
|
d66a65c2
|
2025-03-20T17:34:07
|
|
xkbcomp: Consistent keycodes logging
|
|
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.
|
|
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.
|
|
9e93e5e5
|
2025-04-13T10:25:02
|
|
symbols: Restrict the number of actions and keysyms per level
In preparation to support capitalization in `xkb_state_key_get_syms()`,
this commit reduces the number of supported actions and keysyms per
level, going from UINT_MAX to UINT16_MAX. This is most likely still more
than enough and could be even reduced further, but deemed unnecessary
at the moment: alignment of `struct xkb_level` is driven by the fields
`a` and `s`.
- Switched the item count type from `unsigned int` to `uint16_t`.
- Introduced `xkb_{action,keysym}_count_t` type for the respective item
count for exact typing.
- Added relevant bounds checks.
|
|
44bcdb73
|
2025-04-13T10:24:13
|
|
symbols: Avoid keysyms allocation by stealing darray
|
|
53d80b87
|
2025-03-20T15:29:17
|
|
xkbcomp: Safer keycode max_key_code
Since we now always keep the keycodes array at the minimal dimensions,
`max_key_code` is redundant and error prone. Let’s use `darray_size`
directly.
|
|
256be1ea
|
2025-03-25T08:13:21
|
|
xkbcomp: Fix merge mode for defaults actions
- Keep defaults local: do not share accross includes.
- Do not allocate default actions.
|
|
b1865376
|
2025-03-25T07:46:11
|
|
xkbcomp: Fix merge mode for defaults in symbols
|
|
a629aa84
|
2025-03-25T05:49:04
|
|
xkbcomp: Fix merge mode for defaults in compat
|
|
af5296cf
|
2025-03-19T13:11:35
|
|
xkbcomp: Fix virtual mods merge modes
|
|
06c024e0
|
2025-03-19T13:11:35
|
|
xkbcomp: Fix merge modes
Fix various issues with merge mode handling:
- Invalid initialization
- Invalid merge mode inherited from keymap
- Do not leak local merge mode
|
|
a1e595e7
|
2025-04-11T11:13:25
|
|
rules: Fix merging KcCGST values in layout order
When using layout index ranges (e.g. special indexes “any” or “later”),
the rules still match following the order in the rules file, so layout
indexes may match without following their natural order. So the resulting
KcCGST value should not be merged with the output until reaching the end
of the rule set.
Because the rule set may also involve options, it may match multiple
times for the *same* layout index. So these multiple matches should not
be merged together either, until reaching the end of the rule set.
When reaching the end of the rule set, for each KcCGST component the
pending values are then merged: for each layout, for each KcCGST value
in the corresponding sequence, merge with the output.
---
Example:
! model = symbols
* = pc
! layout[any] option = symbols
C 1 = +c1:%i
C 2 = +c2:%i
B 3 = skip
B 4 = +b:%i
The result of RMLVO
{layout: "A,B,C", options: "4,3,2,1"}
is:
symbols = pc+b:2+c1:3+c2:3
- `skip` was dropped because it has no explicit merge mode;
- although every rule was matched in order, the resulting order of the
symbols follows the order of the layouts, so `+b` appears before `+c1`
and `+c2`.
- the relative order of the options for layout C follows the order
within the rule set, not the order of RMLVO.
Before this commit, the result would have been:
symbols = pc+c1:3+c2:3+b:2
|
|
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.
|
|
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/
|
|
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
|
|
5e557040
|
2025-04-09T11:17:00
|
|
xkbcomp: Fix Unicode escape sequence
While the previous code correctly rejected malformed sequences such as
`\u{` (incomplete) or `\u{123x}`, it should try to consume as much input
as possible until reaching the corresponding closing `}` within the
string. Else we can get leftovers and the error message does not
reference the whole malformed sequence.
Also added further tests with surrogates and noncharacters.
|
|
102f4ba1
|
2025-04-06T19:38:53
|
|
Fix integer conversion warnings
|
|
5a32b779
|
2025-04-06T06:16:41
|
|
logging: Handle NULL map name
Display “(unnamed map)” instead of “(null)”.
|
|
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.
|
|
06394afc
|
2025-04-03T08:49:12
|
|
xkbcomp: Minor parser refactor for keysyms and actions
|
|
f348c6e9
|
2025-04-05T12:48:50
|
|
logging: Quote invalid escape sequence
|