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;
}