xkbcommon and my custom Russian phonetic layout
Posted on 01 August 2025 in Articles • 5 min read
The Soviet Union officially dissolved in 1991, but Russian language remained the region's lingua franca for decades. Many children of my generation were simultaneous bilinguals; we spoke both Azeri and Russian since childhood. I learned to type in Russian, but I never ever learned the official Windows Russian keyboard layout, because I didn't have a keyboard with Russian alphabet printed on it. The alternative was a phonetic layout, and I still remember a program called "Alt-Win", which allowed to select Azeri Latin, or Russian phonetic keyboard layouts in Windows 9x. Over the years, I used other tools in Windows XP and Windows 7 to recreate this layout. And then I moved to Linux.
In Linux, the only tool you need to create your own keyboard layout is a text editor. Since you are already reading this, scroll down to feed your curiosity!

Note
In this article, I refer to Russian phonetic keyboard layouts as keyboard layouts where Russian letters are mostly located at their similarly sounding letters in English, on US QWERTY keyboard. For example, the Russian letters "а", "о", "м", "т" are typed using the English "a", "o", "m", "t" keys.
The trick is to map 33 Russian alphabet letters to a keyboard that has only 26 Latin letters (used in English) while retaining the necessary punctuation marks.
Custom layout - the naive way
The naive way to create a custom layout is by modifying an existing variant definition in one of the symbols files from /usr/share/X11/xkb/symbols. That's what I originally did — I modified the ru file and its phonetic section:
1 2 3 4 5 6 7 8 9 10 11 12 | partial alphanumeric_keys xkb_symbols "phonetic" { name[Group1]= "Russia - Phonetic"; key <TLDE> {[ Cyrillic_yu, Cyrillic_YU ]}; key <AE01> {[ 1, exclam ]}; key <AE02> {[ 2, at ]}; key <AE03> {[ 3, numbersign ]}; ... ... } |
Here, the first column contains the symbolic key names [1], the second column contains the corresponding key symbol for a key pressed without modifiers, and the last column contains the key symbol for a key pressed with Shift.
This works, BUT your user needs write permissions for the file, and the file will be overwritten anyway every time XKB gets updated by the system.
Can you believe that for over 15 years I used the same customised ru symbols file, and replaced the upstream file over and over? I did this manually every time the package responsible for /usr/share/X11/xkb got updated. The file followed me as I moved from Ubuntu to Debian, and from Debian to Arch. And honestly speaking, I never bothered to dig deeper and learn the mechanisms behind the command to set up my desired layouts:
setxkbmap -layout 'us,fi,ru,az' -variant ',,phonetic,' -option grp:shifts_toggle
That allowed me to cycle through US, Finnish, Russian phonetic and Azeri layouts by pressing both shifts.
This changed when I installed Arch on my new laptop. I finally decided to find a "smart way" and learn the mechanisms behind layouts in Linux graphical environments.
Bits about XKB
Imagine a system with a graphical environment backed by Wayland compositor. Let's find out how pressing a key on the keyboard results in a symbol appearing in an application. I'll omit deep technicalities to keep the narrative short.
- Wayland compositor notifies the application about the current keymap configuration. This happens when application starts or the user changes keyboard layout. The application loads the keymap via xkbcommon library.
- The keyboard device sends a hardware signal - a scancode to the Linux Kernel.
- The kernel's evdev subsystem maps the scancode to a keycode - a representation abstracted from hardware.
- Wayland compositor uses libinput to receive keyboard and other input device events from the kernel. It notifies the application (a Wayland client) about a pressed/released key with a keycode, and modifiers.
- The application (using GTK, Qt, or other Wayland client implementations) passes the loaded keymap context, the keycode and modifiers to xkbcommon.
- xkbcommon applies keycodes/compat/geometry/symbols/types (KcCGST) configuration [2], to map the input to the final symbol.
In a nutshell, it's xkbcommon's job to translate Shift + L keystroke to Cyrillic Л symbol, when I have my Russian phonetic layout activated.
As Daniel Stone, the maintainer of xkbcommon nicely puts it:
It’s about two things: parsing and loading keymaps, and managing their ongoing state. State, in terms of keyboards, is the usual suspects — modifiers (e.g. Shift, Alt), multiple layouts (mostly for multiple languages), and LEDs. In general, you only want one person keeping a canonical copy of the state, and distributing it to its clients, as both the X server and Wayland do today. xkbcommon allows for this mode of operation, and is indeed how all current Wayland clients handle keyboard input [3].
Historical reference
X Keyboard Extension (XKB) protocol was developed in early 1990s and included in X Window System, Version 11 Release 6 (X11R6) in May 1994 [4]. XKB extends the core X protocol by offering support for
- Multiple keyboard layouts
- Sophisticated modifier handling
- LED control
- Keyboard geometry description,
- Various keyboard behaviors beyond what the core X protocol provides [5].
Rather than reinventing the wheel, Wayland protocol currently relies on XKB format for keymaps. Unlike X11, where clients received a symbolic representation of the key, in Wayland it's up to the clients to interpret keyboard events and map the pressed keys to symbols. xkbcommon library is typically used for this purpose.
Custom layout - the smart way
The xkbcommon documentation comes with a tutorial on adding a custom keyboard layout [6]. I don't want to repeat that here, and rather encourage you to dive into it and get the information from the original source.
However, I'll briefly describe my Russian Alternative Phonetic setup.
- Symbols file:I placed my custom layout variant in a new symbols file $HOME/.config/xkb/symbols/ru_alternative. This file contains translation of symbolic key codes into the desired key symbols (link).
I made the layout discoverable in GNOME by adding an entry to ~/.config/xkb/rules/evdev.xml (link).
That's it! A simple solution for a single-person machine, and no more half-baked solutions with broken layouts after system updates :)