Home | History | Annotate | Download | only in doc
      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. 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. This is an immutable object
     46 which contains all of the information about the keys, layouts, etc. There
     47 are different ways to do this.
     48 
     49 If we are an evdev client, we have nothing to go by, so we need to ask
     50 the user for his/her keymap preferences (for example, an Icelandic
     51 keyboard with a Dvorak layout). The configuration format is commonly
     52 called RMLVO (Rules+Model+Layout+Variant+Options), the same format used
     53 by the X server. With it, we can fill a struct called xkb_rule_names;
     54 passing 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 
     72 If we are a Wayland client, the compositor gives us a string complete
     73 with 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 
     85 If we are an X11 client, we are better off getting the keymap from the
     86 X server directly. For this we need to choose the XInput device; here
     87 we 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 
    103 Now that we have the keymap, we are ready to handle the keyboard devices.
    104 For each device, we create an xkb_state, which remembers things like which
    105 keyboard 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 
    114 For 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 
    121 When we have an xkb_state for a device, we can start handling key events
    122 from 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 
    133 We 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 
    144 libxkbcommon also supports an extension to the classic XKB, whereby a
    145 single 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 
    154 We 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 
    168 Of course, we also need to keep the xkb_state up-to-date with the
    169 keyboard device, if we want to get the correct keysyms in the future.
    170 
    171 If we are an evdev client, we must let the library know whether a key
    172 is 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 
    183 The `changed` return value tells us exactly which parts of the state
    184 have changed.
    185 
    186 If 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 
    193 On the other hand, if we are an X or Wayland client, the server already
    194 does the hard work for us. It notifies us when the device's state
    195 changes, and we can simply use what it tells us (the necessary
    196 information 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 
    208 Now that we have an always-up-to-date xkb_state, we can examine it.
    209 For example, we can check whether the Control modifier is active, or
    210 whether 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 
    221 And that's it! When we're finished, we should free the objects we've
    222 created:
    223 
    224 ~~~{.c}
    225     xkb_state_unref(state);
    226     xkb_keymap_unref(keymap);
    227     xkb_context_unref(ctx);
    228 ~~~
    229