03 October 2009

xkbswitch - simple keyboard layout switcher for X11

I've been thinking of what to post here for a long time and couldn't find anything interesting, useful and at the same time that is not copy-pasted from somewhere else in Internet. Today I was just searching for a source of one my tiny utility and realized that firstly it is useful (as I'm searching for it after a year passed when I wrote it) and secondly it cannot be a duplicate of anything from the Internet because I have written it by myself :)

So here is the prehistory: I am trying to build a handy and lightweight desktop environment based on Linux (or FreeBSD) at home long since. So I am not the one using Gnome, KDE and even XFCE. Now I am pretty satisfied with Arch Linux and Openbox with a few utilities (I can write separate post about my environment if someone would be interested. Just for info my desktop uses 68 Mb of RAM when it starts). Another aspect of my non-standard requirements is that I'm used to switch keyboard layouts using separate hotkeys for each layout. (For example I am using Ctrl+Shift+1 for English, Ctrl+Shift+2 for Russian and Ctrl+Shift+3 for Ukrainian.) Xxkb cannot handle such things, so the only way is some kind of thirdparty tool. I know two programs that can behave the way I need (well... the first one I am actively using and the second one should also handle different hotkeys, but I haven't checked it personally), they are xneur and kkbswitch. I like xneur very much but it stucks in Arch and further keyboard input is impossible until xneur is restarted. I am using it at work on Ubuntu 9.10 and everything is ok, so I don't know whether it is a bug of xneur or Arch's one. Kkbswitch is designed for KDE and depends on it's libraries, that is why I haven't even tried it.

Been stuck with all this for some time I opened sources off xxkb and taken the "engine" of it. (I just needed xxkb because I have never dealt with Xlib and wanted to get something working ASAP.) So the idea was to make a command line tool which would enable the layout given as it's argument. What for? To use it with hotkeys handled by your window manager :). Almost any WM allows you to define custom hotkeys. Given the above it is very easy to achieve the behavior I wanted. Here is the source of layout switching utility:

#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#include <X11/Xlib.h>
#include <X11/XKBlib.h>

void PrintUsage();

int
main(int argc, char **argv)
{
    int xkbGroup;
    if (argc < 2 || (xkbGroup = atoi(argv[1])) < 0 || xkbGroup > 3)
    {
        PrintUsage();
        exit(0);
    }

    int xkbEventType, xkbError, xkbReason;
    int mjr = XkbMajorVersion, mnr = XkbMinorVersion;
    Display *display = NULL;

    display = XkbOpenDisplay(NULL, &xkbEventType, &xkbError,
   &mjr, &mnr, &xkbReason);
    if (NULL == display)
    {
        warnx("Cannot open X display %s", XDisplayName(NULL));
        switch (xkbReason)
        {
            case XkbOD_BadServerVersion:
            case XkbOD_BadLibraryVersion:
                warnx("Incomatible versions of client and server xkb libraries");
                break;
            case XkbOD_ConnectionRefused:
                warnx("Connection to X server refused");
                break;
            case XkbOD_NonXkbServer:
                warnx("XKB extension is not present");
                break;
            default:
                warnx("Unknown error from XkbOpenDisplay: %d", xkbReason);
                break;
        }
        exit(1);
    }

    Bool status = XkbLockGroup(display, XkbUseCoreKbd, xkbGroup);

    XCloseDisplay(display);

    return status ? 0 : 1;
}

void
PrintUsage()
{
    printf("Usage: xkbswitch [0-3] sets keyboard layout\n");
}

Use cc -I/usr/include -L/usr/lib -lX11 -o xkbswitch xkbswitch.c to compile it. Using it is simple and straightforward too: xxkbswitch 0 enables layout with index 0 (in my case Ctrl+Shift+1 executes xkbswitch 0 and sets English layout, xkbswitch 1 and sets Russian).

6 comments:

K said...

Доброго времени суток! Сегодня поставил себе на Арх Линукс dwm. Пока что я в полном восторге, за исключением проблемы смены раскладки с русского на испанский и обратно. Мой вопрос таков - где мне задать раскладки которые будет использовать моя оболочка?

Далее, как я понимаю, этот скрипт я должен вписать в конфигурацию dwm, так?

П.Д.: Сейчас пишу через транслит.ру

Заранее спасибо.

Привет из Мексики :)

Kirill Malyshev said...

1. раскладка задаётся не для оболочки, а для X сервера - либо через /etc/X11/xorg.conf, либо /etc/X11/xorg.conf.d/
смотри на Arch Linux wiki например

2. в посте не скрипт, а исходник на C, который надо скомпилить

как добавить хоткей в dwm - смотри в доках dwm http://dwm.suckless.org/customisation/customfuncs

Deday said...

Спасибо за сорсы. Теперь собираюсь поюзать откомпиленый бинарник для автоматической смены раскладок в виме при переключении режимов.

Kirill Malyshev said...

спасиб Ивану Паскалю за xxkb ;)

Андрей said...

Спасибо огромное! Убил целый вечер чтобы навешать отдельные шорткаты на каждую раскладку и чтобы при переключении xxkb менял изображение. Уже собирался свой велосипед клепать, но видимо, не судьба)

Kirill Malyshev said...

;) welcome!