From aa3e82364249e93d05b0c3eed4b050ec5d038478 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Sun, 23 Mar 2014 14:32:12 +0200 Subject: [PATCH] doc: add a quick guide to the library This is a nice intro to the documentation, and also preferably gently pushes users to the "proper way" of using the library, which can be confusing. See also: http://fooishbar.org/tell-me-about/xkbcommon-intro/ Signed-off-by: Ran Benita --- README | 4 + doc/Doxyfile.in | 3 +- doc/quick-guide.md | 218 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 doc/quick-guide.md diff --git a/README b/README index 6b99c46..22c6b1e 100644 --- a/README +++ b/README @@ -19,6 +19,10 @@ current distributions for their X11 XKB data. More information on xkeyboard-config is available here: http://www.freedesktop.org/wiki/Software/XKeyboardConfig +Quick Guide +=========== + +See [Quick Guide](doc/quick-guide.md). API === diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index bc4f78e..57b58ee 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -655,7 +655,8 @@ WARN_LOGFILE = # with spaces. INPUT = @abs_top_srcdir@/xkbcommon \ - @abs_top_srcdir@/README + @abs_top_srcdir@/README \ + @abs_top_srcdir@/doc/quick-guide.md # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is diff --git a/doc/quick-guide.md b/doc/quick-guide.md new file mode 100644 index 0000000..6b336a4 --- /dev/null +++ b/doc/quick-guide.md @@ -0,0 +1,218 @@ +# Quick Guide + +## Intro + +This document contains a quick walk-through of the often-used parts of +the library. We will employ a few use-cases to lead the examples: + +1. An evdev client. "evdev" is the Linux kernel's input subsystem; it + only reports to the client which keys are pressed and released. + +2. An X11 client, using the XCB library to communicate with the X + server and the xcb-xkb library for using the XKB protocol. + +3. A Wayland client, using the standard protocol. + +The snippets are not complete, and some support code is omitted. You +can find complete and more complex examples in the source directory: + +1. test/interactive-evdev.c contains an interactive evdev client. + +2. test/interactive-x11.c contains an interactive X11 client. + +Also, the library contains many more functions for examining and using +the library context, the keymap and the keyboard state. See the +hyper-linked reference documentation or go through the xkbcommon/*.h +header files for more details. + +## Code + +Before we can do anything interesting, we need a library context. So +let's create one: + +~~~{.c} + #include + + struct xkb_context ctx; + + ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!ctx) +~~~ + +The xkb_context contains the keymap include paths, the log level and +functions, and other general customizable administrativia. + +Next we need to create a keymap, xkb_keymap. There are different ways to +do this. + +If we are an evdev client, we have nothing to go by, so we need to ask +the user for his/her keymap preferences (for example, an Icelandic +keyboard with a Dvorak layout). The configuration format is commonly +called RMLVO (Rules+Model+Layout+Variant+Options), the same format used +by the X server. With it, we can fill a struct called xkb_rule_names; +passing NULL chooses the system's default. + +~~~{.c} + struct xkb_keymap *keymap; + struct xkb_rule_names names = <...>; + + keymap = xkb_keymap_new_from_names(ctx, &names, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) +~~~ + +If we are a Wayland client, the compositor gives us a string complete +with a keymap. In this case, we can create the keymap object like this: + +~~~{.c} + const char *keymap_string = <...>; + + keymap = xkb_keymap_new_from_string(ctx, keymap_string, + XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) +~~~ + +If we are an X11 client, we are better off getting the keymap from the +X server directly. For this we need to choose the XInput device; here +we will use the core keyboard device: + +~~~{.c} + #include + + xcb_connection_t *conn = <...>; + int32_t device_id; + + device_id = xkb_x11_get_core_keyboard_device_id(conn); + if (device_id == -1) + + keymap = xkb_x11_keymap_new_from_device(ctx, conn, device_id, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) +~~~ + +Now that we have the keymap, we are ready to handle the keyboard devices. +For each device, we create an xkb_state: + +~~~{.c} + struct xkb_state *state; + + state = xkb_state_new(keymap); + if (!state) +~~~ + +For X11/XCB clients, this is better: + +~~~{.c} + state = xkb_x11_state_new_from_device(keymap, conn, device_id); + if (!state) +~~~ + +When we have an xkb_state for a device, we can start handling key events +from it. Given a keycode for a key, we can get its keysym: + +~~~{.c} + event; + xkb_keycode_t keycode; + xkb_keysym_t keysym; + + keycode = event->keycode; + keysym = xkb_state_key_get_one_sym(state, keycode); +~~~ + +We can see which keysym we got, and get its name: + +~~~{.c} + char[64] keysym_name; + + if (keysym == XKB_KEY_Space) + + + xkb_keysym_get_name(keysym, keysym_name, sizeof(keysym_name)); +~~~ + +libxkbcommon also supports an extension to the classic XKB, whereby a +single event can result in multiple keysyms. Here's how to use it: + +~~~{.c} + const xkb_keysym_t *keysyms; + int num_keysyms; + + num_keysyms = xkb_state_key_get_syms(state, keycode); +~~~ + +We can also get a UTF-8 string representation for this key: + +~~~{.c} + char *buffer; + int size; + + // First find the needed size; return value is the same as snprintf(3). + size = xkb_state_key_get_utf8(state, keycode, NULL, 0) + 1; + if (size <= 1) + buffer = + + xkb_state_key_get_utf8(state, keycode, buffer, size); +~~~ + +Of course, we also need to keep the xkb_state up-to-date with the +keyboard device, if we want to get the correct keysyms in the future. + +If we are an evdev client, we must let the library know whether a key +is pressed or released at any given time: + +~~~{.c} + enum xkb_state_component changed; + + if () + changed = xkb_state_update_key(state, keycode, XKB_KEY_DOWN); + else if () + changed = xkb_state_update_key(state, keycode, XKB_KEY_UP); +~~~ + +The `changed` return value tells us exactly which parts of the state +have changed. + +If is is a key-repeat event, we can ask the keymap what to do with it: + +~~~{.c} + if ( && !xkb_keymap_key_repeats(keymap, keycode)) + +~~~ + +On the other hand, if we are an X or Wayland client, the server already +does the hard work for us. It notifies us when the device's state +changes, and we can simply use what it tells us (the necessary +information usually comes in a form of some "state changed" event): + +~~~{.c} + changed = xkb_state_update_mask(state, + event->depressed_mods, + event->latched_mods, + event->locked_mods, + event->depressed_layout, + event->latched_layout, + event->locked_layout); +~~~ + +Now that we have an always-up-to-date xkb_state, we can examine it. +For example, we can check whether the Control modifier is active, or +whether the Num Lock LED is active: + +~~~{.c} + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, + XKB_STATE_MODS_EFFECTIVE) > 0) + + + if (xkb_state_led_name_is_active(state, XKB_LED_NAME_NUM) > 0) + +~~~ + +And that's it! When we're finished, we should free the objects we've +created: + +~~~{.c} + xkb_state_unref(state); + xkb_keymap_unref(keymap); + xkb_context_unref(ctx); +~~~ -- 2.7.4