• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Quick Guide
2
3## Introduction
4
5This document contains a quick walk-through of the often-used parts of
6the library. We will employ a few use-cases to lead the examples:
7
81. An evdev client. "evdev" is the Linux kernel's input subsystem; it
9   only reports to the client which keys are pressed and released.
10
112. An X11 client, using the XCB library to communicate with the X
12   server and the xcb-xkb library for using the XKB protocol.
13
143. A Wayland client, using the standard protocol.
15
16The snippets are not complete, and some support code is omitted. You
17can find complete and more complex examples in the source directory:
18
191. test/interactive-evdev.c contains an interactive evdev client.
20
212. test/interactive-x11.c contains an interactive X11 client.
22
23Also, the library contains many more functions for examining and using
24the library context, the keymap and the keyboard state. See the
25hyper-linked reference documentation or go through the header files in
26xkbcommon/ for more details.
27
28## Code
29
30Before we can do anything interesting, we need a library context. So
31let's create one:
32
33~~~{.c}
34    #include <xkbcommon/xkbcommon.h>
35
36    struct xkb_context ctx;
37
38    ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
39    if (!ctx) <error>
40~~~
41
42The xkb_context contains the keymap include paths, the log level and
43functions, and other general customizable administrativia.
44
45Next we need to create a keymap, xkb_keymap. This is an immutable object
46which contains all of the information about the keys, layouts, etc. There
47are different ways to do this.
48
49If we are an evdev client, we have nothing to go by, so we need to ask
50the user for his/her keymap preferences (for example, an Icelandic
51keyboard with a Dvorak layout). The configuration format is commonly
52called RMLVO (Rules+Model+Layout+Variant+Options), the same format used
53by the X server. With it, we can fill a struct called xkb_rule_names;
54passing NULL chooses the system's default.
55
56~~~{.c}
57    struct xkb_keymap *keymap;
58    /* Example RMLVO for Icelandic Dvorak. */
59    struct xkb_rule_names names = {
60        .rules = NULL,
61        .model = "pc105",
62        .layout = "is",
63        .variant = "dvorak",
64        .options = "terminate:ctrl_alt_bksp"
65    };
66
67    keymap = xkb_keymap_new_from_names(ctx, &names,
68                                       XKB_KEYMAP_COMPILE_NO_FLAGS);
69    if (!keymap) <error>
70~~~
71
72If we are a Wayland client, the compositor gives us a string complete
73with a keymap. In this case, we can create the keymap object like this:
74
75~~~{.c}
76    /* From the wl_keyboard::keymap event. */
77    const char *keymap_string = <...>;
78
79    keymap = xkb_keymap_new_from_string(ctx, keymap_string,
80                                        XKB_KEYMAP_FORMAT_TEXT_V1,
81                                        XKB_KEYMAP_COMPILE_NO_FLAGS);
82    if (!keymap) <error>
83~~~
84
85If we are an X11 client, we are better off getting the keymap from the
86X server directly. For this we need to choose the XInput device; here
87we will use the core keyboard device:
88
89~~~{.c}
90    #include <xkbcommon/xkbcommon-x11.h>
91
92    xcb_connection_t *conn = <...>;
93    int32_t device_id;
94
95    device_id = xkb_x11_get_core_keyboard_device_id(conn);
96    if (device_id == -1) <error>
97
98    keymap = xkb_x11_keymap_new_from_device(ctx, conn, device_id,
99                                            XKB_KEYMAP_COMPILE_NO_FLAGS);
100    if (!keymap) <error>
101~~~
102
103Now that we have the keymap, we are ready to handle the keyboard devices.
104For each device, we create an xkb_state, which remembers things like which
105keyboard modifiers and LEDs are active:
106
107~~~{.c}
108    struct xkb_state *state;
109
110    state = xkb_state_new(keymap);
111    if (!state) <error>
112~~~
113
114For X11/XCB clients, this is better:
115
116~~~{.c}
117    state = xkb_x11_state_new_from_device(keymap, conn, device_id);
118    if (!state) <error>
119~~~
120
121When we have an xkb_state for a device, we can start handling key events
122from it.  Given a keycode for a key, we can get its keysym:
123
124~~~{.c}
125    <key event structure> event;
126    xkb_keycode_t keycode;
127    xkb_keysym_t keysym;
128
129    keycode = event->keycode;
130    keysym = xkb_state_key_get_one_sym(state, keycode);
131~~~
132
133We can see which keysym we got, and get its name:
134
135~~~{.c}
136    char keysym_name[64];
137
138    if (keysym == XKB_KEY_Space)
139        <got a space>
140
141    xkb_keysym_get_name(keysym, keysym_name, sizeof(keysym_name));
142~~~
143
144libxkbcommon also supports an extension to the classic XKB, whereby a
145single event can result in multiple keysyms. Here's how to use it:
146
147~~~{.c}
148    const xkb_keysym_t *keysyms;
149    int num_keysyms;
150
151    num_keysyms = xkb_state_key_get_syms(state, keycode, &keysyms);
152~~~
153
154We can also get a UTF-8 string representation for this key:
155
156~~~{.c}
157    char *buffer;
158    int size;
159
160    // First find the needed size; return value is the same as snprintf(3).
161    size = xkb_state_key_get_utf8(state, keycode, NULL, 0) + 1;
162    if (size <= 1) <nothing to do>
163    buffer = <allocate size bytes>
164
165    xkb_state_key_get_utf8(state, keycode, buffer, size);
166~~~
167
168Of course, we also need to keep the xkb_state up-to-date with the
169keyboard device, if we want to get the correct keysyms in the future.
170
171If we are an evdev client, we must let the library know whether a key
172is pressed or released at any given time:
173
174~~~{.c}
175    enum xkb_state_component changed;
176
177    if (<key press>)
178        changed = xkb_state_update_key(state, keycode, XKB_KEY_DOWN);
179    else if (<key release>)
180        changed = xkb_state_update_key(state, keycode, XKB_KEY_UP);
181~~~
182
183The `changed` return value tells us exactly which parts of the state
184have changed.
185
186If is is a key-repeat event, we can ask the keymap what to do with it:
187
188~~~{.c}
189    if (<key repeat> && !xkb_keymap_key_repeats(keymap, keycode))
190        <discard event>
191~~~
192
193On the other hand, if we are an X or Wayland client, the server already
194does the hard work for us. It notifies us when the device's state
195changes, and we can simply use what it tells us (the necessary
196information usually comes in a form of some "state changed" event):
197
198~~~{.c}
199    changed = xkb_state_update_mask(state,
200                                    event->depressed_mods,
201                                    event->latched_mods,
202                                    event->locked_mods,
203                                    event->depressed_layout,
204                                    event->latched_layout,
205                                    event->locked_layout);
206~~~
207
208Now that we have an always-up-to-date xkb_state, we can examine it.
209For example, we can check whether the Control modifier is active, or
210whether the Num Lock LED is active:
211
212~~~{.c}
213    if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL,
214                                     XKB_STATE_MODS_EFFECTIVE) > 0)
215        <The Control modifier is active>
216
217    if (xkb_state_led_name_is_active(state, XKB_LED_NAME_NUM) > 0)
218        <The Num Lock LED is active>
219~~~
220
221And that's it! When we're finished, we should free the objects we've
222created:
223
224~~~{.c}
225    xkb_state_unref(state);
226    xkb_keymap_unref(keymap);
227    xkb_context_unref(ctx);
228~~~
229