diff options
| author | Haibo Huang <hhb@google.com> | 2020-09-08 17:10:03 -0700 |
|---|---|---|
| committer | Haibo Huang <hhb@google.com> | 2020-09-10 22:20:42 +0000 |
| commit | bffa8499cb8ce3cc4366055be8fe62d501d6a8e5 (patch) | |
| tree | 648dfaada5799a6227dd5f1af43d89ed8d71d96d /doc | |
| parent | e4e474780d90ed6166f7113a7464371baa275007 (diff) | |
| download | platform_external_libxkbcommon-master.tar.gz platform_external_libxkbcommon-master.tar.bz2 platform_external_libxkbcommon-master.zip | |
1. Run meson build locally:
meson config -Denable-x11=false -Denable-wayland=false -Denable-docs=false
2. Copy over generated parser.h / parser.c
3. Copy over config.h, and remove defines for not supported functions.
Change-Id: Id7f3c822c1d958fa541685344961507bcfa03b17
Diffstat (limited to 'doc')
| -rw-r--r-- | doc/.gitignore | 2 | ||||
| -rw-r--r-- | doc/Doxyfile.in | 47 | ||||
| -rw-r--r-- | doc/compat.md | 56 | ||||
| -rw-r--r-- | doc/doxygen-extra.css | 9 | ||||
| -rw-r--r-- | doc/keymap-format-text-v1.md | 368 | ||||
| -rw-r--r-- | doc/quick-guide.md | 229 | ||||
| -rw-r--r-- | doc/rules-format.md | 109 | ||||
| -rw-r--r-- | doc/user-configuration.md | 230 |
8 files changed, 1050 insertions, 0 deletions
diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..63b767d --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,2 @@ +Doxyfile +html/ diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in new file mode 100644 index 0000000..56884ef --- /dev/null +++ b/doc/Doxyfile.in @@ -0,0 +1,47 @@ +PROJECT_NAME = @PACKAGE_NAME@ + +PROJECT_NUMBER = @PACKAGE_VERSION@ + +OUTPUT_DIRECTORY = @OUTPUT_DIRECTORY@ + +BRIEF_MEMBER_DESC = NO + +JAVADOC_AUTOBRIEF = YES + +OPTIMIZE_OUTPUT_FOR_C = YES + +EXTENSION_MAPPING = no_extension=md + +SORT_MEMBER_DOCS = NO + +QUIET = YES + +WARN_IF_UNDOCUMENTED = NO + +INPUT = @INPUT@ + +FILE_PATTERNS = *.c \ + *.h + +RECURSIVE = YES + +USE_MDFILE_AS_MAINPAGE = README.md + +VERBATIM_HEADERS = NO + +ALPHABETICAL_INDEX = NO + +IGNORE_PREFIX = xkb_ \ + XKB_ \ + rxkb_ \ + RXKB_ + +HTML_EXTRA_STYLESHEET = doc/doxygen-extra.css + +HTML_TIMESTAMP = NO + +ENUM_VALUES_PER_LINE = 1 + +SEARCHENGINE = NO + +GENERATE_LATEX = NO diff --git a/doc/compat.md b/doc/compat.md new file mode 100644 index 0000000..19d7d78 --- /dev/null +++ b/doc/compat.md @@ -0,0 +1,56 @@ +# Compatibility + +Relative to the XKB 1.0 specification implemented in current X servers, +xkbcommon has removed support for some parts of the specification which +introduced unnecessary complications. Many of these removals were in fact +not implemented, or half-implemented at best, as well as being totally +unused in the standard dataset. + +Notable removals: +- geometry support + + there were very few geometry definitions available, and while + xkbcommon was responsible for parsing this insanely complex format, + it never actually did anything with it + + hopefully someone will develop a companion library which supports + keyboard geometries in a more useful format +- KcCGST (keycodes/compat/geometry/symbols/types) API + + use RMLVO instead; KcCGST is now an implementation detail + + including pre-defined keymap files +- XKM support + + may come in an optional X11 support/compatibility library +- around half of the interpret actions + + pointer device, message and redirect actions in particular +- non-virtual modifiers + + core and virtual modifiers have been collapsed into the same + namespace, with a 'significant' flag that largely parallels the + core/virtual split +- radio groups + + completely unused in current keymaps, never fully implemented +- overlays + + almost completely unused in current keymaps +- key behaviors + + used to implement radio groups and overlays, and to deal with things + like keys that physically lock; unused in current keymaps +- indicator behaviours such as LED-controls-key + + the only supported LED behaviour is key-controls-LED; again this + was never really used in current keymaps + +On the other hand, some features and extensions were added. + +Notable additions: +- 32-bit keycodes +- extended number of modifiers (planned) +- extended number of groups (planned) +- multiple keysyms per level + + such levels are ignored by x11/xkbcomp. +- key names (e.g. `<AE11>`) can be longer than 4 characters. + +## Compose support + +Relative to the standard implementation in libX11 (described in the +Compose(5) man-page), some features are not supported: + +- the (! MODIFIER) syntax + + parsed correctly but ignored. +- using modifier keysyms in Compose sequences +- several interactions with Braille keysyms diff --git a/doc/doxygen-extra.css b/doc/doxygen-extra.css new file mode 100644 index 0000000..632ebad --- /dev/null +++ b/doc/doxygen-extra.css @@ -0,0 +1,9 @@ +div#top, div.header, div.contents { + margin-left: auto; + margin-right: auto; + width: 960px; +} + +.footer { + display: none; +} diff --git a/doc/keymap-format-text-v1.md b/doc/keymap-format-text-v1.md new file mode 100644 index 0000000..eda6ebb --- /dev/null +++ b/doc/keymap-format-text-v1.md @@ -0,0 +1,368 @@ +# The XKB keymap text format, V1 + +This document describes the `XKB_KEYMAP_FORMAT_TEXT_V1` keymap format, +as implemented by libxkbcommon. + +A keymap consists of a single top-level `xkb_keymap` block, underwhich +are nested the following sections. + + +## The `xkb_keycodes` section + +This is the simplest section type, and is the first one to be +compiled. The purpose of this is mostly to map between the +hardware/evdev scancodes and xkb keycodes. Each key is given a name +by which it can be referred to later, e.g. in the symbols section. + +### Keycode statements + +Statements of the form: + + <TLDE> = 49; + <AE01> = 10; + +The above would let 49 and 10 be valid keycodes in the keymap, and +assign them the names `TLDE` and `AE01` respectively. The format +`<WXYZ>` is always used to refer to a key by name. + +[The naming convention `<AE01>` just denotes the position of the key +in the main alphanumric section of a standard QWERTY keyboard, with +the two letters specifying the row and the two digits specifying the +column, from the bottom left.] + +In the common case this just maps to the evdev scancodes from +`/usr/include/linux/input.h`, e.g. the following definitions: + + #define KEY_GRAVE 41 + #define KEY_1 2 + +correspond to the ones above. Similar definitions appear in the +xf86-input-keyboard driver. Note that in all current keymaps there's a +constant offset of 8 (for historical reasons). + +If there's a conflict, like the same name given to different keycodes, +or same keycode given different names, it is resolved according to the +merge mode which applies to the definitions. + +### Alias statements + +Statements of the form: + + alias <MENU> = <COMP>; + +Allows to refer to a previously defined key (here `<COMP>`) by another +name (here `<MENU>`). Conflicts are handled similarly to keycode +statements. + +### LED name statements + +Statements of the form: + + indicator 1 = "Caps Lock"; + indicator 2 = "Num Lock"; + indicator 3 = "Scroll Lock"; + +Assigns a name to the keyboard LED (AKA indicator) with the given +index. The LED may be referred by this name later in the compat +section and by the user. + + +## The `xkb_types` section + +This section is the second to be processesed, after `xkb_keycodes`. +However, it is completely independent and could have been the first to +be processed (it does not refer to specific keys as specified in the +`xkb_keycodes` section). + +This section defines key types, which, given a key and a keyboard +state (i.e. modifier state and group), determine the shift level to be +used in translating the key to keysyms. These types are assigned to +each group in each key, in the `xkb_symbols` section. + +Key types are called this way because, in a way, they really describe +the "type" of the key (or more correctly, a specific group of the +key). For example, an ordinary keymap will provide a type called +`KEYPAD`, which consists of two levels, with the second level being +chosen according to the state of the Num Lock (or Shift) modifiers. +Another example is a type called `ONE_LEVEL`, which is usually +assigned to keys such as Escape; these have just one level and are not +affected by the modifier state. Yet more common examples are +`TWO_LEVEL` (with Shift choosing the second level), `ALPHABETIC` +(where Caps Lock may also choose the second level), etc. + +### Type definitions + +Statements of the form: + + type "FOUR_LEVEL" { ... } + +The above would create a new type named `FOUR_LEVEL`. +The body of the definition may include statements of the following +forms: + +#### `level_name` statements + + level_name[Level1] = "Base"; + +Mandatory for each level in the type. + +Gives each level in this type a descriptive name. It isn't used +for anything. + +Note: A level may be specified as Level[1-8] or just a number (can +be more than 8). + +#### `modifiers` statement + + modifiers = Shift+Lock+LevelThree; + +Mandatory, should be specified only once. + +A mask of real and virtual modifiers. These are the only modifiers +being considered when matching the modifier state against the type. +The other modifiers, whether active or not, are masked out in the +calculation. + +#### `map` entry statements + + map[Shift+LevelThree] = Level4; + +Should have at least as many mappings as there are levels in the type. + +If the active modifiers, masked with the type's modifiers (as stated +above), match (i.e. equal) the modifiers inside the `map[]` statement, +then the level in the right hand side is chosen. For example, in the +above, if in the current keyboard state the `Shift` and `LevelThree` +modifiers are active, while the `Lock` modifier is not, then the +keysym(s) in the 4th level of the group will be returned to the user. + +#### `preserve` statements + + map[Shift+Lock+LevelThree] = Level5; + preserve[Shift+Lock+LevelThree] = Lock; + +When a key type is used for keysym translation, its modifiers are said +to be "consumed". For example, in a simple US keymap, the "g" "g" key +is assigned an ordinary `ALPHABETIC` key type, whose modifiers are +Shift and Lock; then for the "g" key, these two modifiers are consumed +by the translation. This information is relevant for applications +which further process the modifiers, since by then the consumed +modifiers have already "done their part" and should be masked out. + +However, sometimes even if a modifier had already affected the key +translation through the type, it should *not* be reported as consumed, +for various reasons. In this case, a `preserve[]` statement can be +used to augment the map entry. The modifiers inside the square +brackets should match one of the map[] statements in the type (if +there is no matching map entry, one mapping to Level1 is implicitly +added). The right hand side should consists of modifiers from the +type's modifiers; these modifiers are then "preserved" and not +reported as consumed. + + +## The `xkb_compat` section + +This section is the third to be processed, after `xkb_keycodes` and +`xkb_types`. + +### Interpret statements + +Statements of the form: + + interpret Num_Lock+Any { ... } + interpret Shift_Lock+AnyOf(Shift+Lock) { ... } + +The `xkb_symbols` section (see below) allows the keymap author to +perform, among other things, the following things for each key: + +- Bind an action, like SetMods or LockGroup, to the key. Actions, like + symbols, are specified for each level of each group in the key + separately. + +- Add a virtual modifier to the key's virtual modifier mapping + (vmodmap). + +- Specify whether the key should repeat or not. + +However, doing this for each key (or level) is tedious and inflexible. +Interpret's are a mechanism to apply these settings to a bunch of +keys/levels at once. + +Each interpret specifies a condition by which it attaches to certain +levels. The condition consists of two parts: + +- A keysym. If the level has a different (or more than one) keysym, + the match fails. Leaving out the keysym is equivalent to using the + `NoSymbol` keysym, which always matches successfully. + +- A modifier predicate. The predicate consists of a matching operation + and a mask of (real) modifiers. The modifiers are matched against + the key's modifier map (modmap). The matching operation can be one + of the following: + + * `AnyOfOrNone` - The modmap must either be empty or include at + least one of the specified modifiers. + * `AnyOf` - The modmap must include at least one of the specified + modifiers. + * `NoneOf` - The modmap must not include any of the specified + modifiers. + * `AllOf` - The modmap must include all of the specified modifiers + (but may include others as well). + * `Exactly` - The modmap must be exactly the same as the specified + modifiers. + + Leaving out the predicate is equivalent to using `AnyOfOrNone` while + specifying all modifiers. Leaving out just the matching condition is + equivalent to using `Exactly`. + +An interpret may also include `useModMapMods = level1;` - see below. + +If a level fulfils the conditions of several interprets, only the +most specific one is used: + +- A specific keysym will always match before a generic `NoSymbol` + condition. + +- If the keysyms are the same, the interpret with the more specific + matching operation is used. The above list is sorted from least to + most specific. + +- If both the keysyms and the matching operations are the same (but the + modifiers are different), the first interpret is used. + +As described above, once an interpret "attaches" to a level, it can bind +an action to that level, add one virtual modifier to the key's vmodmap, +or set the key's repeat setting. You should note the following: + +- The key repeat is a property of the entire key; it is not + level-specific. In order to avoid confusion, it is only inspected + for the first level of the first group; the interpret's repeat + setting is ignored when applied to other levels. + +- If one of the above fields was set directly for a key in + `xkb_symbols`, the explicit setting takes precedence over the + interpret. + +The body of the statement may include statements of the following +forms (all of which are optional): + +#### `useModMapMods` statement + + useModMapMods = level1; + +When set to `level1`, the interpret will only match levels which are +the first level of the first group of the keys. This can be useful in +conjunction with e.g. a `virtualModifier` statement. + +#### `action` statement + + action = LockMods(modifiers=NumLock); + +Bind this action to the matching levels. + +#### `virtualModifier` statement + + virtualModifier = NumLock; + +Add this virtual modifier to the key's vmodmap. The given virtual +modifier must be declared at the top level of the file with a +`virtual_modifiers` statement, e.g.: + + virtual_modifiers NumLock; + +#### `repeat` statement + + repeat = True; + +Set whether the key should repeat or not. Must be a boolean value. + +### LED map statements + +Statements of the form: + + indicator "Shift Lock" { ... } + +This statement specifies the behavior and binding of the LED (AKA +indicator) with the given name ("Shift Lock" above). The name should +have been declared previously in the `xkb_keycodes` section (see LED +name statement), and given an index there. If it wasn't, it is created +with the next free index. + +The body of the statement describes the conditions of the keyboard +state which will cause the LED to be lit. It may include the following +statements: + +#### `modifiers` statement + + modifiers = ScrollLock; + +If the given modifiers are in the required state (see below), the +LED is lit. + +#### `whichModState` statment + + whichModState = Latched+Locked; + +Can be any combination of: + +* `base`, `latched`, `locked`, `effective` +* `any` (i.e. all of the above) +* `none` (i.e. none of the above) +* `compat` (legacy value, treated as effective) + +This will cause the respective portion of the modifier state (see +`struct xkb_state`) to be matched against the modifiers given in the +`modifiers` statement. + +Here's a simple example: + +indicator "Num Lock" { + modifiers = NumLock; + whichModState = Locked; +}; + +Whenever the NumLock modifier is locked, the Num Lock LED will light +up. + +#### `groups` statement + + groups = All - group1; + +If the given groups are in the required state (see below), the LED is +lit. + +#### `whichGroupState` statement + + whichGroupState = Effective; + +Can be any combination of: + +* `base`, `latched`, `locked`, `effective` +* `any` (i.e. all of the above) +* `none` (i.e. none of the above) + +This will cause the respective portion of the group state (see +`struct xkb_state`) to be matched against the groups given in the +`groups` statement. + +Note: the above conditions are disjunctive, i.e. if any of them are +satisfied the LED is lit. + + +## The `xkb_symbols` section + +This section is the fourth to be processed, after `xkb_keycodes`, +`xkb_types` and `xkb_compat`. + +TODO + + +## Virtual modifier statements + +Statements of the form: + + virtual_modifiers LControl; + +Can appear in the `xkb_types`, `xkb_compat`, `xkb_symbols` sections. + +TODO diff --git a/doc/quick-guide.md b/doc/quick-guide.md new file mode 100644 index 0000000..eb1a757 --- /dev/null +++ b/doc/quick-guide.md @@ -0,0 +1,229 @@ +# Quick Guide + +## Introduction + +This document contains a quick walk-through of the often-used parts of +the library. We will employ a few use-cases to lead the examples: + +1. An evdev client. "evdev" is the Linux kernel's input subsystem; it + only reports to the client which keys are pressed and released. + +2. An X11 client, using the XCB library to communicate with the X + server and the xcb-xkb library for using the XKB protocol. + +3. A Wayland client, using the standard protocol. + +The snippets are not complete, and some support code is omitted. You +can find complete and more complex examples in the source directory: + +1. tools/interactive-evdev.c contains an interactive evdev client. + +2. tools/interactive-x11.c contains an interactive X11 client. + +3. tools/interactive-wayland.c contains an interactive Wayland client. + +Also, the library contains many more functions for examining and using +the library context, the keymap and the keyboard state. See the +hyper-linked reference documentation or go through the header files in +xkbcommon/ for more details. + +## Code + +Before we can do anything interesting, we need a library context: + +~~~{.c} + #include <xkbcommon/xkbcommon.h> + + struct xkb_context *ctx; + + ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!ctx) <error> +~~~ + +The `xkb_context` contains the keymap include paths, the log level and +functions, and other general customizable administrativia. + +Next we need to create a keymap, `xkb_keymap`. This is an immutable object +which contains all of the information about the keys, layouts, etc. There +are different ways to do this. + +If we are an evdev client, we have nothing to go by, so we need to ask +the user for his/her keymap preferences (for example, an Icelandic +keyboard with a Dvorak layout). The configuration format is commonly +called RMLVO (Rules+Model+Layout+Variant+Options), the same format used +by the X server. With it, we can fill a struct called `xkb_rule_names`; +passing `NULL` chooses the system's default. + +~~~{.c} + struct xkb_keymap *keymap; + /* Example RMLVO for Icelandic Dvorak. */ + struct xkb_rule_names names = { + .rules = NULL, + .model = "pc105", + .layout = "is", + .variant = "dvorak", + .options = "terminate:ctrl_alt_bksp" + }; + + keymap = xkb_keymap_new_from_names(ctx, &names, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) <error> +~~~ + +If we are a Wayland client, the compositor gives us a string complete +with a keymap. In this case, we can create the keymap object like this: + +~~~{.c} + /* From the wl_keyboard::keymap event. */ + const char *keymap_string = <...>; + struct xkb_keymap *keymap; + + keymap = xkb_keymap_new_from_string(ctx, keymap_string, + XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) <error> +~~~ + +If we are an X11 client, we are better off getting the keymap from the +X server directly. For this we need to choose the XInput device; here +we will use the core keyboard device: + +~~~{.c} + #include <xkbcommon/xkbcommon-x11.h> + + xcb_connection_t *conn = <...>; + int32_t device_id; + + device_id = xkb_x11_get_core_keyboard_device_id(conn); + if (device_id == -1) <error> + + keymap = xkb_x11_keymap_new_from_device(ctx, conn, device_id, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) <error> +~~~ + +Now that we have the keymap, we are ready to handle the keyboard devices. +For each device, we create an `xkb_state`, which remembers things like which +keyboard modifiers and LEDs are active: + +~~~{.c} + struct xkb_state *state; + + state = xkb_state_new(keymap); + if (!state) <error> +~~~ + +For X11/XCB clients, this is better: + +~~~{.c} + state = xkb_x11_state_new_from_device(keymap, conn, device_id); + if (!state) <error> +~~~ + +When we have an `xkb_state` for a device, we can start handling key events +from it. Given a keycode for a key, we can get its keysym: + +~~~{.c} + <key event structure> event; + xkb_keycode_t keycode; + xkb_keysym_t keysym; + + keycode = event->keycode; + keysym = xkb_state_key_get_one_sym(state, keycode); +~~~ + +We can see which keysym we got, and get its name: + +~~~{.c} + char keysym_name[64]; + + if (keysym == XKB_KEY_Space) + <got a space> + + xkb_keysym_get_name(keysym, keysym_name, sizeof(keysym_name)); +~~~ + +libxkbcommon also supports an extension to the classic XKB, whereby a +single event can result in multiple keysyms. Here's how to use it: + +~~~{.c} + const xkb_keysym_t *keysyms; + int num_keysyms; + + num_keysyms = xkb_state_key_get_syms(state, keycode, &keysyms); +~~~ + +We can also get a UTF-8 string representation for this key: + +~~~{.c} + char *buffer; + int size; + + // First find the needed size; return value is the same as snprintf(3). + size = xkb_state_key_get_utf8(state, keycode, NULL, 0) + 1; + if (size <= 1) <nothing to do> + buffer = <allocate size bytes> + + xkb_state_key_get_utf8(state, keycode, buffer, size); +~~~ + +Of course, we also need to keep the `xkb_state` up-to-date with the +keyboard device, if we want to get the correct keysyms in the future. + +If we are an evdev client, we must let the library know whether a key +is pressed or released at any given time: + +~~~{.c} + enum xkb_state_component changed; + + if (<key press>) + changed = xkb_state_update_key(state, keycode, XKB_KEY_DOWN); + else if (<key release>) + changed = xkb_state_update_key(state, keycode, XKB_KEY_UP); +~~~ + +The `changed` return value tells us exactly which parts of the state +have changed. + +If it is a key-repeat event, we can ask the keymap what to do with it: + +~~~{.c} + if (<key repeat> && !xkb_keymap_key_repeats(keymap, keycode)) + <discard event> +~~~ + +On the other hand, if we are an X or Wayland client, the server already +does the hard work for us. It notifies us when the device's state +changes, and we can simply use what it tells us (the necessary +information usually comes in a form of some "state changed" event): + +~~~{.c} + changed = xkb_state_update_mask(state, + event->depressed_mods, + event->latched_mods, + event->locked_mods, + event->depressed_layout, + event->latched_layout, + event->locked_layout); +~~~ + +Now that we have an always-up-to-date `xkb_state`, we can examine it. +For example, we can check whether the Control modifier is active, or +whether the Num Lock LED is active: + +~~~{.c} + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, + XKB_STATE_MODS_EFFECTIVE) > 0) + <The Control modifier is active> + + if (xkb_state_led_name_is_active(state, XKB_LED_NAME_NUM) > 0) + <The Num Lock LED is active> +~~~ + +And that's it! Eventually, we should free the objects we've created: + +~~~{.c} + xkb_state_unref(state); + xkb_keymap_unref(keymap); + xkb_context_unref(ctx); +~~~ diff --git a/doc/rules-format.md b/doc/rules-format.md new file mode 100644 index 0000000..f9fe0d9 --- /dev/null +++ b/doc/rules-format.md @@ -0,0 +1,109 @@ +The rules file +============== + +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. + +xkbcomp uses the xkb_component_names struct, which maps directly to +include statements of the appropriate sections, called for short +KcCGST (see doc/keymap-format-text-v1.txt; 'G' stands for "geometry", +which is not supported). These are not really intuitive or straight- +forward 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. + +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. +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 +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. + +Grammar +------- +(It might be helpful to look at a file like rules/evdev along with +this grammar. Comments, whitespace, etc. are not shown.) + +``` +File ::= { "!" (Include | Group | RuleSet) } + +Include ::= "include" <ident> + +Group ::= GroupName "=" { GroupElement } "\n" +GroupName ::= "$"<ident> +GroupElement ::= <ident> + +RuleSet ::= Mapping { Rule } + +Mapping ::= { Mlvo } "=" { Kccgst } "\n" +Mlvo ::= "model" | "option" | ("layout" | "variant") [ Index ] +Index ::= "[" 1..XKB_NUM_GROUPS "]" +Kccgst ::= "keycodes" | "symbols" | "types" | "compat" | "geometry" + +Rule ::= { MlvoValue } "=" { KccgstValue } "\n" +MlvoValue ::= "*" | GroupName | <ident> +KccgstValue ::= <ident> +``` + +Notes: + +- 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). +``` + +- 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. + +- If a Rule is matched, %-expansion is performed on the KccgstValue, + as follows: + +``` + %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). + + %+m, %+l, %+v, %+l[1], %+v[1] + As above, but prefixed with '+'. Similarly, '|', '-', '_' may be + used instead of '+'. + + %(m), %(l), %(l[1]), %(v), %(v[1]): + As above, but prefixed by '(' and suffixed by ')'. +``` + + 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])"). diff --git a/doc/user-configuration.md b/doc/user-configuration.md new file mode 100644 index 0000000..2146599 --- /dev/null +++ b/doc/user-configuration.md @@ -0,0 +1,230 @@ +# User-configuration + +This page describes how to add a custom layout or option so that it will be +parsed by libxkbcommon. + +**The below requires libxkbcommon as keymap compiler and does not work in X**. + +## Data locations + +libxkbcommon searches the following paths for XKB configuration files: +- `$XDG_CONFIG_HOME/xkb/`, or `$HOME/.config/xkb/` if the `$XDG_CONFIG_HOME` + environment variable is not defined +- `$HOME/.xkb/` +- `$XKB_CONFIG_EXTRA_PATH` if set, otherswise `<sysconfdir>/xkb` (on most + distributions this is `/etc/xkb`) +- `$XKB_CONFIG_ROOT` if set, otherwise `<datadir>/X11/xkb/` (path defined by the + `xkeyboard-config` package, on most distributions this is + `/usr/share/X11/xkb`) + +A keymap created with `xkb_keymap_new_from_names()` will look up those paths in +order until the required data is found. + +**Note: Where libxkbcommon runs in a privileged context, only the system +(datadir) path is available.** + +Each directory should have one or more of the following subdirectories: +- `compat` +- `geometry` (libxkbcommon ignores this directory) +- `keycodes` +- `rules` +- `symbols` +- `types` + +The majority of user-specific configuration involve modifying key symbols and +this is what this document focuses on. For use-cases where a user may need to +add new key types or compat entries the general approach remains the same. A +detailed description for how to add those types or compat entries is out of +scope for this document. + +You should never need to add user-specific keycodes. Where a keycode is missing, +the addition should be filed in the upstream xkeyboard-config project. + +## RMLVO vs KcCGST + +Due to how XKB is configured, there is no such thing as a "layout" in XKB +itself, or, indeed, any of the rules, models, variant, options (RMLVO) decribed +in `struct xkb_rule_names`. RMLVO names are merely lookup keys in the +rules file provided by xkeyboard-config to map to the correct keycode, compat, +geometry (ignored by libxkbcommon), symbols and types (KcCGST). The KcCGST data +is the one used by XKB and libxbkcommon to map keys to actual symbols. + +For example, a common RMLVO configuration is layout "us", variant "dvorak" and +option "terminate:ctrl_alt_bksp". Using the default rules file and model +this maps into the following KcCGST components: + +``` +xkb_keymap { + xkb_keycodes { include "evdev+aliases(qwerty)" }; + xkb_types { include "complete" }; + xkb_compat { include "complete" }; + xkb_symbols { include "pc+us(dvorak)+inet(evdev)+terminate(ctrl_alt_bksp)" }; + xkb_geometry { include "pc(pc105)" }; +}; +``` + +A detailed explanation of how rules files convert RMLVO to KcCGST is out of +scope for this document. See [the rules file](md_doc_rules-format.html) page +instead. + + +## Adding a layout + +Adding a layout requires that the user adds **symbols** in the correct location. + +The default rules files (usually `evdev`) have a catch-all to map a layout, say +"foo", and a variant, say "bar", into the "bar" section in the file +`$xkb_base_dir/symbols/foo`. +This is sufficient to define a new keyboard layout. The example below defines +the keyboard layout "banana" with an optional variant "orange" + +``` +$ cat $XDG_CONFIG_HOME/xkb/symbols/banana +// Like a US layout but swap the top row so numbers are on Shift +default partial alphanumeric_keys +xkb_symbols "basic" { + include "us(basic)" + name[Group1]= "Banana (US)"; + + key <AE01> { [ exclam, 1] }; + key <AE02> { [ at, 2] }; + key <AE03> { [ numbersign, 3] }; + key <AE04> { [ dollar, 4] }; + key <AE05> { [ percent, 5] }; + key <AE06> { [ asciicircum, 6] }; + key <AE07> { [ ampersand, 7] }; + key <AE08> { [ asterisk, 8] }; + key <AE09> { [ parenleft, 9] }; + key <AE10> { [ parenright, 0] }; + key <AE11> { [ underscore, minus] }; + key <AE12> { [ plus, equal] }; +}; + +// Same as banana but map the euro sign to the 5 key +partial alphanumeric_keys +xkb_symbols "orange" { + include "banana(basic)" + name[Group1] = "Banana (Eurosign on 5)"; + include "eurosign(5)" +}; +``` + +The `default` section is loaded when no variant is given. The first example +sections uses ``include`` to populate with a symbols list defined elsewhere +(here: section `basic` from the file `symbols/us`, aka. the default US keyboard +layout) and overrides parts of these +symbols. The effect of this section is to swap the numbers and symbols in the +top-most row (compared to the US layout) but otherwise use the US layout. + +The "orange" variant uses the "banana" symbols and includes a different section +to define the eurosign. It does not specificially override any symbols. + +The exact details of how `xkb_symbols` work is out of scope for this document. + +## Adding an option + +For technical reasons, options do **not** have a catch-all to map option names +to files and sections and must be specifically mapped by the user. This requires +a custom rules file. As the `evdev` ruleset is hardcoded in many clients, the +custom rules file must usually be named `evdev`. + +``` +$ cat $XDG_CONFIG_HOME/xkb/rules/evdev +! option = symbols + custom:foo = +custom(bar) + custom:baz = +other(baz) + +! include %S/evdev +``` + +This rules file maps the RMLVO option "custom:foo" to the "bar" section in the +`symbols/custom` file and the "custom:baz" option to the "baz" section in the +`symbols/other` file. Note how the RMLVO option name may be different to the +file or section name. + +The `include` statement includes the system-provided `evdev` ruleset. This +allows users to only override those options they need. + +The files themselves are similar to the layout examples in the previous section: + +``` +$ cat $XDG_CONFIG_HOME/xkb/symbols/custom +// map the Tilde key to nothing on the first shift level +partial alphanumeric_keys +xkb_symbols "bar" { + key <TLDE> { [ VoidSymbol ] }; +}; + +$ cat $XDG_CONFIG_HOME/xkb/symbols/other +// map first key in bottom row (Z in the US layout) to k/K +partial alphanumeric_keys +xkb_symbols "baz" { + key <AB01> { [ k, K ] }; +}; +``` + +With these in place, a user may select any layout/variant together with +the "custom:foo" and/or "custom:baz" options. + +## Discoverable layouts + +**The below requires libxkbregistry as XKB lookup tool and does not work where +clients parse the XML file directly**. + +The above sections apply only to the data files and require that the user knows +about the existence of the new entries. To make custom entries discoverable by +the configuration tools (e.g. the GNOME Control Center), the new entries must +also be added to the XML file that is parsed by libxkbregistry. In most cases, +this is the `evdev.xml` file in the rules directory. The example below shows the +XML file that would add the custom layout and custom options as outlined above +to the XKB registry: + +``` +$ cat $XDG_CONFIG_HOME/xkb/rules/evdev.xml +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE xkbConfigRegistry SYSTEM "xkb.dtd"> +<xkbConfigRegistry version="1.1"> + <layoutList> + <layout> + <configItem> + <name>banana</name> + <shortDescription>ban</shortDescription> + <description>Banana</description> + </configItem> + <variantList> + <variant> + <configItem> + <name>orange</name> + <shortDescription>or</shortDescription> + <description>Orange (Banana)</description> + </variant> + </variantList> + </layoutList> + <optionList> + <group allowMultipleSelection="true"> + <configItem> + <name>custom</name> + <description>Custom options</description> + </configItem> + <option> + <configItem> + <name>custom:foo</name> + <description>Map Tilde to nothing</description> + </configItem> + </option> + <option> + <configItem> + <name>custom:baz</name> + <description>Map Z to K</description> + </configItem> + </option> + </group> + </optionList> +</xkbConfigRegistry> +``` + +The default behavior of libxkbregistry ensures that the new layout and options +are added to the system-provided layouts and options. + +For details on the XML format, see DTD in `<datadir>/X11/xkb/rules/xkb.dtd` +and the system-provided XML files in `<datadir>/X11/xkb/rulies/xkb.dtd`. |
