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