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