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