aboutsummaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2020-09-08 17:10:03 -0700
committerHaibo Huang <hhb@google.com>2020-09-10 22:20:42 +0000
commitbffa8499cb8ce3cc4366055be8fe62d501d6a8e5 (patch)
tree648dfaada5799a6227dd5f1af43d89ed8d71d96d /doc
parente4e474780d90ed6166f7113a7464371baa275007 (diff)
downloadplatform_external_libxkbcommon-master.tar.gz
platform_external_libxkbcommon-master.tar.bz2
platform_external_libxkbcommon-master.zip
Upgrade libxkbcommon to xkbcommon-1.0.0HEADmaster
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/.gitignore2
-rw-r--r--doc/Doxyfile.in47
-rw-r--r--doc/compat.md56
-rw-r--r--doc/doxygen-extra.css9
-rw-r--r--doc/keymap-format-text-v1.md368
-rw-r--r--doc/quick-guide.md229
-rw-r--r--doc/rules-format.md109
-rw-r--r--doc/user-configuration.md230
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`.