Finding the language for a xkb keyboard

During the last days I was working on keyboarding issues on Linux. In our app we want to display the (xkb) keyboards that the user has installed and that are visible in the gnome panel. Displaying them is relatively easy, but then I also needed the language that is associated with the keyboard.

libxklavier provides the necessary methods but isn’t exactly well documented. It took quite a bit of trying and searching for apps that provide similar functionality. Eventually I found what I needed in gnome-control-center, file gnome-keyboard-properties-xkbltadd.c.

To get a list of languages libxklavier provides the method xkl_config_registry_foreach_language; and there’s also xkl_config_registry_foreach_language_variant that can be called for each language. What I didn’t understand first is that the TwoConfigItemsProcessFunc callback method sometimes gets called with config_item == NULL. It is important not to ignore these calls since these are the default layouts. Additionally, the country that you also need to build a proper locale string is conveyed in the parent_config_item.

Below is some sample code that lists all languages with their keyboard layouts. Beware that the language and variants are separated by a tab character in xkb_id.

#include <string.h>
#include <libgnomekbd/gkbd-keyboard-drawing.h>
#include <libgnomekbd/gkbd-keyboard-config.h>

char * description_utf8 (XklConfigRegistry * config_registry, const char * name)
{
    char *l, *sl, *v, *sv;
    char *v1, *utf_name;
    if (gkbd_keyboard_config_get_descriptions(config_registry, name, &sl, &l, &sv, &v))
        name = gkbd_keyboard_config_format_full_layout (l, v);
    v1 = g_strdup(name);
    utf_name = g_locale_to_utf8(g_strstrip(v1), -1, NULL, NULL, NULL);
    g_free(v1);
    return utf_name;
}

char * desc_to_utf8 (XklConfigItem * ci)
{
    char *sd = g_strstrip(ci->description);
    return sd[0] == 0 ? g_strdup(ci->name) : g_locale_to_utf8(sd, -1, NULL, NULL, NULL);
}

static void print_language_variant(
    XklConfigRegistry * config_registry, XklConfigItem * parent_config_item,
    XklConfigItem * config_item, void * data)
{
    char *utf_variant_name = config_item ?
        description_utf8(config_registry, gkbd_keyboard_config_merge_items(parent_config_item->name, config_item->name)) :
        desc_to_utf8(parent_config_item);

    const gchar *xkb_id = config_item ?
        gkbd_keyboard_config_merge_items(parent_config_item->name, config_item->name) :
        parent_config_item->name;

    printf("\t%s: %s\n", xkb_id, utf_variant_name);
    g_free (utf_variant_name);
}

static void LanguageVariants(XklConfigRegistry * reg, XklConfigItem * item, char * data)
{
    printf("Adding variants for language %s (%s)\n", item->name, item->description);
    xkl_config_registry_foreach_language_variant(reg, item->name,
        (TwoConfigItemsProcessFunc)print_language_variant, data);
}

int main (int argc, char *argv[])
{
    gtk_init(&argc, &argv);
    Display * disp = XOpenDisplay(NULL);
    XklEngine * eng = xkl_engine_get_instance(disp);

    XklConfigRegistry* reg = xkl_config_registry_get_instance(eng);
    if (xkl_config_registry_load(reg, TRUE))
    {
        xkl_config_registry_foreach_language(reg, (ConfigItemProcessFunc)LanguageVariants, NULL);
    }
    return 0;
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: