quick-guide: fix xkb_state_key_get_syms() example
[platform/upstream/libxkbcommon.git] / doc / quick-guide.md
1 # Quick Guide
2
3 ## Intro
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. So
31 let'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
42 The xkb_context contains the keymap include paths, the log level and
43 functions, and other general customizable administrativia.
44
45 Next we need to create a keymap, xkb_keymap. There are different ways to
46 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     struct xkb_rule_names names = <...>;
58
59     keymap = xkb_keymap_new_from_names(ctx, &names,
60                                        XKB_KEYMAP_COMPILE_NO_FLAGS);
61     if (!keymap) <error>
62 ~~~
63
64 If we are a Wayland client, the compositor gives us a string complete
65 with a keymap. In this case, we can create the keymap object like this:
66
67 ~~~{.c}
68     const char *keymap_string = <...>;
69
70     keymap = xkb_keymap_new_from_string(ctx, keymap_string,
71                                         XKB_KEYMAP_FORMAT_TEXT_V1,
72                                         XKB_KEYMAP_COMPILE_NO_FLAGS);
73     if (!keymap) <error>
74 ~~~
75
76 If we are an X11 client, we are better off getting the keymap from the
77 X server directly. For this we need to choose the XInput device; here
78 we will use the core keyboard device:
79
80 ~~~{.c}
81     #include <xkbcommon/xkbcommon-x11.h>
82
83     xcb_connection_t *conn = <...>;
84     int32_t device_id;
85
86     device_id = xkb_x11_get_core_keyboard_device_id(conn);
87     if (device_id == -1) <error>
88
89     keymap = xkb_x11_keymap_new_from_device(ctx, conn, device_id,
90                                             XKB_KEYMAP_COMPILE_NO_FLAGS);
91     if (!keymap) <error>
92 ~~~
93
94 Now that we have the keymap, we are ready to handle the keyboard devices.
95 For each device, we create an xkb_state:
96
97 ~~~{.c}
98     struct xkb_state *state;
99
100     state = xkb_state_new(keymap);
101     if (!state) <error>
102 ~~~
103
104 For X11/XCB clients, this is better:
105
106 ~~~{.c}
107     state = xkb_x11_state_new_from_device(keymap, conn, device_id);
108     if (!state) <error>
109 ~~~
110
111 When we have an xkb_state for a device, we can start handling key events
112 from it.  Given a keycode for a key, we can get its keysym:
113
114 ~~~{.c}
115     <key event structure> event;
116     xkb_keycode_t keycode;
117     xkb_keysym_t keysym;
118
119     keycode = event->keycode;
120     keysym = xkb_state_key_get_one_sym(state, keycode);
121 ~~~
122
123 We can see which keysym we got, and get its name:
124
125 ~~~{.c}
126     char keysym_name[64];
127
128     if (keysym == XKB_KEY_Space)
129         <got a space>
130
131     xkb_keysym_get_name(keysym, keysym_name, sizeof(keysym_name));
132 ~~~
133
134 libxkbcommon also supports an extension to the classic XKB, whereby a
135 single event can result in multiple keysyms. Here's how to use it:
136
137 ~~~{.c}
138     const xkb_keysym_t *keysyms;
139     int num_keysyms;
140
141     num_keysyms = xkb_state_key_get_syms(state, keycode, &keysyms);
142 ~~~
143
144 We can also get a UTF-8 string representation for this key:
145
146 ~~~{.c}
147     char *buffer;
148     int size;
149
150     // First find the needed size; return value is the same as snprintf(3).
151     size = xkb_state_key_get_utf8(state, keycode, NULL, 0) + 1;
152     if (size <= 1) <nothing to do>
153     buffer = <allocate size bytes>
154
155     xkb_state_key_get_utf8(state, keycode, buffer, size);
156 ~~~
157
158 Of course, we also need to keep the xkb_state up-to-date with the
159 keyboard device, if we want to get the correct keysyms in the future.
160
161 If we are an evdev client, we must let the library know whether a key
162 is pressed or released at any given time:
163
164 ~~~{.c}
165     enum xkb_state_component changed;
166
167     if (<key press>)
168         changed = xkb_state_update_key(state, keycode, XKB_KEY_DOWN);
169     else if (<key release>)
170         changed = xkb_state_update_key(state, keycode, XKB_KEY_UP);
171 ~~~
172
173 The `changed` return value tells us exactly which parts of the state
174 have changed.
175
176 If is is a key-repeat event, we can ask the keymap what to do with it:
177
178 ~~~{.c}
179     if (<key repeat> && !xkb_keymap_key_repeats(keymap, keycode))
180         <discard event>
181 ~~~
182
183 On the other hand, if we are an X or Wayland client, the server already
184 does the hard work for us. It notifies us when the device's state
185 changes, and we can simply use what it tells us (the necessary
186 information usually comes in a form of some "state changed" event):
187
188 ~~~{.c}
189     changed = xkb_state_update_mask(state,
190                                     event->depressed_mods,
191                                     event->latched_mods,
192                                     event->locked_mods,
193                                     event->depressed_layout,
194                                     event->latched_layout,
195                                     event->locked_layout);
196 ~~~
197
198 Now that we have an always-up-to-date xkb_state, we can examine it.
199 For example, we can check whether the Control modifier is active, or
200 whether the Num Lock LED is active:
201
202 ~~~{.c}
203     if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL,
204                                      XKB_STATE_MODS_EFFECTIVE) > 0)
205         <The Control modifier is active>
206
207     if (xkb_state_led_name_is_active(state, XKB_LED_NAME_NUM) > 0)
208         <The Num Lock LED is active>
209 ~~~
210
211 And that's it! When we're finished, we should free the objects we've
212 created:
213
214 ~~~{.c}
215     xkb_state_unref(state);
216     xkb_keymap_unref(keymap);
217     xkb_context_unref(ctx);
218 ~~~