Файл типа xkb_types.

В этом файле описывается - каким образом вычисляется "уровень" (shift level) в таблице символов (symbols) для каждой клавиши.

Напомню, что с каждой клавишей (скан-кодом) в XKB связан двумерный массив символов. "Координатами" в этом массиве являются "номер группы" (group) и "уровень" (shift level). То есть, когда нажата какая-то кнопка и XKB должен выбрать подходящий символ для данной клавиши, этот символ выбирается из массива в соответствии с текущими "номером группы" и "уровнем".

Обычно, разные "номера групп" используется для разных национальных языков (точнее - алфавитов), а разные "уровни" используются для больших/маленьких букв (в общем-то, все знают - что меняется при нажатии кнопки Shift). Хотя заметим, что XKB позволяет иметь до четырех групп и до 64 (!) "уровней" (в то же время, если не ошибаюсь, xkbcomp допускает номер "уровня" только до 8).

Так вот. Если изменение "номера группы" описывается в файле xkb_compat, то зависимость "уровня" от нажатия клавиш-модификаторов (Shift, Control, Alt и т.п.) описывается как-раз в файлах xkb_types.

Точнее, в этих файлах описываются "типы" клавиш. Каждый тип имеет название (в общем-то, произвольное), а в "описании типа" определяется - как вычислять "уровень" для клавиш этого типа.

Соответственно, в файлах xkb_symbols, где скан-кодам "приписываются" необходимые массивы возможных символов для каждой клавиши, указывается и тип этой кнопки. Правда, принадлежность каждой клавиши к конкретному типу, уже определена "по умолчанию" в модуле XKB (и соответственно, определены четыре типа "по умолчанию"). Поэтому, не ищите в файлах xkb_symbols явного указания типа, они используются только в том случае, когда хочется изменить "поведение" клавиши.

Итак. В файле xkb_types могут встретиться объявления

Объявление виртуальных модификаторов.

Это объявление просто перечисляет - какие виртуальные модификаторы далее могут использоватся в объявлениях типов.

Напомню, что в самом X-сервере (не в модуле XKB) определенны восемь модификаторов - Shift, Lock, Control, Mod1-Mod5, которые в терминах XKB называются "реальными" (real). В дополнение к ним XKB может иметь еще своих 16 модификаторов, которые, соответственно в нем именуются "виртуальными" (virtual). Обычно, в XKB вводятся виртуальные модификаторы NumLock, ScrollLock, Alt, AltGr и т.п.
Назначение модификаторов на конкретные клавиши делается в файле xkb_symbols.

Так вот. В описаниях типа могут фигурировать как реальные, так и виртуальные модификаторы. Поскольку, "реальные" определены "по умолчанию", никаких специальных объявлений для них не требуется. А вот названия "виртуальных" желательно объявить, прежде чем описывать типы.

Объявление виртуальных модификаторов имеет очень простой вид

'virtual_modifiers' список_модификаторов  ';'
где "список_модификаторов" - просто перечисление используемых модификаторов через запятую. Например, строчка
virtual_modifiers NumLock, Alt;
говорит о том, что в описаниях типов могут встречаться кроме реальных модификаторов (Shift, Lock и т.д.), также модификаторы NumLock и Alt.

Объявление типа.

Эти объявления выглядят как

'type' ИмяТипа '{' Инструкции '};'

"ИмяТипа" - это призвольная константа типа STRING (то есть строка символов в "двойных кавычках"). Это имя потом может использоваться в xkb_symbols для явного указания типа клавиши.

А "Инструкции" это несколько объявлений (они выглядят как "присваивание" переменной некоторого значения), кадое заканчивается "точкой с запятой".

В описании типа могут всречаться инструкции

modifiers

Просто перечисляет, какие модификаторы (реальные и виртуальные) влияют на выбор "уровня" в данном типе. Если модификаторов несколько, они перечисляются через знак '+'.
Например,

modifiers = NumLock;
или
modifiers = Shift+Lock;

map[...]

Как-раз описывает - какой "уровень" выбирается в зависимости от состояния (активности) модификатора. В квадратных скобках указывается модификатор или их комбинация (через знак '+'), а справа от "знака присваивания" - соответствующий "уровень" (Level1, Level2 ...). Кроме того, в качестве модификатора (внутри скобок) может встречаться специальное слово "None", что, как не трудно догадаться, означает отсутствие (точнее - неактивное состояние) модификаторов.
Например,

map[None] = Level1;
если модификатор (модификаторы) не активен, то используется "уровень" 1,
map[Shift] = Level2;
если активен модификатор Shift, то выбирается "уровень" 2,
map[Control+Alt] = Level3;
если активны сразу два модификатора - Control и Alt, то выбрать "уровень" 3.

Обратите внимание, что в последнем примере каждый из модификаторов Control и Alt, по-отдельности могут никак не влиять на изменения "уровня", (а только нажатые вместе). В этом случае в описании типа не будет строчек c map[Control] и map[Alt].
А вот map[None], как правило, присутствует в каждом типе.

level_name[...]

Эта инструкция присваивает призвольное символьное имя для каждого "уровня", допустимого для данного типа. Соответственно, в квадратных скобка указывается "уровень" (Level1, Level2 ...), а справа от "присваивания" константа типа STRING, которая и является названием этого уровня.
Например,

level_name[Level1] = "Base";
level_name[Level2] = "Shifted";
(вместо слова level_name можно использовать levelname).
Надо заметить, что для функционирования XKB это названия (и, соответственно, вся эта инструкция) не имеет никакого значения. Они могут использоваться прикладными программами, которые показывают состояние клавиатуры.

preserve[...]

Здесь требуются некоторые пояснения.
Напомню, что X-сервер передает прикладной программе сообщение о событии (нажатии/отпускании клавиши) в котором указывается скан-код клавиши и слово - "состояние" состоящее из набора модификаторов.

Для перевода этого сообщения в символ используются соответствующие подпрограммы Xlib.

Естественно, эти программы в используют в качестве аргументов и скан-код и "состояние". Причем, отдельные подпрограммы (их там несколько) могут для принятия решения использовать не все модификаторы из "состояния".

Для того, чтобы избежать нежелательных эффектов, когда несколько таких подпрограмм обрабатывают сообщение последовательно, каждая подпрограмма обычно "вычищает" "использованные" модификаторы из слова-"состояния".

Но, в то же время, бывают ситуации, когда это нежелательно и какой-нибудь модификатор должен "приниматься во внимание" несколькими подпрограммами.
(Что это за ситуации - я сам не знаю.)

Для таких случаев и используется инструкция preserve - "сохранить" (имеется ввиду - сохранять модификатор в "состоянии").

В этой инструкции в квадратных скобках указывется модификатор (или комбинация модификаторов), такой же, как в одной из инструкции map[...], а справа от "присваивания" - модификатор (или набор модификаторов), который нужно сохранять.

Обратите внимание, что в скобках обязательно должна быть комбинация (или модификатор), точно такая же как и в одной из инструкций map[...].
Дело в том, что инструкция preserve[...] не является самостоятельной инструкцией, а представляет собой "продолжение" соответствующей инструкции map[...]. Поэтому, по "комбинации в скобках" XKB "сшивает" эти две инструкции.
А вот в правой части может быть только часть этих модификаторов (или даже один). То есть, в обработке будут учитываться все модификаторы из левой части, а сохраняться только те, которые указаны в правой.

Надо сказать, что в правой части инструкции preserve может, также, стоять и "None", что означает, что "ничего сохранять не нужно".
Но, поскольку "по умолчанию" и так ничего не сохраняется, то такие инструкции особого смысла не имеют и их можно не писать.

Предопределенные типы.

В модуле XKB "по умолчанию" определены четыре типа и, соответственно, каждая клавиша "по умолчанию" приписана к одному из этих четырех типов.

Надо заметить, что, если клавиша отнесена к соответствующему типу, в ее описании (в xkb_symbols) массив значений должен иметь необходимое количество "уровней".

Как следствие этого, хотя вы можете переопределить любой из "предопределенных" типов (поменяв в нем модификаторы или названия уровней), но при этом нельзя менять в них количество уровней.
Если вам хочется иметь для каких-то клавиш большее количество уровней, придется сочинить для них новый тип (напомню, что назвать его можно как угодно).

Примеры описаний типов, можно посмотреть в соответствущих файлах в директории {XKBROOT}/types/, поэтому я здесь их приводить не буду.

А пример составления нового типа и его использования можно посмотреть в разделе "Примеры":"Новый тип для клавиши Enter".


Иван Паскаль pascal@tsu.ru