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