За XKB я брался неоднократно и на данный момент разобрался с ним настолько, что с одной стороны понимаю, что мало чего понимаю, а с другой ― могу, пожалуй, реализовать все идеи насчёт раскладок. Эта заметка будет, в частности, и мне для памяти. Хитрых вещей здесь нет, скорее проба пера.
Цель: гибкий подход к созданию и использованию раскладок. Требуется, чтобы затрагивался только профиль самого пользователя.
Гуглится много чего. В частности, мне было полезно внимательное чтение следующей статьи:
http://madduck.net/docs/extending-xkb/
Сначала общие факты об XKB.
XKB ― это «штука», которая занимается клавиатурой.
Основная единица ― keymap, который задаёт конкретное распределение функций между клавишами (я его так и буду звать ― кимап). Кимап содержит одну или несколько раскладок клавиатуры (что для нас наиболее интересно), способ переключения, а также всякую другую информацию вплоть до геометрии клавиатуры. В определении кимапов допускается большая свобода. Часто пользователю достаточно пользоваться одним-единственным кимапом (например, классический вариант с двумя раскладками), а для большей гибкости можно загружать разные кимапы.
Один кимап может содержать до четырёх раскладок, которые называются группами (group). Что касается переключения между ними, стандарт предусматривает круговое переключение в ту или другую сторону или включение первой или последней раскладки. Чтобы включать раскладку с заданным номером, надо импровизировать. С одной стороны, не очень удобно. С другой стороны, можно поставить вопрос о целесообразности использования одного кимапа с большим числом раскладок ― возможно, вместо этого стоит работать с разными кимапами.
В пределах одной раскладки различаются уровни (levels), каждый уровень задаёт свой набор символов для клавиш. Обычно уровней хотя бы два: один ― строчные буквы, второй ― прописные. У многих раскладок четыре уровня: для перехода на третий, скажем, может использоваться AltGr, а на четвёртый ― Shift+AltGr. Уровни ― гибкая вещь: их может быть много, клавиши переключения можно настраивать, к тому же есть разные режимы включения уровня: либо нажатие клавиши вместе с модификатором (как шифт), либо постоянное включение уровня (как капслок), либо модификатор включает уровень ровно на одно нажатие (аналог мёртвой клавиши). Например, уровнями можно симулировать нестандартные мёртвые клавиши.
Теперь постепенно к практической части.
Вся конфигурационная информация о клавиатуре хранится в текстовых файлах. Эти файлы раскиданы по стандартным поддиректориям директории /usr/share/X11/xkb. Соответственно, оттуда можно брать какие-то файлы и редактировать на свой вкус. Однако писать в системных директориях мы ничего не будем, все настройки на уровне пользователя.
Главные наши инструменты ― это xkbcomp и setxkbmap. xkbcomp - программа, которая компилирует и загружает раскладки. setxkbmap предоставляет более высокоуровневый интерфейс для установки раскладок, но, насколько понимаю, он фактически ограничен системными вещами. Поэтому мы будем использовать setxkbmap не для установки раскладок, а для их формирования, а сфомированные с его помощью раскладки будем скармливать xkbcomp-у.
Чтобы получить представление о том, что может съесть xkbcomp, можно выполнить команду
которая напечатает текущий кимап. Например, у меня получается
Код:
xkb_keymap {
xkb_keycodes { include "evdev+aliases(qwerty)" };
xkb_types { include "complete" };
xkb_compat { include "complete" };
xkb_symbols { include "pc+us+ru(typewriter):2+inet(evdev)+group(shift_caps_switch)+compose(menu)" };
xkb_geometry { include "pc(pc105)" };
};
Здесь интересно xkb_symbols: видно, что стоят английская и русская машинописная раскладка, что переключение между раскладками − стандартное CapsLock/Shift+CapsLock, что клавиша меню имеет значение Compose. Однако описание кимапа содержит и много неинтересной (нам сейчас) информации, которая, однако, обязательно должна присутствовать.
Если же мы изменяем кимап с помощью setxkbmap, мы можем отдельно задавать его параметры: например, выполнив команду (не выполняйте её если не знаете, что делать, оставшись без русской раскладки)
Код:
setxkbmap -layout us
получаем
Код:
$ setxkbmap -print
xkb_keymap {
xkb_keycodes { include "evdev+aliases(qwerty)" };
xkb_types { include "complete" };
xkb_compat { include "complete" };
xkb_symbols { include "pc+us+inet(evdev)+group(shift_caps_switch)+compose(menu)" };
xkb_geometry { include "pc(pc105)" };
};
То есть задав один параметр -layout, мы изменяем именно набор раскладок, а остальное не трогаем. Замечательное свойство setxkbmap состоит в том, что он может не устанавливать кимап, а только печатать его, для чего служит опция -print. Вот этот-то вывод setxkbmap-а мы будем скармливать xkbcomp-у, который сможет установить кимап, даже если исходники лежат в нашей домашней директории.
Значит, план действий такой.
1. Поиздеваться в домашней директории над какой-нибудь раскладкой.
2. Добиться, чтобы опция -layout у setxkbmap воспринимала бы нашу раскладку.
3. Добиться, чтобы наша раскладка компилировалась и загружалась.
1. Ну, поиздеваемся над русской. Например, добавить к машинописной раскладке третий уровень с ерундой типа «ёлочек». Третий уровень пусть включается правым альтом, а также для интереса задействуем | на роль «мёртвой клавиши», то есть переключателя типа latch.
В выводе setxkbmap мы видим такие вещи, как pc+us+ru(typewriter)+... Это соответствует загрузке секций определённых файлов: например, us означает загрузку секции по умолчанию из файла us, а ru(typewriter) - секции typewriter файла ru. Поскольку речь идёт о xkb_symbols, эти файлы лежат в поддиректории symbols той директории, в которой всё лежит. По умолчанию ― в /usr/share/X11/xkb. Например, можно полюбоваться на файл с вариантами русской раскладки:
Код:
less /usr/share/X11/xkb/symbols/ru
Видим, что по умолчанию используется секция winkeys, которая включает в себя секцию common. Прокрутив вниз (например, до секции Tatar) можно увидеть, как делаются небольшие расширения: импортируется большая раскладка и некоторые клавиши переопределяются. Конкретно в случае татарской видим строчку
Код:
include "level3(ralt_switch)"
включающую секцию ralt_switch из файла level3 ― это переключение на третий и четвёртый уровень с помощью правого Alt.
Мы в качестве корневой директории будем использовать ~/.xkb. Создадим поддиректорию symbols и поместим туда файл myru с содержанием
Код:
partial default alphanumeric_keys
xkb_symbols "typewriter" {
include "ru(typewriter)"
name[Group1]= "Russian (typewriter)";
key.type[group1]="FOUR_LEVEL";
key <TLDE> { [ ISO_Level3_Latch, plus, bar ] };
key <AE01> { [ numerosign, 1 ] };
key <AE02> { [ minus, 2, emdash ] };
key <AE08> { [ underscore, 8, asterisk ] };
key <AE09> { [ question, 9, guillemotleft, doublelowquotemark ] };
key <AE10> { [ percent, 0, guillemotright, leftdoublequotemark ] };
include "level3(ralt_switch)"
};
Зачем name[Group1] и key.type ― сам не знаю, по аналогии. Имена символов (в том числе ISO_Level3_Latch взяты из упоминавшегося файла /usr/include/X11/keysymdef.h.
2. Теперь насчёт setxkbmap. Как можно догадаться, эта программа в первую очередь преобразует свои аргументы в файлы и секции, которые надо загружать. Правила, по которым она делает эти преобразования, так и называются ― «правила» (rules), они лежат в директории rules. Конкретно нам нужен файл evdev. Скопируем его в ~/.xkb/rules и добавим строчки
Код:
! model layout = symbols
* myru = pc+myru
Значит, когда в опции -layout программы setxkbmap будет участвовать myru, в соответствии с новыми правилами это будет означать импорт файла myru.
Чтобы setxkbmap искал правила не только в системной директории, а в нашей
тоже, используем опцию -I:
Код:
setxkbmap "-I$HOME/.xkb" -layout "us,myru(typewriter)" -print
Пробела после -I нет, и тильда не раскрылась бы в домашнюю директорию, так что так. Это работает: генерируется описание раскладки.
Установить её setxkbmap, однако, не может.
3. Чтобы кимап скомпилировался и загрузился, скормим его описание xkbcomp-у. Получается:
Код:
setxkbmap "-I$HOME/.xkb" -layout "us,myru(typewriter)" -print | xkbcomp "-I$HOME/.xkb" - $DISPLAY
Опция -I позволяет xkbcomp-у найти наш файл символов.
Кстати, можно было бы скомпилировать файл раскладки в бинарный и загружать бинарный. На моём компе это даёт выигрыш во времени в два раза: с 0.050 секунд до 0.025 секунд. На десяти включениях можно сэкономить аж 0.250 секунд.
Остаётся повесить загрузку кимапов на клавиши с помощью xbindkeys или менеджера шорткатов DE и можно наслаждаться.
P.S. В этом сообщении я использовал длинное тире и ёлочки. Однако моя мегараскладка ни при чём: набирал в виме с использованием его внутренней раскладки.