From f83ac45383cd6ece34eac48d61c6503fd9e84e08 Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Fri, 1 Mar 2024 08:44:35 +0100 Subject: [PATCH] doc: Improve rules - Improved introduction - Added examples - Added RMLVO resolution process --- doc/diagrams/xkb-configuration.dot | 17 +- doc/doxygen-extra.css | 4 + doc/introduction-to-xkb.md | 20 +- doc/keymap-format-text-v1.md | 7 + doc/rules-format.md | 365 ++++++++++++++++++++++++----- 5 files changed, 335 insertions(+), 78 deletions(-) diff --git a/doc/diagrams/xkb-configuration.dot b/doc/diagrams/xkb-configuration.dot index e547f0025..c5ec60b3c 100644 --- a/doc/diagrams/xkb-configuration.dot +++ b/doc/diagrams/xkb-configuration.dot @@ -11,7 +11,8 @@ digraph { RMLVO_resolution [ label=<RMLVO resolution
Determine KcCGST using the specified rules file:
match the given model, layout, variant and options fields>, style=rounded, - color=blue + color=blue, + href="@ref rmlvo-resolution" ]; KcCGST [ label=<Layout database configuration
KcCGST: Keycodes, Compat, Geometry, Symbols, Types>, @@ -24,7 +25,7 @@ digraph { color=blue ]; Keymap [ - label=<Window server configuration
Complete keymap>, + label=<Display server configuration
Complete keymap>, penwidth=3, href="@ref keymap-intro" ]; @@ -34,12 +35,12 @@ digraph {
- - - - - - + + + + + +
Layout Database
Rules files
Keycodes files
Compat files
(Geometry files)
Symbols files
Types files
Rules files
Keycodes files
Compat files
(Geometry files)
Symbols files
Types files
>]; diff --git a/doc/doxygen-extra.css b/doc/doxygen-extra.css index 97aa72e3c..ac00c9063 100644 --- a/doc/doxygen-extra.css +++ b/doc/doxygen-extra.css @@ -12,6 +12,10 @@ dl.todo dt::before { content: '🚧 '; } +dl.note dd { + margin-inline-start: revert; +} + span.todo::before { content: '🚧 '; } diff --git a/doc/introduction-to-xkb.md b/doc/introduction-to-xkb.md index 776786706..4588bb463 100644 --- a/doc/introduction-to-xkb.md +++ b/doc/introduction-to-xkb.md @@ -58,7 +58,7 @@ implementation. The RMLVO configuration consists of the following components:
-
Rules
+
Rules @anchor config-rules-def
The rules define the _mapping_ from high to low level components. The rules _component_ is the file containing the set of rules to use. @@ -66,7 +66,7 @@ implementation. See the [rules file format](doc/rules-format.md) for further details.
-
Model
+
Model @anchor config-model-def
The name of the model of the keyboard hardware in use. It may depend on: @@ -80,16 +80,16 @@ implementation. - The keyboard _vendor:_ keyboard may have a set of keys that are not standard, or may be specific to an OS.
-
Layout
+
Layout @anchor config-layout-def
The identifier of the general layout to use. It usually refers to a country or a language.
-
Variant
+
Variant @anchor config-variant-def
Any minor variants on the general layout. It may be national variants
-
Options
+
Options @anchor config-options-def
Set of extra options to customize the standard layouts. @@ -113,28 +113,28 @@ implementation. The KcCGST configuration consists of the following components:
-
Key codes
+
Key codes @anchor config-keycodes-def
A translation of the raw [key codes] from the keyboard into symbolic names.
-
Compatibility
+
Compatibility @anchor config-compat-def
A specification of what internal actions modifiers and various special-purpose keys produce.
-
Geometry
+
Geometry @anchor config-geometry-def
A description of the physical layout of a keyboard. @attention This legacy feature is [not supported](@ref geometry-support) by _xkbcommon_.
-
Key symbols
+
Key symbols @anchor config-symbols-def
A translation of symbolic key codes into actual [key symbols] \(keysyms).
-
Key types
+
Key types @anchor config-types-def
Types describe how a pressed key is affected by active [modifiers] such as Shift, Control, Alt, etc. diff --git a/doc/keymap-format-text-v1.md b/doc/keymap-format-text-v1.md index ec4914102..365d33ea1 100644 --- a/doc/keymap-format-text-v1.md +++ b/doc/keymap-format-text-v1.md @@ -1532,6 +1532,13 @@ another file. Here it would include the `xkb_symbols` section called `nordic_base`, from the file `rx-51` located in the `nokia_vndr` folder, itself located in an XKB include path. +@anchor merge-mode-def +One can use a **merge mode** *prefix* to specify the merge mode of the file: +- β€˜+’ selects the **override** merge mode. +- β€˜|’ selects the **augment** merge mode. + +@todo dedicated section for merge mode + ### Key statement Statements of the form: diff --git a/doc/rules-format.md b/doc/rules-format.md index eab5bd22c..5c9dae816 100644 --- a/doc/rules-format.md +++ b/doc/rules-format.md @@ -3,48 +3,132 @@ The rules file {#rule-file-format} The purpose of the rules file is to map between configuration values that are easy for a user to specify and understand, and the -configuration values xkbcomp uses and understands. +configuration values that the keymap compiler, `xkbcomp`, uses and +understands. The following diagram presents an overview of this +process. See the [XKB introduction] for further details on the +components. -xkbcomp uses the `xkb_component_names` struct, which maps directly to -include statements of the appropriate sections, called for short -[KcCGST] \(see the [XKB introduction]; 'G' stands for "geometry", -which is not supported). These are not really intuitive nor -straightforward for the uninitiated. +@dotfile xkb-configuration "XKB keymap configurations" -[KcCGST]: @ref KcCGST-intro -[XKB introduction]: @ref xkb-intro +@tableofcontents{html:2} + +`xkbcomp` uses the `xkb_component_names` struct internally, which maps +directly to [include statements] of the appropriate [sections] \(called +[KcCGST] for short): + +- [key codes], +- [compatibility], +- geometry ([not supported](@ref geometry-support) by xkbcommon), +- [symbols], +- [types]. +These are not really intuitive nor straightforward for the uninitiated. Instead, the user passes in a `xkb_rule_names` struct, which consists -of the name of a rules file (in Linux this is usually "evdev"), a -keyboard model (e.g. "pc105"), a set of layouts (which will end up -in different groups, e.g. "us,fr"), variants (used to alter/augment -the respective layout, e.g. "intl,dvorak"), and a set of options -(used to tweak some general behavior of the keyboard, e.g. -"ctrl:nocaps,compose:menu" to make the Caps Lock key act like Ctrl -and the Menu key like Compose). We call these -[RMLVO](@ref RMLVO-intro). +of the following fields (called [RMLVO] for short): + +- the name of a [rules] file (in Linux this is usually β€œevdev”), +- a keyboard [model] \(e.g. β€œpc105”), +- a set of [layouts][layout] (which will end up in different + groups, e.g. β€œus,fr”), +- a set of [variants][variant] (used to alter/augment the respective + layout, e.g. β€œintl,dvorak”), +- a set of [options] \(used to tweak some general + behavior of the keyboard, e.g. β€œctrl:nocaps,compose:menu” to make + the Caps Lock key act like Ctrl and the Menu key like Compose). + +[KcCGST]: @ref KcCGST-intro +[RMLVO]: @ref RMLVO-intro +[MLVO]: @ref RMLVO-intro +[XKB introduction]: @ref xkb-intro +[include statements]: @ref xkb-include +[sections]: @ref keymap-section-def +[key codes]: @ref the-xkb_keycodes-section +[compatibility]: @ref the-xkb_compat-section +[symbols]: @ref the-xkb_symbols-section +[types]: @ref the-xkb_types-section +[rules]: @ref config-rules-def +[model]: @ref config-model-def +[layout]: @ref config-layout-def +[variant]: @ref config-variant-def +[option]: @ref config-options-def +[options]: @ref config-options-def Format of the file ------------------ -The file consists of rule sets, each consisting of rules (one per -line), which match the MLVO values on the left hand side, and, if -the values match to the values the user passed in, results in the -values on the right hand side being added to the resulting KcCGST. +@anchor rule-set-def +@anchor rule-def +The file consists of **rule sets**, each consisting of **rules** (one +per line), which match the [MLVO] values on the left hand side, and, +if the values match to the values the user passed in, results in the +values on the right hand side being [added][value update] to the +resulting [KcCGST]. See @ref rmlvo-resolution for further details. + +[rule set]: @ref rule-set-def +[rule sets]: @ref rule-set-def +[rule]: @ref rule-def + +```c +// This is a comment + +// The following line is a rule header. +// It starts with β€˜!’ and introduces a rules set. +// It indicates that the rules map MLVO options to KcCGST symbols. +! option = symbols + // The following lines are rules that add symbols of the RHS when the + // LHS matches an option. + ctrl:nocaps = +ctrl(nocaps) + compose:menu = +compose(menu) + +// One may use multiple MLVO components on the LHS +! layout option = symbols + be caps:digits_row = +capslock(digits_row) + fr caps:digits_row = +capslock(digits_row) +``` + +@anchor rules-group-def Since some values are related and repeated often, it is possible -to group them together and refer to them by a group name in the +to *group* them together and refer to them by a **group name** in the rules. -Along with matching values by simple string equality, and for -membership in a group defined previously, rules may also contain -"wildcard" values - "*" - which always match. These usually appear -near the end. +[group]: @ref rules-group-def + +```c +// Let’s rewrite the previous rules set using groups. +// Groups starts with β€˜$’. + +// Define a group for countries with AZERTY layouts +! $azerty = be fr + +// The following rule will match option `caps:digits_row` only for +// layouts in the $azerty group, i.e. `fr` and `be`. +! layout option = symbols + $azerty caps:digits_row = +capslock(digits_row) +``` + +@anchor rules-wildcard-def +Along with matching values by simple string equality and for +membership in a [group] defined previously, rules may also contain +**wildcard** values β€œ\*” which *always match*. These usually appear +near the end of a rule set to set *default* values. + +```c +! layout = keycodes + // The following two lines only match exactly their respective groups. + $azerty = +aliases(azerty) + $qwertz = +aliases(qwertz) + // This line will match layouts that are neither in $azerty nor in + // $qwertz groups. + * = +aliases(qwerty) +``` Grammar ------- -(It might be helpful to look at a file like rules/evdev along with -this grammar. Comments, whitespace, etc. are not shown.) +It is advised to look at a file like `rules/evdev` along with +this grammar. -``` +@note Comments, whitespace, etc. are not shown. + +```bnf File ::= { "!" (Include | Group | RuleSet) } Include ::= "include" @@ -65,49 +149,210 @@ MlvoValue ::= "*" | GroupName | KccgstValue ::= ``` -Notes: + +@note +- Include processes the rules in the file path specified in the `ident`, + in order. **%-expansion** is performed, as follows: +
+
`%%`
+
A literal %.
+
\%H
+
The value of the `$HOME` environment variable.
+
\%E
+
+ The extra lookup path for system-wide XKB data (usually + `/etc/xkb/rules`). +
+
\%S
+
+ The system-installed rules directory (usually + `/usr/share/X11/xkb/rules`). +
+
-- Include processes the rules in the file path specified in the ident, - in order. %-expansion is performed, as follows: +- The order of values in a `Rule` must be the same as the `Mapping` it + follows. The mapping line determines the meaning of the values in + the rules which follow in the `RuleSet`. -``` - %%: - A literal %. +- If a `Rule` is matched, **%-expansion** is performed on the +`KccgstValue`, as follows: - %H: - The value of the HOME environment variable. +
+
\%m, \%l, \%v
+
+ The [model], [layout] or [variant], if *only one* was given + (e.g. \%l for β€œus,il” is invalid). +
+
+ \%l[1], \%l[2], …, + \%v[1], \%v[2], … +
+
+ [Layout][layout] or [variant] for the specified layout `Index`, + if *more than one* was given, e.g.: \%l[1] is + invalid for β€œus” but expands to β€œus” for β€œus,de”. +
+
+ `%+m`, + `%+l`, `%+l[1]`, `%+l[2]`, …, + `%+v`, `%+v[1]`, `%+v[2]`, … +
+
+ As above, but prefixed with β€˜+’. Similarly, β€˜|’, β€˜-’, β€˜_’ may be + used instead of β€˜+’. See the [merge mode] documentation for the + special meaning of β€˜+’ and β€˜|’. +
+
+ `%(m)`, + `%(l)`, `%(l[1])`, `%(l[2])`, …, + `%(v)`, `%(v[1])`, `%(v[2])`, … +
+
+ As above, but prefixed by β€˜(’ and suffixed by β€˜)’. +
+
- %E: - The extra lookup path for system-wide XKB data (usually /etc/xkb/rules). + In case the expansion is *invalid*, as described above, it is *skipped* + (the rest of the string is still processed); this includes the prefix + and suffix. This is why one should use e.g. %(v[1]) + instead of (\%v[1]). See @ref rules-symbols-example for + an illustration. - %S: - The system-installed rules directory (usually /usr/share/X11/xkb/rules). -``` +RMLVO resolution process {#rmlvo-resolution} +------------------------ -- The order of values in a Rule must be the same as the Mapping it - follows. The mapping line determines the meaning of the values in - the rules which follow in the RuleSet. +First of all, the rules *file* is extracted from the provided +[RMLVO][RMLVO] configuration (usually `evdev`). Then its path +is resolved and the file is parsed to get the [rule sets]. + +Then *each rule set* is checked against the provided [MLVO] configuration, +following their *order* in the rules file. + +If a [rule] matches in a @ref rule-set-def "rule set", then: + + +
    +
  1. + @anchor rules-kccgst-value-update + The *KcCGST* value of the rule is used to update the [KcCGST] + configuration, using the following instructions. Note that `foo` + and `bar` are placeholders; β€˜+’ specifies the *override* [merge mode] + and can be replaced by β€˜|’ to specify the *augment* merge mode instead. + + | Rule value | Old KcCGST value | New KcCGST value | + | ----------------- | ---------------- | --------------------- | + | `bar` | | `bar` | + | `bar` | `foo` | `foo` (*skip* `bar`) | + | `bar` | `+foo` | `bar+foo` (*prepend*) | + | `+bar` | | `+bar` | + | `+bar` | `foo` | `foo+bar` | + | `+bar` | `+foo` | `+foo+bar` | +
  2. +
  3. + The rest of the set will be *skipped*, except if the set matches + against [options]. Indeed, those may contain *multiple* legitimate + rules, so they are processed entirely. See @ref rules-options-example + for an illustration. +
  4. +
-- If a Rule is matched, %-expansion is performed on the KccgstValue, - as follows: +[value update]: @ref rules-kccgst-value-update +[merge mode]: @ref merge-mode-def +### Example: key codes + +Using the following example: + +```c +! $jollamodels = jollasbj +! $azerty = be fr +! $qwertz = al ch cz de hr hu ro si sk + +! model = keycodes + $jollamodels = evdev+jolla(jolla) + olpc = evdev+olpc(olpc) + * = evdev + +! layout = keycodes + $azerty = +aliases(azerty) + $qwertz = +aliases(qwertz) + * = +aliases(qwerty) ``` - %m, %l, %v: - The model, layout or variant, if only one was given (e.g. - %l for "us,il" is invalid). - %l[1], %v[1]: - Layout or variant for the specified group Index, if more than - one was given (e.g. %l[1] for "us" is invalid). +we would have the following resolutions of [key codes]: + +| Model | Layout | Keycodes | +| ---------- | :------: | :----------------------------------- | +| `jollasbj` | `us` | `evdev+jolla(jolla)+aliases(qwerty)` | +| `olpc` | `be` | `evdev+olpc(olpc)+aliases(azerty)` | +| `pc` | `al` | `evdev+aliases(qwertz)` | + +### Example: layouts, variants and symbols {#rules-symbols-example} - %+m, %+l, %+v, %+l[1], %+v[1] - As above, but prefixed with '+'. Similarly, '|', '-', '_' may be - used instead of '+'. +Using the following example: - %(m), %(l), %(l[1]), %(v), %(v[1]): - As above, but prefixed by '(' and suffixed by ')'. +```c +! layout = symbols + * = pc+%l%(v) +// The following would not work: syntax for *multiple* layouts +// in a rule set for *single* layout. +//* = pc+%l[1]%(v[1]) + +! layout[1] = symbols + * = pc+%l[1]%(v[1]) +// The following would not work: syntax for *single* layout +// in a rule set for *multiple* layouts. +//* = pc+%l%(v) + +! layout[2] = symbols + * = +%l[2]%(v[2]):2 + +! layout[3] = symbols + * = +%l[3]%(v[3]):3 ``` - In case the expansion is invalid, as described above, it is - skipped (the rest of the string is still processed); this includes - the prefix and suffix (that's why you shouldn't use e.g. "(%v[1])"). +we would have the following resolutions of [symbols]: + +| Layout | Variant | Symbols | Rules sets used | +| ---------- | ------------ | ----------------------------- | --------------- | +| `us` | | `pc+us` | #1 | +| `us` | `intl` | `pc+us(intl)` | #1 | +| `us,es` | | `pc+us+es:2` | #2, #3 | +| `us,es,fr` | `intl,,bepo` | `pc+us(intl)+es:2+fr(bepo):3` | #2, #3, #4 | + +### Example: layout, option and symbols {#rules-options-example} + +Using the following example: + +```c +! $azerty = be fr + +! layout = symbols + * = pc+%l%(v) + +! layout option = symbols + $azerty caps:digits_row = +capslock(digits_row) + * misc:typo = +typo(base) + * lv3:ralt_alt = +level3(ralt_alt) + ``` + +we would have the following resolutions of [symbols]: + +| Layout | Option | Symbols | +| ------- | ---------------------------------------- | -------------------------------------------------------- | +| `be` | `caps:digits_row` | `pc+be+capslock(digits_row)` | +| `gb` | `caps:digits_row` | `pc+gb` | +| `fr` | `misc:typo` | `pc+fr+typo(base)` | +| `fr` | `misc:typo,caps:digits_row` | `pc+fr+capslock(digits_row)+typo(base)` | +| `fr` | `lv3:ralt_alt,caps:digits_row,misc:typo` | `pc+fr+capslock(digits_row)+typo(base)+level3(ralt_alt)` | + +Note that the configuration with `gb` [layout] has no match for the [option] +and that the order of the [options] in the [RMLVO] configuration has no +influence on the resulting [symbols].