5 This document contains a quick walk-through of the often-used parts of
6 the library. We will employ a few use-cases to lead the examples:
8 1. An evdev client. "evdev" is the Linux kernel's input subsystem; it
9 only reports to the client which keys are pressed and released.
11 2. An X11 client, using the XCB library to communicate with the X
12 server and the xcb-xkb library for using the XKB protocol.
14 3. A Wayland client, using the standard protocol.
16 The snippets are not complete, and some support code is omitted. You
17 can find complete and more complex examples in the source directory:
19 1. test/interactive-evdev.c contains an interactive evdev client.
21 2. test/interactive-x11.c contains an interactive X11 client.
23 3. test/interactive-wayland.c contains an interactive Wayland client.
25 Also, the library contains many more functions for examining and using
26 the library context, the keymap and the keyboard state. See the
27 hyper-linked reference documentation or go through the header files in
28 xkbcommon/ for more details.
32 Before we can do anything interesting, we need a library context:
35 #include <xkbcommon/xkbcommon.h>
37 struct xkb_context *ctx;
39 ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
43 The `xkb_context` contains the keymap include paths, the log level and
44 functions, and other general customizable administrativia.
46 Next we need to create a keymap, `xkb_keymap`. This is an immutable object
47 which contains all of the information about the keys, layouts, etc. There
48 are different ways to do this.
50 If we are an evdev client, we have nothing to go by, so we need to ask
51 the user for his/her keymap preferences (for example, an Icelandic
52 keyboard with a Dvorak layout). The configuration format is commonly
53 called RMLVO (Rules+Model+Layout+Variant+Options), the same format used
54 by the X server. With it, we can fill a struct called `xkb_rule_names`;
55 passing `NULL` chooses the system's default.
58 struct xkb_keymap *keymap;
59 /* Example RMLVO for Icelandic Dvorak. */
60 struct xkb_rule_names names = {
65 .options = "terminate:ctrl_alt_bksp"
68 keymap = xkb_keymap_new_from_names(ctx, &names,
69 XKB_KEYMAP_COMPILE_NO_FLAGS);
73 If we are a Wayland client, the compositor gives us a string complete
74 with a keymap. In this case, we can create the keymap object like this:
77 /* From the wl_keyboard::keymap event. */
78 const char *keymap_string = <...>;
79 struct xkb_keymap *keymap;
81 keymap = xkb_keymap_new_from_string(ctx, keymap_string,
82 XKB_KEYMAP_FORMAT_TEXT_V1,
83 XKB_KEYMAP_COMPILE_NO_FLAGS);
87 If we are an X11 client, we are better off getting the keymap from the
88 X server directly. For this we need to choose the XInput device; here
89 we will use the core keyboard device:
92 #include <xkbcommon/xkbcommon-x11.h>
94 xcb_connection_t *conn = <...>;
97 device_id = xkb_x11_get_core_keyboard_device_id(conn);
98 if (device_id == -1) <error>
100 keymap = xkb_x11_keymap_new_from_device(ctx, conn, device_id,
101 XKB_KEYMAP_COMPILE_NO_FLAGS);
105 Now that we have the keymap, we are ready to handle the keyboard devices.
106 For each device, we create an `xkb_state`, which remembers things like which
107 keyboard modifiers and LEDs are active:
110 struct xkb_state *state;
112 state = xkb_state_new(keymap);
116 For X11/XCB clients, this is better:
119 state = xkb_x11_state_new_from_device(keymap, conn, device_id);
123 When we have an `xkb_state` for a device, we can start handling key events
124 from it. Given a keycode for a key, we can get its keysym:
127 <key event structure> event;
128 xkb_keycode_t keycode;
131 keycode = event->keycode;
132 keysym = xkb_state_key_get_one_sym(state, keycode);
135 We can see which keysym we got, and get its name:
138 char keysym_name[64];
140 if (keysym == XKB_KEY_Space)
143 xkb_keysym_get_name(keysym, keysym_name, sizeof(keysym_name));
146 libxkbcommon also supports an extension to the classic XKB, whereby a
147 single event can result in multiple keysyms. Here's how to use it:
150 const xkb_keysym_t *keysyms;
153 num_keysyms = xkb_state_key_get_syms(state, keycode, &keysyms);
156 We can also get a UTF-8 string representation for this key:
162 // First find the needed size; return value is the same as snprintf(3).
163 size = xkb_state_key_get_utf8(state, keycode, NULL, 0) + 1;
164 if (size <= 1) <nothing to do>
165 buffer = <allocate size bytes>
167 xkb_state_key_get_utf8(state, keycode, buffer, size);
170 Of course, we also need to keep the `xkb_state` up-to-date with the
171 keyboard device, if we want to get the correct keysyms in the future.
173 If we are an evdev client, we must let the library know whether a key
174 is pressed or released at any given time:
177 enum xkb_state_component changed;
180 changed = xkb_state_update_key(state, keycode, XKB_KEY_DOWN);
181 else if (<key release>)
182 changed = xkb_state_update_key(state, keycode, XKB_KEY_UP);
185 The `changed` return value tells us exactly which parts of the state
188 If it is a key-repeat event, we can ask the keymap what to do with it:
191 if (<key repeat> && !xkb_keymap_key_repeats(keymap, keycode))
195 On the other hand, if we are an X or Wayland client, the server already
196 does the hard work for us. It notifies us when the device's state
197 changes, and we can simply use what it tells us (the necessary
198 information usually comes in a form of some "state changed" event):
201 changed = xkb_state_update_mask(state,
202 event->depressed_mods,
205 event->depressed_layout,
206 event->latched_layout,
207 event->locked_layout);
210 Now that we have an always-up-to-date `xkb_state`, we can examine it.
211 For example, we can check whether the Control modifier is active, or
212 whether the Num Lock LED is active:
215 if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL,
216 XKB_STATE_MODS_EFFECTIVE) > 0)
217 <The Control modifier is active>
219 if (xkb_state_led_name_is_active(state, XKB_LED_NAME_NUM) > 0)
220 <The Num Lock LED is active>
223 And that's it! Eventually, we should free the objects we've created:
226 xkb_state_unref(state);
227 xkb_keymap_unref(keymap);
228 xkb_context_unref(ctx);