Добавить в избранное | Сделать стартовой страницей

Большая Linux библиотека для пользователей OS Linux и ПО для нее
Есть что сказать? Нужен совет? Посети наш форум.


-


X Keyboard Extension.

Автор : Иван Паскаль

Настройка XKB.

При старте X-сервера, модуль XKB зачитывает все необходимые данные из текстовых файлов, которые образуют "базу данных" настроек XKB.

Строго говоря, большинство из этих файлов сам модуль XKB не читает. Он вызывает программу xkbcomp, которая переводит содержимое этих файлов в двоичный формат, понятный непосредственно модулю XKB.

Но для настройки это не так уж важно, поскольку вызов xkbcomp происходит автоматически, незаметно для пользователя.

База данных, необходимых XKB, состоит из 5 компонентов

keycodes
таблицы, которые просто задают символические имена для скан-кодов.
Например
= 49;
= 10;
types
описывает типы клавиш. Тип клавиши определяет - как должно меняться значение, выдаваемое клавишей в зависимости от модификаторов (Control, Shift и т.п.). Так, например, "буквенные" клавиши относятся к типу ALPHABETIC, что означает, что они имеют разное значение в зависимости от состояния Shift и CapsLock. А клавиша [Enter] имеет тип - ONE_LEVEL, что означает, что ее значение всегда одно и то же, независимо от состояния модификаторов.
compat (сокращенное от compability)
описывает "поведение" модификаторов. В XKB имеется несколько внутренних переменных, которые, в конечном счете, и определяют - какой символ будет генерироваться при нажатии клавиши в конкретной ситуации. Так вот, в compat как-раз описывается - как должны меняться эти переменные при нажатии различных клавиш-модификаторов. В этом же разделе обычно описывается и поведение "лампочек"-индикаторов на клавиатуре.
symbols
таблицы, в которых для каждого скан-кода (имени скан-кода, определенного в keycodes) перечисляются все значения (symbols), которые должна выдавать клавиша. Естественно, количество различных значений зависит от типа клавиши (котрые описываются в types), а какое именно значение будет выдано в конкретной ситуации, определяется состоянием модификаторов и их "поведением" (которое описывается в compat)
geometry
описывает "геометрию" клавиатуры - то есть расположение клавиш на клавиатуре. Эти описания нужны не столько самому X-серверу, сколько прикладным программам, которые рисуют изображение клавиатуры.

Все эти компоненты разложены по одноименным директориям в директории {XROOT}/lib/X11/xkb (в дальнейшем, я буду обозначать ее {XKBROOT}).

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

   тип_компонента "имя_блока" {........};

Поэтому, для того, чтобы выбрать конкретную настройку, ее обычно указывают в виде
имя_файла(имя_блока)
например,
us(pc104)

В тоже время, обычно один из блоков в файле (не обязательно самый первый) помечается флагом default, например

        xkb_symbols "pc101" {...};
default xkb_symbols "pc101euro" {...};
        xkb_symbols "pc102" {...};
        xkb_symbols "pc102euro" {...};

Это означает, что если указать только имя файла, то будет выбран именно этот блок.

Три способа задания полной конфигурации XKB.

Весь набор компонентов, необходимых для настройки XKB, описывается в файле конфигурации X-сервера в секции Keyboard.

Первый способ.

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

XkbKeycodes  "xfree86"
XkbTypes        "default"
XkbCompat       "default"
XkbSymbols      "us(pc104)"
XkbGeometry     "pc(pc104)"

Как легко догадаться, это означает, что

  • описание keycodes берется из файла "xfree86" в директории {XKBROOT}/keycodes, причем из файла будет выбран тот блок, который помечен в нем флагом default;
  • описание types берется из файла "default" в директории {XKBROOT}/types;
  • описание compat берется из файла "default" в директории {XKBROOT}/compat;
  • описание symbols берется из файла "us" в директории {XKBROOT}/symbols, блок "pc104";
  • описание geometry берется из файла "pc" в директории {XKBROOT}/geometry, блок "pc104";

Надо заметить, что в любом блоке (в любых компонентах) может встретиться инструкция

include "имя_файла(имя_блока)" (естественно, имя_блока может отсутствовать)

что, как нетрудно догадаться, означает, что в текущий блок должно быть вставлено другое описание из указанного файла (указанного блока).

Поэтому полное описание может неявно включать в себя данные из многих других файлов, кроме тех, которые вы явно укажете в файле конфигурации X-сервера.

Второй способ.

Второй способ заключается в том, что вы можете указать одной инструкцией сразу полный набор настроек. Такие наборы называются keymaps и, также как и обычные компоненты конфигурации XKB, располагаются в отдельных файлах (которые, тоже содержат в себе несколько именованных блоков) в директории {XKBROOT}/keymap.

Обычно, каждом блоке keymap просто указывается - из каких файлов XKB должен извлечь соответствующие компоненты (хотя, в принципе, там может быть и полное описание всех компонентов), например

xkb_keymap "ru"    {
    xkb_keycodes        { include "xfree86"           };
    xkb_types           { include "default"           };
    xkb_compatibility   { include "default"           };
    xkb_symbols         { include "en_US(pc105)+ru"   };
    xkb_geometry        { include "pc(pc102)"         };
};
Обратите внимание, что в одной инструкции include может быть указано несколько файлов (блоков) через знак "+". Понятно, что это означает, что должны быть вставлены последовательно все указанные файлы.

Таким образом, в файле конфигурации X-сервера можно вместо пяти компонентов указать сразу один их готовых наборов - keymap'ов, например

XkbKeymap    "xfree86(ru)"
Кроме того, эти два способа можно комбинировать. Например, если вы выбрали одну из подходящих keymap, но вас не устраивает один из компонентов, например geometry, то в файле конфигурации можно указать
XkbKeymap     "xfree86(ru)"
XkbGeometry     "pc(pc104)"

При этом, в соответствии с первой инструкцией, все компоненты будут взяты из keymap "xfree86(ru)", а вторая инструкция "перепишет" geometry, не затрагивая остальные компоненты (хотя я в этом не уверен :)

Третий способ.

И, наконец, третий способ. Он несколько отличается от предыдущих.

Набор настроек можно указывать не перечислением компонентов, а с помощью задания "правил" (Rules), "модели" (Model), "схемы" (Layout), "варианта" (Variant) и "опций" (Option). В этом наборе только Rules представляют собой некий файл, в котором находится таблица правил - "как выбрать все пять компонентов настроек XKB в зависимости от значений Model, Layout и т.д.".

Все остальные параметры представляют собой просто "ключевые слова" по которым в таблицах "правил" ищутся подходящие файлы настроек (keycodes, types, compat, symbols и geometry). Естественно, искать будет сам модуль XKB при старте.

Другими словами, Rules определяет некоторую функцию, аргументами которой являются Model, Layout, Variant и Options, а значение, которое возвращает эта функция представляет собой полный набор из компонентов настроек XKB - keycodes, types, compat, symbols и geometry (или полная keymap).

Если рассмотреть какой-нибудь файл rules (эти файлы тоже находятся в {XKBROOT} в поддиректории rules), то можно заметить, что в них есть строчки, начинающиеся со знака "!". Это "шаблоны", которые описывают - как интерпретировать следующие за ними строчки "правил".

Например, "шаблон"

! model = keycodes  geometry
говорит о том, что в следующих строках описываются правила - как по имени "модели" XKB должен выбрать файлы keycodes и geometry. Например,
pc104 = xfree86 pc(pc104)
надо понимать так, что если значение аргумента Model - слово "pc104", то keycodes надо взять из файла {XKBROOT}/keycodes/xfree86, а geometry - из файла {XKBROOT}/geometry/pc, блок с именем "pc104".
А, например, "шаблон"
! model    layout  =       symbols
говорит о том, что следующие за ним правила описывают - как по названию "модели" и "схемы" выбрать файл (и блок), с нужными symbols.

Рассматривая файл rules можно заметить, что в нем также есть строчки с wildcards - знаком "*". То есть, в качестве аргументов можно использовать не только те слова, которые встречаются в "правилах". Если программа не найдет указанные вами слова в левой части правила, то все равно подберет какие-нибудь названия для файлов - компонентов настройки.
Например, правило

! model        layout  =       symbols
....
   *      *     =       en_US(pc102)+%l%(v)
означает, что если указанные вами Model и Layout не были найдены в предыдущих правилах, то в качестве symbols надо взять блок pc102 из файла en_US, и добавить к нему блок, название которого задано параметром Variant из файла, название которого задано аргументом Layout. (Таким образом, в некоторых случаях, некоторые из параметров могут являться и названиями файлов или блоков. Но в общем случае это все-таки просто "ключевые слова").

Можно также заметить, что...
Во-первых, не все параметры обязательно задавать для выбора всех компонентов. Обычно достаточно указать Model и Layout (ну и, естественно, Rules), а Variant и Options нужны только в некоторых случаях.
А во-вторых, что

  • Model обычно определяет тип "железа" - клавиатуры;
  • Layout - язык или, точнее, алфавит, который "навешивается" на кнопки клавиатуры;
  • Variant - ну "вариант" он и есть вариант - различные варианты размещения знаков алфавита (заданных Layout'ом);
  • Options - обычно меняет "поведение" или "расположение" модификаторов - Control и Group (переключатель групп - это переключатель "языка", например - русский/латинский).

Кстати, заметьте также, что хотя Options как правило состоят из двух слов, разделенных двоеточием, это не означает, что вы можете самостоятельно комбинировать левую и правую часть (двоеточие в данном случае просто делает их более понятными). Так, например, в rules есть правила для значений Options "grp:toggle" и "ctrl:ctrl_aa". Но если вы попробуете "сконструировать" что-то типа "ctrl:toggle", ничего хорошего из этого не получится, поскольку такого слова в правилах нет.

Итак, если вы используете третий способ указания конфигурации XKB, то в файле конфигурации X-сервера, надо задать параметры XkbRules, XkbModel, XkbLayout и, если вам нужно что-то не совсем стандартное - XkbVariant и XkbOptions.
Например,

XkbRules   "xfree86"
XkbModel        "pc104"
XkbLayout       "ru"
XkbVariant      ""
XkbOptions      "ctrl:ctrl_ac"
означает, что XKB должен
  • в соответствии с правилами, описанными в файле {XKBROOT}/rules/xfree86, выбрать настройки для
  • клавиатуры типа "pc104" (104 кнопки),
  • русского алфавита (английский алфавит будет включен "по умолчанию"),
  • вариант - "стандартный" (то есть, этот параметр можно было не писать)
  • и, наконец, дополнительные опции для вашей "раскладки клавиатуры" - "ctrl:ctrl_aa".

Кстати, что означают различные опции, а также - какие "модели" и "схемы" определены в "правилах" (и что они означают) можно посмотреть в файле xfree86.lst (или другом файле *.lst, если вы выбрали "правила" не xfree86), который находится в той же директории, что и файл "правил", то есть - {XKBROOT}/rules.

Несколько практических рекомендаций.

Небольшое отступление - "о клавише - переключателе рус/лат".
Когда был написан первый вариант этих рекомендаций, сама раскладка "русской" клавиатуры (symbols/ru) включала в себя и "переключатель групп" - рус/лат, "подвешенный" на клавишу CapsLock. С одной стороны это было удобно - в простейшем случае достаточно было выбрать "русскую раскладку" и вы автоматически получали и клавишу для переключения "на русский". Но, с другой стороны, это было неудобно для тех, кто предпочитает в качестве переключателя рус/лат другую клавишу (или комбинацию клавиш). Конечно, выбрать другой переключатель не составляло труда, но при этом оставался и переключатель на CapsLock, что многим не нравилось. Для того, чтобы убрать его, надо было "залезть" в соответствующий файл и вручную подправлять соответствующую раскладку.

В конце концов (начиная с версии 3.3.4) сами разработчики XFree убрали этот "переключатель" из "русской раскладки". Но, в связи с этим появились и некторые проблемы - теперь клавишу-переключатель надо явно "заказывать" при конфигурировании XKB. Что я и попытся отразить в своих рекомендациях.
Итак...

Самый простой способ - использовать программу для автоматической настройки "иксов".

В XFree86 такая программа называется XF86Setup. Она использует третий метод задания конфигурации XKB. При этом "по умолчанию" используются "правила" (XkbRules) - xfree86. Вам нужно будет только выбрать "модель" (XkbModel), "схему" (XkbLayout) и "способ переключения групп" (переключатель "РУС/ЛАТ").

Кроме того, при желании вы можете изменить "положение клавиши Ctrl". Естественно, в конфигурации это будет выглядеть как соответствующие строчки XkbOptions.

Итак. Запустите программу XF86Setup, выберите раздел Keyboard. В этом разделе выберите из меню Model (тип клавиатуры) и Layout (язык). Не забудьте отметить в отдельных списках (в правой части) подходящий "переключатель групп" и, если хотите - "расположение Ctrl".

При выходе из программы она запишет соответствующие строчки в файл конфигурации XFree в секции Keyboard.

Но, если вы захотите вписать эти строчки самостоятельно, могу дать еще несколько советов.

Прежде всего, надо сказать, что "ключевыми словами" в этих настройках будут

  • xfree86 - название "архитектуры" X-Window;
  • pc101 (pc104, pc105 и т.п.) - тип клавиатуры (количество кнопок);
  • ru - название "раскладки клавиатуры" с русским алфавитом.
(Если у вас другая "архитектура"/клавиатура/алфавит, то подберите названия самостоятельно.)

Итак...

Начнем со второго способа - полная keymap.

В файлах конфигурации есть набор "полных keymap'ов" для архитектуры xfree86, отличающихся "языком". Все они лежат в файле xfree86, а название блока внутри файла отражает название "языка" (точнее - алфавита) - xfree86(us), xfree86(fr), xfree86(ru) и т.д. Полный список keymap'ов можно посмотреть в файле {XKBROOT}/keymap.dir.

Для "руссифицированной" клавиатуры вполне подойдет

XkbKeymap        "xfree86(ru)"

К сожалению, после "выкидывания" CapsLock как переключателя рус/лат из русской раскладки (см. замечание в начале этого раздела) получилось так, что "полная keymap" для русского языка осталась вообще без какого-либо переключателя "по умолчанию". Но вы можете добавить его "вручную". Для этого придется найти в файле {XKBROOT}/keymap/xfree86 блок "ru". И дописать в строчку xkb_symbols ссылку на описание соответствующего переключателя групп. Для CapsLock это будет - group(caps_toggle). То есть, строчка будет выглядеть как

xkb_symbols    { include "en_US(pc105)+ru+group(caps_toggle)"};

Если вы выбираете третий способ - через "правила", "модель", "схему" и т.д.

Как я уже говорил,

  • название "правил" (rules) соответствет "архитектуре" (xfree86);
  • "модель" (model) соответствует типу клавиатуры (pc101, pc102 и т.п.);
  • "схема" (layout) отражает "язык" (ru).
Поэтому, подходящая конфигурация будет выглядеть примерно так -
XkbRules    "xfree86"
XkbModel        "pc104"
XkbLayout       "ru"
С помощью XkbOptions можно подобрать "поведение" управляющих клавиш. Возможные значения XkbOptions и их смысл можно подсмотреть в файле {XKBROOT}/rules/xfree86.lst.

Не забудьте, что в последних версиях надо явно выбрать переключатель групп. Для CapsLock это будет -

XkbOptions    "grp:caps_toggle"

И, наконец, первый способ - описание отдельных компонентов настройки (keycodes, compat, types, symbols, geometry).

Если вы не знаете с чего начать, подсмотрите соответствующий набор в keymap. Или попробуйте "вычислить" его "вручную" через rules/model/layout. (Подробнее об этом можно прочитать в "Примеры: Где будем экспериментировать?")

Могу посоветовать

  • - для keycodes выбрать файл xfree86;
  • - для types и compat подойдут файлы default ("по умолчанию") или complete ("полная");
  • - geometry, скорее всего, "pc", а количество кнопок задается названием блока в файле pc - pc(pc101), pc(pc102), pc(pc104). (Полный список "геометрий" в файле {XKBROOT}/geometry.dir.)

А вот на symbols обратите особое внимание. Файл symbols/ru описывает только "буквенные" клавиши. Если вы укажете только его, то у вас не будут работать все остальные кнопки (включая Enter, Shift/Ctrl/Alt, F1-F12 и т.д.).

Поэтому symbols должен состоять по крайней мере из двух файлов - en_US(pc101) (в скобках - тип клавиатуры) и, собственно, ru.
Полный список symbols в файле {XKBROOT}/symbols.dir.

Сюда же надо добавить и описание подходящего "переключателя рус/лат"
Описание всех возможных переключателей групп находится в файле {XKBROOT}/symbols/group.

Итак. Для первого метода список может выглядеть так -

XkbKeycodes "xfree86"
XkbTypes        "complete"
XkbCompat       "complete"
XkbSymbols      "en_US(pc101)+ru+group(caps_toggle)"
XkbGeometry     "pc(pc101)"
Если вам хочется дополнительные изменения "поведения" управляющих клавиш (то, что в третьем методе задается XkbOptions), то подсмотрите подходящую "добавку" в {XKBROOT}/rules/xfree86.lst и "приплюсуйте" ее в строчку XkbSymbols. Например,
XkbSymbols  "en_US(pc101)+ru+group(shift_toggle)+ctrl(ctrl_ac)"

Еще один способ описания конфигурации XKB.


Кроме опций в общем файле конфигурации X-сервера (XF86Config) XKB может иметь свой отдельный файл конфигурации. Правда он в XFree86 не применяется и (увы) не описан. В то же время, с помощью этого файла можно
  • задать конфигурацию XKB для каждого дисплея по отдельности (если на машине запущено несколько X серверов на разных дисплеях)
  • настроить намного больше внутренних параметров XKB, чем это позволяет XF86Config.

Собственный файл конфигурации XKB (назовем его так) должен находится в директории {XRoot}/lib/X11/xkb и называться X<цифра>-config.keyboard
где <цифра> - номер дисплея (обычно - X0-config.keyboard)

Формат этого файла.


Прежде всего надо заметить, что все инструкции в этом файле выглядят как операторы присваивания языка C.
параметр_XKB = выражение ;
Если оператор один в строке, то знак ';' в конце не обязателен. В любом месте строки могут находится комментарии, которые должны начинаться с '#' или '//'.
"Выражение" представляет собой
  • числовое значение (например - величина задержки или номер группы);
  • логическое значение - on или off;
  • строка в кавычках - "" (например - имя файла/блока содержащего описание компонентов конфигурации XKB)
  • название модификатора, "управляющего флага" и т.п.
Если в выражении требуется указать несколько модификаторов (флагов) одновременно, они перечисляются через '+'. 
Кроме того, в файле могут встретиться некоторые разновидности "присваивания". Если инструкция определяет, например, начальные значения для "набора управляющих флагов", в котором некоторые флаги и так уже установлены по умолчанию, то возможны следующие операции
  • убрать из набора флаги, указанные в инструкции
    набор_флагов -= флаг1 + флаг2 + ...
  • добавить в набор указанные флаги
    набор_флагов += флаг1 + флаг2 + ...
  • и наконец, полностью заменить набор флагов на тот, что вы укажете
    набор_флагов = флаг1 + флаг2 + ...
Итак. В этом файле можно задать следующие параметры 

Компоненты конфигурации.


                  
rules = "..."
model = "..."
layout = "..."
variant = "..."
options = "..."

keymap = "..."

keycodes = "..."
geometry = "..."
types = "..."
compat = "..."
symbols = "..."  (или symbolstouse = "...")

Описывают те же параметры, что и в главном конфигурационном файле X сервера (XF86Config).
Напомню, что собственный файл конфигурации XKB может быть составлен для каждого дисплея по отдельности. Поэтому, если компоненты конфигурации уже описаны в XF86Config, то здесь имеет смысл указывать только те компоненты (или rules/model/layout/etc.), которые для данного дисплея отличаются от общих. Естественно, все эти параметры, указанные в "дополнительном файле конфигурации" имеют больший приоритет и переписывают соответствующие значения из файла конфигурации X сервера.

Начальное значения для набора модификаторов.


                  
modifiers [ = | -= | += ] модификатор1 + модификатор2 + ...
"Модификатор" - название одного из "реальных" модификаторов - shift, lock, control (или ctrl), mod1, mod2, mod3, mod4, mod5. 
Как я уже говорил, здесь вместо присваивания могут использоваться операции '-=' - убрать модификатор(ы), '+=' - добавить модификатор(ы), '=' - заменить набор модификаторов на указанные в этой инструкции.
(Надо заметить, что по умолчанию при старте X сервера этот набор модификаторов пустой. Поэтому, имеют смысл только операции '+=' и '='. Причем разницы между ними нет.)

Начальное значение для набора "управляющих флагов".


                  
controls  [ = | -= | += ] флаг1 + флаг2 + ...
Как и в предыдущей инструкции, операция может быть убрать/добавить/заменить ('-='/'+='/'='). 

"Флаги" могут быть


                  
repeat (или repeatkeys)
разрешить автоповтор клавиш
(по умолчанию он и так разрешен, поэтому имеет смысл только его убрать
controls -= repeat);
mousekeys
включить эмуляцию мыши;
mousekeysaccel
включить режим "ускорения" для эмуляции движения курсора мыши
overlay1
overlay2
включить соответствующие "перекрытия".
ignoregrouplock
игнорировать "текущую группу" в режиме GrabKey
audiblebell
включить (выключить) звуковой сигнал.
(Напомню, что XKB может вместо звукового сигнала посылать bell-event'ы для проигрывания звуков или мелодий "звуковой приставкой". Если такая "приставка" у вас есть, то обычную "пищалку" можно и выключить.
accessxkeys
slowkeys
bouncekeys
stickykeys
accessxtimeout
accessxfeedback
включение различных режимов AccessX (для людей с "ограниченными физическими возможностями")

                  

Список модификаторов, которые игнорируются в режиме GrabKey


                  
ignorelockmods [ -= | += | = ] модификатор1 + модификатор2 + ...
(или ignorelockmodifiers ...)

                  

Список "внутренних" модификаторов


                  
internalmods [ -= | += | = ] модификатор1 + модификатор2 + ...
(или internalmodifiers ...)

Это модификаторы, которые используются только внутри X сервера (для выбора "действия" клавиши, если таковое есть) и не сообщаются в клавиатурных event'ах, посылаемых приложениям.

"Метод выравнивания" групп.


                  
groups = [ wrap | clamp | число ] 
(или outofrangegroups ...)

Задает "метод выравнивания групп". Напомню, что метод может быть wrap, clamp или redirect. В последнем случае нужен дополнительный параметр - куда "редирект", если номер группы выходит за границы диапазона.
Так вот, метод redirect задается в виде
groups = номер_группы

                  

Параметры "пищалки".


                  
bell = число  (или bellvolume = число )
bellpitch = число
bellduration = число
click = число (или clickvolume = число )

Все эти инструкции устанавливают параметры "пищалки" (bell) и "клика" клавиатуры (обычно это более короткий сигнал, чем bell).
Инструкции bell и click могут также иметь вид
bell = [ on | off ]
click = [ on | off ]
что (как нетрудно догадаться) просто означают включить/выключить эти сигналы. Если сигнал просто включен и не указано его "volume", то оно считается - 100. 

Различные задержки (таймауты).


                  
repeatdelay = число
задержка (в миллисекундах) между нажатием клавиши и началом автоповтора;
repeatinterval = число
интервал (в миллисекундах) между автоповторами;
slowkeysdelay = число
в режиме slowkeys клавиша считается нажатой, если она удерживается некоторый промежуток времени, чтобы избежать срабатывания при случайном "задевании" клавиши. Этот параметр и определяет указанную задержку.
debouncedelay = число
в режиме bouncekeys клавиша после нажатия/отпускания некоторое время не реагирует на повторные нажатия/отпускания, чтобы избежать ложных срабатываний при неаккуратном нажатии клавиши. Этот параметр и определяет указанную задержку.
accessxtimeout = число (или axtimeout = число)
промежуток времени (в секундах) после которого режим AccessX автоматически отключается. Имеет смысл только если установлен соответствующий флаг
(controls += ... accessxtimeout ...);

                  

Параметры "ускорения" курсора мыши.


                  
mousekeysdelay = число
задержка (в миллисекундах) до начала автоповтора клавиши эмулирующей движение "мышиного" курсора (то же самое, что и repeatdelay для обычных клавиш);
mousekeysinterval = число
интервал автоповтора (то же, что и repeatinterval);
mousekeysmaxspeed = число
максимальная скорость движения курсора в пикселах за один event (точнее - если в соответствующем "действии" эмуляции движения курсора - MovePtr уже задан параметр "смещение за один event" больше единицы, то максимальная скорость будет "смещение"*maxspeed);
mousekeystimetomax = число
через сколько повторов курсор достигает максимальной скорости
mousekeyscurve = число (в диапазоне -1000:1000)
"степень кривизны" кривой ускорения (в "режиме ускорения" скорость курсора нарастает от начального "смещения" до максимального не линейно, а пропорционально X^(1 + curve/1000).
Если mousekeyscurve = 0, то зависимость линейная)

                  

Включение/выключение отдельных событий дополнительной звуковой индикации в AccessX


                  
accessxtimeoutctrlson [ -= | += | = ] событие1 + событие2 + ...
(или axtctrlson ...)
accessxtimeoutctrlsoff [ -= | += | = ]  событие1 + событие2 + ...
(или axtctrlsoff ...)

где "событие" - slowkeyspress, slowkeysaccept, feature, slowwarn, indicator, stickykeys, slowkeysrelease, slowkeysreject, bouncekeysreject, dumbbell.
Подробнее об этих событиях можно прочитать в документации (XKBlib), поставляемой в "исходниках" XFree86.

Немного о "внутренностях" XKB.


                  

Основные термины - коды и символы.


Основное назначение модуля XKB — преобразовывать скан-коды нажимаемых клавиш в коды символов.
Обычно в документации XKB скан-коды называются keycodes, а коды символов - просто "символы" (symbols).
Естественно, "символы" - это не обязательно коды "печатных" символов (букв, цифр, знаков препинания и т. п.). Это могут быть также "управляющие" коды (Esc, Enter, Backspace и т. п.) или коды, которые никак не отображаются, но влияют на внутренне состояние самого XKB (переключение РУС/ЛАТ, Control, Shift, Alt и т.п.) и, следовательно, на то, какой символ будет выбран при нажатии обычных "буквенных" клавиш.

Две части XKB и "проблема совместимости".


Прежде всего следует сказать несколько слов о том, как происходит преобразование скан-кодов в символы при работе X Window System без модуля XKB.
Сам X-сервер переводом скан-кода в код символа не занимается. При нажатии или отпускании кнопки клавиатурный модуль X-сервера посылает сообщение о событии (event) прикладной программе.
В этом сообщении указывается только скан-код нажатой кнопки и "состояние клавиатуры" - набор битовых флагов, который отражает состояние клавиш-модификаторов (Shift, Control, Alt, CapsLock и т. п.).
Клиентская программа должна сама решить, какой символ соответствует скан-коду при таком сочетании битов-модификаторов.
Естественно, для этого программа может воспользоваться таблицей, хранящейся в X-сервере, в которой для каждого скан-кода перечислены возможные символы. Обычно програма при старте запрашивает эту таблицу у сервера. (Таблицу на сервере можно менять с помощью утилиты xmodmap).
Разумеется, при создании программ никто не пишет каждый раз процедуру для интерпретации скан-кодов. Для этих целей существуют специальные подпрограммы в библиотеке Xlib.
Конечно, Xlib используется не только для этого. Это библиотека низкоуровневых процедур для работы с X-сервером. Даже если программа пользуется высокоуровневыми библиотеками-"тулкитами" (Xaw, Motif, Qt, gtk и т. п.), библиотека Xlib служит "базовой" для этих тулкитов.
Итак, процедуры из Xlib, зная скан-код и состояние клавиатуры, в соответствии с таблицей символов, полученной от сервера при старте, выбирают подходящий символ.
Модуль XKB точно так же сообщает программе только скан-код и свое "состояние". В отличие от "старого" модуля (обычно говорят - "core protocol", будем его называть для краткости - "core-модуль"), XKB имеет более сложную таблицу символов, другой набор модификаторов и некоторые дополнительные параметры "состояния клавиатуры" (обо всех этих отличиях мы поговорим по ходу рассмотрения "внутренностей" XKB).
Для полноценной работы с XKB библиотека Xlib должна содержать процедуры преобразования скан-кодов, "знакомые с Xkb".
Естественно, "иксы", у которых X-сервер "укомплектован" модулем XKB, имеют и соответствующую библиотеку Xlib.
Таким образом, XKB фактически делится на две части - модуль, встроенный в X-сервер, и набор подпрограмм, входящих в библиотеку Xlib.
Однако же, никто не запрещает использовать программы, которые были собраны со старой библиотекой Xlib, "не подозревающей" о существовании XKB: при этом и возникает "проблема совместимости". Модуль XKB должен уметь общаться как со "своей" Xlib, так и со старой, работающей в соответствии с core protocol.
Естественно, "общение" не ограничивается только передачей сообщений о нажатии/отпускании клавиш. Процедуры Xlib могут обращаться к X-серверу с различными запросами (например, взять таблицу символов) и командами (например, поменять в этой таблице расположение символов).
На все эти запросы и команды модуль XKB должен реагировать так, чтобы даже "старая" Xlib могла работать правильно (насколько это возможно).

Таблица символов


Что же собой представляет таблица символов, связывающая символы со скан-кодами и состоянием модификаторов? Рассмотрим сначала "традиционную" таблицу символов, которая используется в core protocol.
Как и во многих других клавиатурных модулях, ее можно представить как обычную двумерную таблицу, где каждая строка соответствует скан-коду, а столбцы - модификаторам или комбинации модификаторов.
Прежде всего надо заметить, что в "сообщении о нажатии/отпускании клавиши" под биты-модификаторы отводится один байт (октет) и соответственно, существует восемь битов-модификаторов. Первые три называются - Shift, Lock, Control, остальные "безымянные" - Mod1, Mod2, Mod3, Mod4, Mod5.
Замечу, что хотя названия первых трех модификаторов явно намекают на то, каким клавишам они должны соответствовать, на самом деле они могут быть "привязаны" (то есть, менять свое значение при нажатии/отпускании клавиши) к любым другим кнопкам.
В данном случае нам важно, что восемь модификаторов могут составить 256 различных комбинаций. Поэтому теоретически таблица символов может содержать до 256 столбцов. В то же время, в core protocol'е строго определены только первые четыре колонки, в смысле - каким комбинациям модификаторов они соответствуют. Легко догадаться, что в этих комбинациях используются только два модификатора - Shift и Mode_switch.
(Вы можете заметить, что среди модификаторов нет бита с именем Mode_switch. Совершенно верно. Его роль выполняет один из "безымянных", модификаторов - Mod1-Mod5. А Mode_switch - это название одного из служебных символов. Когда приложение запрашивает у сервера таблицу символов, оно также выясняет, какой из безымянных модификаторов связан с этим символом, и в дальнейшем по состоянию этого модификатора догадывается о том, нажал ли пользователь клавишу, соответствующую символу Mode_switch.)
Итак. Первые четыре колонки в таблице соответствуют "состояниям" -
"никаких модификаторов" Shift Mode_switch Mode_switch+Shift


В терминах core protocol можно сказать, что состояние Mode_switch выбирает одну из двух групп (не надо путать их с XKB группами, о которых мы поговорим позднее), а состояние Shift - одну из двух колонок внутри группы.
Как вы скорее всего знаете, разные группы обычно используются для разных языков (алфавитов), а Shift выбирает строчные или прописные буквы в пределах одного алфавита.

  Group 1 Group 2
  Shift Mode_switch Mode_switch+Shift
...
keycode 38 a A Cyrillic_ef Cyrillic_EF
keycode 39 s S Cyrillic_yeru Cyrillic_YERU
keycode 40 d D Cyrillic_ve Cyrillic_VE
...

Заметьте также, что ни Lock, ни Control в выборе символа из таблицы не участвуют. Если эти модификаторы активны, то отдельные подпрограммки Xlib после выбора символа из таблицы делают соответствующие преобразования этих символов.

Вернемся к XKB. Как видите, недостаток "традиционной" таблицы - ее "негибкость". Хотя колонок может быть до 256, "стандартно" обрабатываются только первые четыре, причем их зависимость от состояния модификаторов жестко "зашита" в алгоритмах Xlib.

Поэтому одно из основных усовершенствований, которые были внесены при разработке XKB - большая гибкость в построении таблицы.

  • Во-первых, в XKB колонки не связаны жестко с конкретными модификаторами. В одном из файлов конфигурации XKB описывается зависимость номера колонки от произвольного набора модификаторов. Естественно, эти зависимости можно изменять и добавлять простым редактированием соответствующего файла. (Подробнее о них смотри ниже: Вычисление "уровня" (shift level). Типы клавиш.)
  • Во-вторых, в одной и той же "раскладке клавиатуры" разные клавиши могут соответствовать разному количеству символов в зависимости от модификаторов. Например,
    • клавиша Enter вообще не зависит от модификаторов, то есть в соответствующей строке имеет смысл только одна колонка;
    • клавиша с символами '1' и '!' содержит две колонки, выбор конкретной зависит только от Shift,
    • а клавиша с символами '-','_'и '=' может иметь три колонки, выбор которых зависит от двух модификаторов - Shift и Mod1
  • При таком подходе понятие "группа" сильно меняет свой смысл. Мы уже не можем определять группу как "пачку" колонок, поскольку для разных клавиш размер этой "пачки" будет разным.
    Вообще-то, при той гибкости в связывании колонок с модификаторами, которую дает XKB, можно было бы вообще забыть о группах или просто говорить, что группа —это группа колонок, объединенных модификатором (тем же Mode_switch). Но...

Делить таблицу на группы удобнее. Во-первых, так легче провести границу между разными алфавитами (если, конечно, таковые используются в раскладке). Заметьте, что в некоторых случаях хотелось бы иметь не два разных алфавита, а больше. Причем раскладки для разных алфавитов могли бы составлять разные люди, независимо друг от друга
Во-вторых, чем больше модификаторов участвуют в выборе колонок, тем сложнее и запутаннее становятся соответствующие описания зависимостей.

Поэтому, авторы XKB использовали радикальный подход - в одной и той же раскладке может быть несколько (до четырех) отдельных таблиц. Вот эти таблицы и называются группами XKB (или просто groups).

Вообще-то, правильнее сказать не "несколько двумерных таблиц в одной раскладке", а - у каждого скан-кода (keycode) может быть до четырех "однострочных" таблиц - групп.
Потому, что ...

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

Итак.

  • Для каждого скан-кода (keycode) в XKB "раскладке" хранится несколько однострочных таблиц символов, которые называются "группами".
  • Каждая такая таблица может делиться на несколько колонок - "уровней" (shift level)
  • Какая из таблиц-строчек актуальна в данный момент, определяется текущим номером группы (или просто - group). Текущий номер группы хранится в X-сервере и сообщается приложению в событии о нажатии/отпускании клавиши вместе со скан-кодом и набором модификаторов.
  • Выбор нужной колонки (shift level) определяется состоянием модификаторов.
  • Разные keycode могут иметь разное количество групп.
  • В разных группах даже одного и того же keycode может быть разное количество shift level.

keycode номер группы количество level'ов  
36 1 одна колонка Enter  
38 1 две колонки a A  
2 две колонки Cyrillic_ef Cyrillic_EF  
3 две колонки Greek_alpha Greek_ALPHA  
21 1 две колонки + =  
2 четыре колонки + = \ ;
...

Наконец, надо сказать, что групп может быть от одной до четырех, а уровней - до 64.

Таблица действий.

Кроме "таблицы символов" к скан-коду может быть "привязана" аналогичная "таблица действий" (actions). Эта таблица также делится на подтаблицы (группы) и колонки (уровни).

В отличие от таблицы символов, которая используется приложением (X-сервер ее только хранит, чтобы сообщить каждому вновь стартующему приложению), таблица действий используется самим сервером.

В ее ячейках располагаются вызовы внутренних процедур XKB, которые меняют его состояние - текущую группу, состояние модификаторов и внутренних флагов XKB.

Точнее - действия, выполняемые actions, не ограничиваются измениями состояния XKB. Они также используются для

  • эмуляции событий мыши (перемещения указателя и нажатия mouse buttons)
  • генерации специальных events для приложений
  • переключения экранов
  • выключения X-сервера
  • и т.п.

Немного подробнее о всех возможных actions написано в разделе Описание действий.

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

Заметим, что в core-модуле понятия "действие" вообще нет.

Состояние XKB: номер группы.

Текуший номер группы хранится в "таблице состояния" XKB.
Точнее, внутри XKB имеются три ячейки

  • locked group - некий аналог нажатия клавиши CapsLock, но для групп
  • latched group - аналог действия клавиши Shift, но, опять же, для групп
  • base group - базовое смещение номера группы

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

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

Метод выравнивания номера группы.

Естественно, при таком суммировании может получиться число, большее чем количество заданных групп. Чтобы получить из него какой-нибудь допустимый номер группы, XKB может использовать три разных метода:

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

Модификаторы.

Кроме переменных, содержащих номера групп, "состояние XKB" определяется "флажками" - модификаторами. Эти битовые флаги меняются при нажатии клавиш Shift, CapsLock, Alt, Control и т. п. и, естественно, влияют на выбор подходящего символа из таблиц.

Как я уже упоминал, "core protocol" (протокол "общения" между "традиционным" клавиатурным модулем и Xlib) тоже имеет "набор модификаторов" (который и сообщается прикладной программе при нажатии кнопок). Эти модификаторы (8 бит) называются Shift, Lock, Control, Mod1-Mod5. В зависимости от их состояния Xlib выбирает подходящий символ и может выполнять дополнительные действия — делать из обычных символов управляющие, менять прописные/строчные буквы и т. п.
Кроме того, программа может сама (помимо Xlib) по-своему интерпретировать эти модификаторы и менять свое поведение.

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

Итак. Модификаторы core protocol'а в XKB называются "реальными" (real) модификаторами и их названия такие же, как в core protocol.

Кроме того, XKB имеет еще 16 своих внутренних модификаторов, которые называются "виртуальными" (virtual) модификаторами.

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

Итак. Эти модификаторы выполняют несколько функций

  • по их состоянию "вычисляется" shift level для выбора нужного символа и/или "действия";
  • по их состоянию "вычисляется" состояние индикаторов (см. ниже);
  • и, кроме того, они могут влиять на выполнение некоторых других действий XKB (вычисление номера группы и т.п.).

Состояние XKB: модификаторы.

Так же как и номер группы, набор битов-модификаторов внутри XKB существует в трех экземплярах (в трех переменных)

  • locked modifiers
  • latched modifiers
  • base modifiers

Содержимое этих переменных (так же как и "групповых") может меняться с помощью действий (actions).

Как и для номеров групп, для модификаторов существует "фактический" набор модификаторов, который определяется как логическая сумма (побитная операция ИЛИ) трех указанных переменных. Соответственно, никаких дополнительных "выравниваний", как для значения номера группы, не требуется.

Вычисление "уровня" (shift level). Типы клавиш.

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

Для того чтобы обеспечить такую гибкость, в XKB существут понятие "тип клавиши".

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

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

Надо отметить, что хотя описания типов и принадлежность каждой клавиши к определенному типу можно гибко менять, в XKB по умолчанию задан основной набор типов и для всех клавиш расписаны идентификаторы типов. Поэтому обычно нет необходимости задавать эти параметры в файлах конфигурации XKB.

Какая еще информация хранится для каждого скан-кода.

Кроме таблицы символов (и, возможно, "действий") с каждым скан-кодом связаны еще несколько переменных

  • метод "выравнивания" номера группы, специфичный для данной клавиши;
  • "поведение" клавиши;
  • набор "исключений";
  • реальный модификатор (modmap) и виртуальный модификатор (vmodmap), связанные с этой клавишей.

Метод "выравнивания" номера группы.

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

В этом случае эффективный номер группы может дополнительно "выравниваться", специально для данной клавиши.

Возможные методы точно такие же, как и "глобальные". По умолчанию используется метод Wrap.

"Поведение" клавиши.

Эта переменная состоит из двух частей - набора флагов и дополнительного аргумента. Обычно аргумент не нужен. Но некоторые флаги подразумевают дполнительный числовой аргумент, а смысл этого аргумента зависит от флага.

Флаги определяют

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

Набор "исключений".

Это битовая маска, которая указывает - какая информация, связанная с клавишей, "задана точно" (explicit) и не должна изменяться в некоторых случаях. Дело в том, что в core protocol определены команды, с помощью которых программы могут менять "раскладку клавиатуры" внутри клавиатурного модуля X-сервера. Естественно, эти комады меняют только "привязку" символов, поскольку другие "свойства" скан-кодов в core protocol'е не определены.

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

Так вот. Набор "исключений" может защитить информацию, связанную с конкретным скан-кодом, именно от таких косвенных изменений.
Если прикладная программа будет пользоваться соответствующим запросами XKB модуля (а не core protocol), такой защиты не требуется.

Итак, с помощью этой маски можно запретить

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

Реальный и виртуальный модификаторы.

Обратите внимание, что с каждым скан-кодом связаны две разные переменные (modmap и vmodmap), одна для реальных модификаторов, другая - для виртуальных.

Набор реальных модификаторов служит для эмуляции "традиционного" набора модификаторов (в соответствии с core protocol), а набор виртуальных модификаторов может служить аргументами для "действий", связанных с этой клавишей.

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

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

Кроме того, эти два набора служат для установления соответствия между реальными и виртуальными модификаторами. Надо заметить, что виртуальный модификатор не имеет никакого смысла, если не связан с каким-нибудь реальным модификатором.

Состояние XKB: Набор управляющих флагов (XKB Controls).

Кроме номера группы и набора модификаторов, в XKB существует аналогичный набор для "управляющих флагов". Правда, в отличии от номера группы и набора модификаторов, которые "размазаны" по трем переменным (base, locked, latched), набор управляющих флагов только один.

В "управляющие флаги" входят все те "флажки", которые не попали в "набор модификаторов". Они не сообщаются приложению, а используются XKB для переключения его внутренних режимов.
Эти флаги управляют

  • включением режима перекрытия для части клавиатуры;
  • включением режима эмуляции мыши.
  • включением различных режимов подсистемы AccessX.
  • и некоторыми другими сойствами XKB.

"Управляющие флаги" (как и номера групп и модификаторы) меняются соответствущими действиями, привязанными к подходящим клавишам.

Индикаторы.

Как известно, на клавиатуре кроме "кнопок" имеется несколько "лампочек"- индикаторов. Управление этими индикаторами тоже входит в обязанности XKB.
В XKB может существовать до 32 индикаторов.
Естественно, на клавиатуре отображаются только первые 3-4 из них. Эти индикаторы называются в XKB "физическими", а остальные - "виртуальными". Состояние виртуальных модификаторов может быть считано из XKB и отображаться на экране специальными программами (xkbvleds, mxkbledpanel).

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

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

Поэтому, с каждым индикатором связан набор флагов, который определяет

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

Таблица "совместимости".

Как уже упоминалось, XKB вынужден решать "проблему совместимости" с программами, которые не подозревают о существовании XKB и обращаются с запросами к "core-модулю" X-сервера.

Естественно, модуль XKB может обработать эти запросы, но основная проблема, возникающая при этом, состоит в том, что в модуле XKB вводятся некоторые новые понятия (новые относительно core protocol'а), которые никак не отражены в "традиционных" запросах к клавиатурному модулю.

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

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

  • Во-вторых, в core protocol "номер группы" имеет другой смысл. Как уже говорилось - групп всего две, переключаются они символом Mode_Switch и в "состоянии клавиатуры" переключение на "дополнительную" группу отображается одним из модификаторов Mod1-Mod5 - тем, который связан с символом Mode_Switch.

    Таким образом, в "традиционном" протоколе номер группы отображается одним из модификаторов - "основная группа/альтернативная группа", а в модуле XKB, в "состоянии клавиатуры" явно существует двухбитное поле - "номер группы" (которое, к тому же, не "перекрывается" с набором модификаторов).

    Кроме того, в "традиционном" модуле клавиатуры каждая группа состоит ровно из двух "уровней". Хотя при этом допускается, что каждому скан-коду может быть сопоставлен одномерный массив символов длиной до 256. Первые четыре ячейки в нем соответствуют "двум группам, в каждой по два уровня". Остальные ячейки "клиентская" программа может выбирать сама, в зависимости от состояния модификаторов Mod1-Mod5.

    Поэтому, для совместимости модуль XKB, при общении со "старыми" программами, вынужден ...

    • Во-первых, "размазывать" свои подтаблицы-группы в одну строчку "традиционной" таблицы символов (честно говоря, я так и не понял общий алгоритм этого действия, кроме тривиального случая, когда скан-коду соответствует две группы, каждая из двух уровней).
    • Во-вторых, отображать свой "номер группы" в состояние какого-нибудь "реального" модификатора.
  • Наконец, в core-модуле отсутствуют "действия" - основной механизм, обеспечивающий "гибкость поведения" XKB. В связи с этим возникает проблема - "старая" программа может поменять "привязку" символов к скан-кодам, но, поскольку она не подозревает о том, что к скан-кодам могут быть "привязаны" также и "действия", может возникнуть ситуация, когда такая программа переместить, например, символ "переключатель РУС/ЛАТ" на другую клавишу, а соответствующее "действие" (которое в XKB реально осуществляет это переключение) останется на старом месте.

    Для решения этой проблемы в XKB хранится таблица "интерпретаций" (interpretation) управляющих символов. Эта таблица связывает коды символов и вызовы соответствующих "действий" (actions). Естественно, в этой таблице присутствуют только специальные "управляющие" символы ( Caps_Lock, Shift, Num_Lock, "переключатель РУС/ЛАТ" и т.п.).

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

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

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

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

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

Еще несколько определений.

Радио-группы. (Radio Groups)

Модуль XKB позволяет объединять несколько клавиш в "радио-группу". То есть, клавиши одной ради-огруппы являются взаимозависимыми. При нажатии одно из клавиш группы все остальные из этой группы "отжимаются".

Естественно, нажатая клавиша остается "залипшей", пока не будет нажата другая клавиша из этой группы. Принадлежность конкретной клавиши к некоторой радио-группе задается в поле "поведение клавиши".

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

В XKB можно объявить до 127 радио-групп (хотя это может зависить от конкретной реализации XKB).

Перекрытия (Overlay).

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

Такая группа называется "перекрытием" (overlay). Их может быть всего две. Принадлежность конкретной клавиши к конкретной группе-"перекрытию" и "альтернативный" скан-код задаются в поле "поведение клавиши".

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

AccessX.Дополнительные услуги для людей с ограниченными физическими возможностями.

Имеются ввиду люди у которых подвижность рук (пальцев) ограничена или они вынуждены пользоваться какими-либо маханическими приспособлениями для работы с клавиатурой.

Проблемы, которые могут возникнуть при этом:

  • Невозможно нажимать одновременно несколько клавиш (например Shift+"буква"). Для решения этой проблемы в XKB предусмотрен режим StickyKeys ("прилипающие клавиши"). В этом режиме вместо одновременного нажатия нескольких клавиш можно нажимать их последовательно. Например, вместо Shift+Control+C можно последовательно нажать клавиши Shift, Control и C. Обратие внимание - не все клавиши должны "слипаться". Правило здесь простое - если клавиша является модификатором и без других кнопок ее нажатие не имеет смысла, то после нажатия такой клавиши XKB ждет нажатия других клавиш, чтобы "слепить" в одно событие. Если и последующие кнопки являются модификаторами (как Control после Shift в нашем примере), то XKB остается в состянии ожидания. И только после нажатия обычной (буквенной клавиши) генерируется event и XKB возвращается в нормальное состяние.
    Кроме того заметьте, что этот режим сам может вызвать проблему если клавиша модификатор нажата по ошибке. Любое следующее нажатие вызовет не то действие, которое хотелось бы. Поэтому в режиме StickyKeys предусмотрена специальная задержка (это настраиваемый параметр) в течении которой XKB ждет следующую клавишу. Если за это время другого нажатия не последовало, то клавиша отпускается.
  • "Дребезг" клавиши при нажатии. Для решения этой проблемы в XKB предусмотрен режим BounceKeys ("прыгающие клавиши"). В этом режиме после первого нажатия на клавишу XKB на некоторое время становится "нечувствительным", то есть не обращает внимание на изменение состяния клавиши и таким образом игнорирует лишние нажатия. Естественно интервал времени "нечувствительности" можно менять.
  • Ошибочное "задевание" клавиш. Имеется ввиду, что человек при перемещении руки от одной клавиши к другой может случайно задеть несколько клавшь, которые нажимать не собирался. Для решения этой проблемы предусмотрен режим SlowKeys ("медленные клавиши"). Смысл его в том, что клавиша считается реально нажатой если она остается в таком состоянии некоторое время (опять же это время можно настраивать). Другими словами, если клавишу нажать и быстро отпустить, то XKB игнорирут такое скоротечное нажатие.
  • Невозможность управлять "мышью". Для решения этой проблемы в XKB предусморена возможность эмулировать события мыши с помощью клавиатуры. Подробнее об этом режиме мы поговорим ниже.

Все эти режимы осуществляются частью XKB модуля, которая называется AccessX. Все режимы можно включать и выключать по отдельности изменяя состяние одноименных "управляющих флагов XKB" (XKB Controls).

Обратите внимание, что само включение режимов AccessX может быть проблемой. (Представьте себе, что человеку нужен режим StickyKeys, а для его активизации нужно нажать сложную комбинация из нескольких клавиш). Поэтому для включения некоторых режимов используются специальные действия:

  • Если нажать клавишу Shift и удерживать ее нажатой в течении 8 секунд, то включается режим SlowKeys.
  • Если нажать тот же Shift пять раз подряд, то включется режим StickyKeys.

Правда для этого должен быть включен режим распознавания таких "магических последовательностей" (AccessXKeys). Его можно включить

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

С другой стороны, если один из режимов AccessX включен, а компьютер используется разными пользователями, то человку не имеющему ограничений он может наоборот мешать. Поэтому в XKB предусмотрено автоматическое отключение режимов AccessX, если в течении некоторого времени клавиатура никак не использовалась. Кроме того, режим StickyKeys (эмуляция одновременного нажатия через последовательное) автоматически выключиться, если вы нажмете несколько клавиш действительно одновременно.
Саму возможность автоматического выключения AccessX по таймауту можно (как и другие режимы) включить/выключить соответствующим флагом (AccessXTimeout) в XKB Controls.

И наконец - в AccessX предусмотрен дополнительный режим звуковой индикации всех происходящих событий - начало и окончание всевозможных таймаутов, а также включение и выключение LED'ов. Для того, чтобы лучше ориентироваться в этх событиях (особенно если включено несколько разных режимов AccessX) XKB старается озвучивать их звуками разной длительности и тона (насколько позволяет "железо").
Этот режим, как и другие может быть включен/выключен соответсвующим флагом (AccessXFeedback) в XKB Controls. Кроме того, можно по отдельности включить/выключить озвучивание отдельных событий.

Эмуляция "мыши"

XKB может эмулировать события мыши с помощью клавиатуры. То есть, его можно настроить так, что при нажатии определенных клавиш X-сервер будет посылать приложению сообщения (events) не о нажатии/отжатии кнопок, а о перемещении мыши и нажатии кнопок на мышке.

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

Рассмотрим их немного подробнее.

  • В action "перемещение" можно задавать сразу обе координаты (или их приращения). Координаты могут быть как абсолютные (это означает, что при выполнении такого действия указатель мыши должен встать в заданную точку экрана), так и относительные - собственно перемещение на несколько точек в нужном направлении. Обычно для удобства делают несколько разных action для одного направления, но с разными приращениями - на одну точку, на десять точек и т.д. Эти action можно привязать к одной кнопке, но в разных уровнях. Получится, что при обычном нажатии кнопки указатель смещается, на одну точку, а нажатие той же кнопки с Shift'ом перемещение будет на несколько точек при одном нажатии.
  • В action "нажатии кнопки мыши" можно кроме самой кнопки указать и число повторов. То есть, одиночное нажатие клавиши может эмулировать "двойной клик" (или тройной, четверной и т.п.).
  • Кроме того, существует разновидность этих действий, которая не просто "нажимает кнопку мыши" по нажатии клавиши, а оставляет ее нажатой после отпускания клавши (как все Lock клавши). То есть, вы можете с помощью такого действия "прижать кнопку мыши", переместить указатель и повторным нажатием клавиши "отпустить кнопку мыши". Естественно, это выглядит так, как будто вы двигали реальную мышь с нажатой кнопкой.
  • И наконец, обратите внимание, что кнопок мыши может быть до пяти, а с учетом "многократных кликов" и Lock'ирующих нажатий может получится, что под "мышинные кнопки" придется занять довольно много клавиш. Для того, чтобы сократить это количество в XKB предусмотрено, что одну из кнопок можно объявить "кнопкой по умолчанию" (default button). Для такого назначения и его изменения предусмотрены специальные действия, в которых можно опять же указать, как конкретную кнопку (по номеру), так и относительное изменение номера "кнопки по умолчания". Комбинируя эти действия, можно одной клавишей перебирать циклически кнопки (делая их по очереди "умолчательными"), а в действиях "нажимающих" кнопки указать, что они относятся к той кнопке, которая сейчас выбрана как default button. (Проблема только в том, как не запутаться и не забыть - какая кнопка сейчас выбрана :-)

Кроме того, существует два режима (mode) перемещения мыши - простой и "с ускорением" (accelerated). При одиночном нажатии клавиши разница между ними незаметна. А вот если вы держите клавишу нажатой и работает автоповтор, тот в обычном режиме на каждый автоповтор указатель смещается на одно и то же количество точек (заданое в аргументах действия). А в accelerated mode указатель начинает ускоряться, то есть с каждым новым автоповтором размер одиночного шага растет.

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

  • delay - интервал (в миллисекундах) от нажатия клавиши (эмулирующей движение мыши) до первого автоповтора.
  • interval - интервал (в миллисекундах) между повторами
  • maxspeed - максимальная скорость (в точках на один повтор)
  • timetomax - количество повторов, за которое достигается максимальная скорость движения. Как видите, здесь нет в явном виде величины ускорения. XKB сам вычисляет его из начальной величины смещения (задается в конкретном действии), maxspeed и timetomax.
  • curve - "степень кривизны" ускорения. Дело в том, что скорость может расти не линейно. В общем виде приращение скорости пропорционально функции X^(1 + curve/1000). То есть, при curve=0 скорость растет линейно, а при других значениях (от -1000 до +1000) с некоторой "кривизной".

По умолчанию используется именно режим с ускорением.

Включение и выключение эмуляции мыши и выбор режима движения выбирается двумя управляющими флагами XKB (XKB Controls) - MouseKeys и MouseKeysAccel.

Надо заметить, что по умолчанию все нужные действия описаны и привязаны к кнопкам "дополнительной цифровой клавиатуры" (NUMPAD). Для включения и выключения режима эмуляции мыши используется комбинация Shift+NumLock.

Расширенные возможности "пищалки" (Bell).

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

Надо отметить, что управление "пищалкой" заложено еще в традиционном (core) модуле клавиатуры. С помощью стандартных запросов к X-серверу, приложение может регулировать параметры key_click'а (высоту тона, длительность и громкость), а также вызвать этот click при необходимости.

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

Поэтому, по замыслу разработчиков, выбором конкретного звука и его воспроизведением должна заниматься отдельная программа (назовем ее - "музыкальная приставка"). А модуль XKB вместо "писка" просто генерирует специальное сообщение (event), которое так же как и обычные event'ы X-сервера могут быть доставлены любой программе. "Музыкальная приставка" только должна при старте сообщить X-серверу, что ее интересует определенная разновидность event'ов (в данном случае - bell-event'ы от модуля XKB).

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

Соответственно, теперь любое приложение с помощью соответствующих запросов к X-серверу (теперь уже не в core-формате, а в формате XKB), может заказать не просто "писк" с определенным тоном и длительностью, а любой звук, указав его имя (bell name).

При этом XKB собственно является просто "ретранслятором". Он даже не анализирует правильность "имени звука", а просто, получив запрос от любого приложения, передает его в виде своего event'а "музыкальной приставке".

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

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

Надо заметить также, что XKB не только ретранслирует запросы, но и сам может "заказать звук" при некоторых изменениях своего внутреннего состояния (состояния индикаторов, флагов и т.п.).

Общие замечания о языке файлов конфигурации XKB.

Для описания конфигурации XKB используется язык с синтаксисом похожим на синтаксис языка C.

Поэтому, формат числовых и строковых констант, встречающихся в этих файлах, обычно соответствут формату констант языка C.

Так строковые константы представляют собой набор символов ограниченный "двойными кавычками" (например - "Num Lock"). Причем, внутри строк могут встречаться "спецсимволы", которые обозначаются так же как в языке C (\r, \n, \t, \v, \b, \f или через восьмеричный код - \0**).

Числовые константы могут записываться как в десятичном формате (например - 123), так и в шестнадцатеричном (0x123, 0xff) и восьмеричном (033).

Главное отличие от языка C в том, что во всех словах маленькие и большие буквы НЕ различаются (case insensitive). То есть, например - SETMODS, SetMods, setMods и setmods означают одно и то же.

Объявления в файлах конфигурации, общие для всех типов файлов.

Каждый файл или блок конфигурации состоит из группы объявлений (деклараций, инструкций, определений ?).

Какие именно объявления допустимы в конкретном файле (и как они выглядят) зависит от "Типа Файла".

Однако, есть некоторые слова, которые могут встречаться в файлах (блоках) любых типов.

Инструкция include.

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

  include "en_US(pc104)+ru"

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

Способ добавления.

Перед каждым отдельным объявлением может стоять дополнительное слово, которое определяет "способ добавления" или "замещения" (merge mode).

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

  • augment - в случае конфликта оставить старое определение, новое игнорировать
  • override - заменить строе определение на новое
  • replace - обычно то же самое, что и override, но в файле xkb_symbols означает немного другое. Поскольку, каждому скан-коду соответствует целый массив возможных значений (какое именно выбирается - зависит от модификаторов), различные определения одного и того же скан-кода могут описывать значения только для части ячеек этого массива. Так вот, если новое описание определяет только некоторые ячейки и "способ добавления" - override, то переписаны будут только те ячейки, которые присутствуют в новом определении, остальные останутся без изменений. А вот если "способ добавления" - replace, то все старое описание уничтожается (включая те ячейки, которые отсутствуют в новом описании) и заменяется на новое, даже если оно не полное.
  • alternate - допустимо только для файлов типа xkb_keycodes, означает, что, если новое имя конфликтует с уже существующим, то просто рассматривать его как "alias скан-кода", то есть - просто другое имя для того же числового значения скан-кода.

Еще раз об include.

Кстати, возвращаясь к инструкции include. Если объявления из "включаемого" файла "перекрываются" с уже имеющимися, то "по умолчанию" считается, что они добавляются в режиме override (если внутри файла они не помечены другими "способами добавления"). То же самое "умолчание" действует, если в строке-аргументе include есть дополнительные файлы, через знак '+'.

А вот если вместо плюса стоит знак '|', то это означает, что следующий файл должен добавляться в режиме augment (опять же, некоторые объявления внутри него могут иметь свои "способы добавления").

Кроме того, "способ добавления" (кроме altrenate) может использоваться вместо инструкции include. То есть, вместо

include "group(toggle)"

можно использовать, например, инструкцию

replace "group(toggle)"

Нетрудно догадаться, что это означает, что все инструкции из файла (блока) "group(toggle)" должны быть вставлены в текущий файл (как по инструкции include), но при этом подразумевается, что у всех инструкций "способ добавления" - replace.

Общее строение файлов конфигурации XKB.

Возможны три типа файлов конфигурации

"Простая" конфигурация

Если в файле находится "простая" конфигурация, то в начале файла должен быть заголовок

  [ Флаги ] ТипФайла [ Имя ]

после которого сразу следуют объявления (или инструкции). Например,

xkb_keyсodes

   = 49;
   = 10;
.......

Последовательность из "простых" блоков.

Однако, чаще используется другой формат файла - последовательность "простых" блоков. В таком файле объявления группируются в блоки, которые ограничиваются фигурными скобками - '{...}' (после каждого блока должна быть "точка с запятой" - ';').

Перед каждым блоком должен быть заголовок, такой же как и в файле с "простой" конфигурацией

 [ Флаги ] ТипФайла   [ Имя1 ] '{' [ Объявления ] '};'
 [ Флаги ] ТипФайла   [ Имя2 ] '{' [ Объявления ] '};'
...

Например,

xkb_symbols "basic" {....};
xkb_symbols "us" {....};
....

Типы файлов.

И в том и в другом формате используются одинаковые "Типы Файлов". Это может быть одно из пяти слов

  • xkb_keycodes - файл (или блок), в котором числовым значения скан-кодов даются символические имена
  • xkb_types - файл, в котором описываются возможные типы клавиш (тип определяет - сколько различных значений может иметь одна и та же клавиша в зависимости от состояния модификаторов)
  • xkb_compat - файл, в котором описывается "поведение" модификаторов
  • xkb_symbols - основной файл, в котором каждому скан-коду (заданному символическим именем) назначаются все возможные значения, которые может выдавать конкретная клавиша (другими словами - "раскладка клавиатуры").
  • xkb_geometry - описание расположения кнопок и индикаторов на клавиатуре

Надо отметить, что, если файл состоит из нескольких блоков, то все блоки должны быть одного типа. Отличаются они только именем.

Имя представляет собой произвольное слово в двойных кавычках.

Как можно заметить, в формате заголовка только "ТипФайла" должен присутствовать обязательно, а "Имя" может отсутствовать. Естественно, если файл предствляет собой "простую" конфигурацию или содержит только один блок, то именовать их необязательно. В этом случае, чтобы сослаться в настройках X-сервера на такую конфигурацию достаточно указать имя файла.

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

 имя_файла(имя_блока)

например,

 us(pc104)

Флаги.

В каждом заголовке может быть несколько флагов

  • default - этот флаг имеет смысл, если файл состоит из нескольких блоков. Он помечает один из блоков (только один !) как блок "по умолчанию". То есть, если где-то будет указано, что конфигурацию надо брать из такого файла, но при этом не сказано - из какого блока, то будет взят именно тот из блоков, который помечен флагом "default".
  • partial - означает, что в этом блоке дано не полное описание соответствующего типа, а только его часть. Например, это может быть блок типа xkb_symbols, в котором описаны только "функциональные" клавиши, или блок типа xkb_geometry, в котором описано только расположение индикаторов.
  • hidden - означает, что определения из этого блока в "нормальном" состоянии клавиатуры (когда не активен ни один из модификаторов) не видны, и проявляются только при нажатии какого-нибудь модификатора. Например, блок типа xkb_symbols в котором описаны коды которые выдает "дополнительная цифровая клавиатура" (keypad) при нажатом Num_Lock.

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

  • alphanumeric_keys - "алфавитно-цифровые"
  • modifier_keys - модификаторы (Control, Alt, Meta и т.п.)
  • keypad_keys - клавиши "дополнительной цифровой" клавиатуры
  • function_keys - "функциональные" клавиши
  • alternate_group - "альтернативная" группа, то есть символы какого-нибудь национального алфавита.

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

Кстати, сводный список всех блоков конфигураций с их флагами можно найти в файлах *.dir в директории {XROOT}/lib/X11/xkb. Названия файлов аналогичны названиям типов конфигурации - keycodes, types, symbols и т.д. Флаги там обозначаются одной буквой - первой буквой из названия соответствующего флага.

Последовательность из "составных" блоков.

Наконец, рассмотрим третий тип конфигурационного файла - последовательность из "составных" блоков. Каждый такой "Составной Блок" оформляется как "простой" блок

 [ Флаги ] СложныйТип [ Имя ] '{' Блок { Блок } '}' ';'

но внутри содержит не просто объявления, а блоки "простых" типов, например

xkb_keymap "complete" {
        xkb_keycodes  {...};
        xkb_types     {...};
        xkb_compat    {...};
        xkb_symbols   {...};
        xkb_geometry  {...};
};

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

Существует три типа "составных" блоков

  • xkb_semantics - такой блок должен содержать блок xkb_compat и может также иметь в себе блок xkb_types;
  • xkb_layout - должен содержать блоки xkb_keycodes, xkb_types, xkb_symbols и может, также, иметь в себе блок xkb_geometry;
  • xkb_keymap - наиболее полный блок, должен включать в себя все, что должны содержать предыдущие два типа (то есть - xkb_keycodes, xkb_types, xkb_compat xkb_symbols) и может включать дополнительно те компоненты, которые могут иметь в себе два предыдущих типа.

Файл типа xkb_keycodes.

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

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

А, кроме того, сам X-сервер переводит эти коды в свои "унифицированные" скан-коды, которые не зависят от архитектуры ("железной" и "софтверной") системы.

Поэтому, при выборе подходящей таблицы xkb_keycodes надо ориентироваться на тип X-сервера, который вы используете. Так, для сервера из "семейства" XFree86, самое правильное - брать определения keycodes, которые соответствуют набору скан-кодов, выдаваемых XFree86.

В файле xkb_keycodes могут встречаться четыре типа объявлений.

Объявление Переменной.

В файле xkb_keycodes могут быть определены две переменные - minimum и maximum.

Они задают минимальное и максимальное значение для скан-кодов. Естественно, что все скан-коды, которые будут использоваться для задания символических имен должны "вписатся" в диапазон между minimum и maximum. Вообще говоря, "объявление переменной" имеет вид

имя_переменной '=' Выражение ';'

Поэтому, слева от знака '=' должно быть либо слово 'minimum', либо - 'maximum'. А справа может быть любое арифметическое выражение (только вот - зачем ?), которое может быть вычислено на этапе "разборки" файла и дать в результате константу типа INTEGER.

Объявление Имени Клавиши.

Основное объявление, которое используется в файлах этого типа.
Имеет вид

KEYNAME '=' Выражение ';'

KEYNAME, вообще говоря, просто некоторая строка символов (string), допустимая в языке C. Отличается только тем, что она ограничивается "угловыми скобками" - знаками '<' и '>' и должна быть не длиннее 4 символов.
Например,

   = ... ;

"Выражение" в правой части объявления может быть любым арифметическим выражением, допустимым в языке C. То есть, содержать операции '+ - / *' и "круглые" скобки, при этом операндами могут быть числовые константы десятичного, шестнадцатеричного и восьмеричного типов (в терминах языка C).

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

Объявление Алиаса Клавиши.

Эти объявления имеют вид

'alias' KEYNAME '=' KEYNAME ';'

Они служат просто для того, чтобы одному скан-коду дать несколько разных имен.

Объявление Имени Индикатора.

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

Заметим, что в в модуле XKB, существует 32 индикатора. Часть из них отображается на светодиодах (LED) клавиатуры (обычно - первые три) и являются "физическими" индикаторами. Остальные никак не отображаются на "физической" клавиатуре, но могут изображаться специальными программами (xkbvleds, mxkbledpanel). Поэтому, они называются "виртуальными индикаторами".

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

В файлах типа xkb_keycodes им только даются символические имена, которые потом используются в файлах типа xkb_compat и xkb_geometry для указания индикатора.

Объявление имени индикатора имеет вид

'indicator' INTEGER '=' STRING ';'

или

'virtual indicator' INTEGER '=' STRING ';'

Здесь, INTEGER - числовая константы типа INTEGER. Она просто определяет номер индикатора. Обычно, первые три индикатора являются "физическими" (светодиоды NumLock, CapsLock и ScrollLock на клавиатуре), остальные - с 4 по 32, являются "виртуальными" (то есть, никак не отображаются на "физической" клавиатуре).

STRING - произвольная строка символов в "двойных кавычках".

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

Пример файла типа xkb_keycodes

default xkb_keycodes "xfree86" {

    minimum= 8;
    maximum= 134;

     =  49;
     =  10;
     =  11;
.......

    indicator 1 = "Caps Lock";
    indicator 2 = "Num Lock";
    indicator 3 = "Scroll Lock";

    virtual indicator 4 = "Shift Lock";
    virtual indicator 5 = "Altrnate Group";

    alias  = ;
};

Файл типа xkb_types.

В этом файле описывается - каким образом вычисляется "уровень" (shift level) в таблице символов (symbols) для каждой клавиши. 
Напомню, что с каждой клавишей (скан-кодом) в XKB связано от одной до четырех однострочных таблиц символов. Конкретная таблица выбирается в соответствии с "текущим номером группы" (group number), а конкретный символ в группе значением "уровеня" (shift level). 
Обычно, разные "номера групп" используется для разных национальных языков (точнее - алфавитов), а разные "уровни" используются для больших/маленьких букв (в общем-то, все знают - что меняется при нажатии кнопки Shift). Хотя заметим, что XKB позволяет иметь до четырех групп и до 64 (!) "уровней" 
Так вот. Если изменение "номера группы" описывается в файле 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 = ...;
  • map[...] = ...;
  • level_name[...] = ...;
  • preserve[...] = ...;

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], как правило, присутствует в каждом типе.
Замечу также, что уровень можно указывать как по имени - Level1, Level2 и т.д., так и просто числом в допустимом диапазоне (1-64). Кстати, программа xkbcomp понимает только названия от Level1 до Level8. Поэтому если вам понадобится больше уровней, то указать их вы сможете только цифрами. 

level_name[...]

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

preserve[...]

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

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

В модуле XKB "по умолчанию" определены четыре типа и, соответственно, каждая клавиша "по умолчанию" приписана к одному из этих четырех типов. 
  • "ONE_LEVEL" - клавиши, которые имею только одно значение, независимо от состояния модификаторов (Enter, Escape, Space и т.п.)
  • "TWO_LEVEL" - клавиши с двумя уровнями (но не "буквенные"), второй уровень выбирается модификатором Shift (но не зависит от Lock). Это, в основном, клавиши на 0основной клавиатуре с цифрами и "специальными" символами (1/!, 2/@, 3/# и т.д.)
  • "ALPHABETIC" - "буквенные" клавиши. Они имеют два уровня (прописные/строчные), но в отличии от клавиш типа "TWO_LEVEL" зависят не только от Shift, но и от Lock.
  • "KEYPAD" - клавиши на "дополнительной цифровой клавиатуре" (keypad). Тоже имеют два уровня, зависят от состояния NumLock и Shift.
Надо заметить, что, если клавиша отнесена к соответствующему типу, в ее описании (в xkb_symbols) массив значений должен иметь необходимое количество "уровней". 
Как следствие этого, хотя вы можете переопределить любой из "предопределенных" типов (поменяв в нем модификаторы или названия уровней), но при этом нельзя менять в них количество уровней. 
Если вам хочется иметь для каких-то клавиш большее количество уровней, придется сочинить для них новый тип (напомню, что назвать его можно как угодно).
Примеры описаний типов, можно посмотреть в соответствущих файлах в директории {XKBROOT}/types/, поэтому я здесь их приводить не буду. 
А пример составления нового типа и его использования можно посмотреть в разделе "Примеры":"Новый тип для клавиши Enter". 

Файл, типа xkb_compat.

В этом файле описывается поведение клавиш модификаторов - какие изменения происходят в состоянии клавиатуры (изменения битов-модификаторов и "номера группы") при нажатии этих клавиш. 
Напомню, что внутри XKB существует структура (таблица) - Xkb Compability Map, которая состоит из двух частей 
  • набора (массива) "интерпретаций" (interpret)
  • четырех переменных, которые определяют - какие "реальные" модификаторы (модификаторы "традиционного" клаватурного модуля X-сервера) будут отображать изменение "номера группы".
Если прикладные программы обращаются к X-серверу не специальными XKB-запросами, а запросами к "традиционному" клавиатурному модулю X-сервера, которые должны поменять "привязку" кодов символов (или реальных модификаторов) к скан-кодам, то модуль XKB, выполнив требуемый перенос, пытается также пренести и "действия", "привязанные" к скан-кодам (и некоторые другие параметры клавиши). 
Для выполнения такого "переноса" и используется Xkb Compability Map.
В файле типа xkb_compat могут встречаться объявления 

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

Как и в файле типа xkb_types, прежде всего должны быть объявлены виртуальные модификаторы, которые могут встречаться в дальнейших описаниях. Реальные модификаторы (если они также используются) описывать не надо, поскольку, они имеют стандартные названия. А вот виртуальные модификаторы могут иметь произвольные названия, поэтому, для правильной интерпретации остальных записей необходимо сообщить программе, которая будет "разбирать" этот файл, что соответствующие слова являются названиями виртуальных модификаторов. 
Объявление виртуальных модификаторов имеет вид 
'virtual_modifiers' список модификаторов ';'
Например, 
virtual_modifiers NumLock, AltGr ;

Описание "интерпретации".

Каждая "интерпретация" (interpretation) устанавливает соответствие между кодом какго-нибудь "управляющего" символа (symbol) и "действием" (action), которое должен будет выполнить модуль XKB при нажатии клавиши к которой "привязан" этот символ. 
Полностью внутренняя структура, описывающая интерпретацию, состоит из 
  • кода символа
  • "действия"
  • набора реальных модификаторов
  • "критерия соответствия" модификаторам
  • флагов ("автоповтор" и "залипание")
  • виртуального модификатора для клавиши
Естественно, не все эти поля обязательно должны быть заполнены. 
Итак, поле "код символа", естественно, определяет символ, к которому "привязывается" "действие", а поле "действие" - само это "действие". 
Также, в "интерпретации" могут быть заданы поля "реальные модификаторы" и "критерий соответствия". 
Для чего нужны эти поля? 
Напомню, что к любому скан-коду может быть "привязан" один или несколько реальных модификаторов. При поиске подходящего места для "действия", XKB может использовать не только код символа, но и расположение этих реальных модификаторов.
Если эти поля НЕ заданы, то XKB, при изменнии "привязки" символа к скан-коду, просто перенесет туда же соответствующее "действие". 
А вот если эти поля заданы, то прежде чем выполнить перенос, XKB сравнивает набор реальных модификаторов, привязанных к скан-коду и набор реальных модификаторов, указанный в "интерпретации". "Критерий соответствия" определяет - как сравнивать эти два набора (см. ниже). 
Если условие выполняется, "действие" переносится.
Кстати, если используются эти два поля (набор модификаторов и "критерий соответствия"), то кода символа может в интерпретации и не быть. 
При этом, поиск подходящего места делается XKB только на сравнении наборов модификаторов. Например - найти тот скан-код, к которому "привязан" реальный модификатор Lock, и перенести туда "действие", независимо от того, какой код символа соответствует этому скан-коду. 
Итак. Поле "реальные модификаторы" представляет собой просто один или несколько битов модификаторов. 
А "критерий соответствия" представляет собой одно из условий
  • AnyOfOrNone (любой из... или ни одного) - практически означает, что поле "модификаторов" не имеет никагого смысла, условие выполняется, если совпадает любой из модификаторов или никакой;
  • NoneOf (ни один из...) - у скан-кода не должно быть ни одного из указанных модификаторов;
  • AnyOf (любой из...) - у скан-кода должен быть хотя бы один из указанных модификаторов;
  • AllOf (все из...) - должны совпасть все указанные модификаторы;
  • Exactly (точно) - то же, что и AllOf, но при этом у скан-кода не должно быть ни одного модификатора, не попавшего в список.
Кроме того, вместе с любым из перечисленных "критериев" может быть указан "критерий" 
  • LevelOneOnly (только первый уровень) - условие выполняется, если символ привязывается к первому уровню первой группы в соответствующем скан-коде. Выполнение этого условия также требуется, для переноса "флагов" и "виртуального модификатора".
Естественно, "по умолчанию" поле модификаторов пустое, а "критерий" - "любой из.. или ни одного". 
Поле флагов и виртуальный модификатор (он должен быть только один), могут быть тоже "перенесены" в описание скан-кода, если символ "переносится" в первый уровень первой группы таблицы, привязанной к скан-коду. 
Флаги добавляются в поле "поведение клавиши", а модификатор в поле "виртуальные модификаторы" (эти поля есть у каждого описания скан-кода). 
"По умолчанию" поле "флаги" содержит флаг "автоповтор", а поле "виртуальный модификатор" - пустое. Итак. Описание "интерпретации" имеет вид 
'interpret' символ '{' описание  '};'
или 
'interpret' символ '+' модификатор '{' описание  '};'
или 
'interpret' символ '+' критерий '(' модификаторы ') {' описание  '};'
Например 
interpret  Nun_Lock {...};
interpret  ISO_Level2 + Shift {...};
interpret  ISO_Lock + AnyOf(Lock+shift) {...};
Если в заголовке указан только код символа, критерий - AnyOfOrNone, поле модификаторов - пустое. 
Если указан, код символа и название модификатора (не указан "критерий"), то "критерий" - Exactly. 
Если указан "критерий", то в скобках вместо списка модификаторов может стоять слово all. Понятно, что это означает - все модификаторы. 
Кроме того, вместо "критерия" и списка модификаторов может использоваться слово Any. Это означает - AnyOf(all). 
Наконец, как уже говорилось, если есть набор модификаторов и "критерий", то кода символа может и не быть ("привязка" осуществляется путем сравнения наборов модификаторов). В этом случае, вместо кода символа также ставится слово - Any. 
Например,
interpret Any + Any {...};
означает, что эта "интерпретация" применяется ко всем клавишам, у которых есть реальные модификаторы. 
Внутри описания "интерпретации" могут быть строчки типа оператора присваивания 
  • useModMapMods = ...; или useModMap = ...;
  • repeat = ...;
  • locking = ...;
  • virtualModifier = ...; или virtualMod = ...;
  • action = ...;

useModMapMods

Служит для указания "критерия" LevelOneOnly. Если справа стоит слово "level1" или "levelone", то "критерий" проверяется. Если слова "anylevel" или "any" - игнорируется. Кстати, "по умолчанию" он игнорируется, так что строчки вида 
useModMapMods = anylevel;
особого смысла не имеют. 

repeat и locking

Устанавливают значения для флагов "автоповтор" и "залипание". Справа от присваивания должно быть логическое значение - True или False. 
Например,
repeat = True;
locking = False;

virtualModifier

Указывает виртуальный модификатор. Напомню, что этот модификатор тоже може быть добавлен к описанию скан-кода, если символ переносится в "первый уровень первой группы" таблицы значений для скан-кода. 
Справа от присваивания просто указывается название виртуального модификатора. 
Например,
virtualModifier = AltGr;

action

Описывает "действие". Подробнее об этом читайте "Описание действий". 
Здесь замечу, что "действие" также может быть "пустым". Если "интерпретация" нужна для того, чтобы перенести не "действие", а только "флаги" или "виртуальный модификатор", то ее описание может выглядеть как
interpret ... {
  repeat = False;
  locking = True;
  action = NoAction();
};

Объявление "отображения номера группы в модификатор".

Напомню, что в "состоянии XKB" (которое может быть "считано" прикладной программой) есть специальное двухбитное поле, в котором указан текущий номер группы. В "традиционном" "состоянии клавиатуры" такого поля нет, а смена группы индицируется одним из модификаторов. 
Поэтому, для программ, понимающих только "традиционное состояние клавиатуры", XKB преобразует номер группы в активное состояние какого-нибудь модификатора. 
Для каждого из четырех номеров групп может быть объявлен отдельный модификатор (хотя обычно, используется один для всех групп, отличных от первой). 
Это объявление имеет очень простой вид. 
'group' номер группы '=' модификатор ';'
Например, 
group 2 = AltGr;

Описание поведения индикатора.

В файлах типа xkb_compat также описывается "поведение индикаторов", хотя к "таблице совместимости" (compability) они отношения не имеют. 
Напомню, что в XKB можно определить до 32 индикаторов. Первые 3-4 (в зависимости от типа клавиатуры) отображаются реальными "лампочками" на клавиатуре, а остальные считаются "виртуальными" и могут отображаться специальными программами. 
В файле типа xkb_keycodes индикаторам даются символические имена (связыватся номера индикаторов и "имя индикатора"). 
А в файле xkb_compat описывается - как эти индикаторы ведут себя в зависимости от "состояния клавиатуры". Напомню, что... 
Во-первых, индикаторы могут отображать состояние
  • модификаторов,
  • номера группы,
  • управляющих флагов.
Причем, поскольку первые два из перечисленных "компонентов состояния XKB" "размазаны" по трем переменным (base, locked, latched), поведение индикаторы можно связать с любой из указанных переменных или с их "эффективным" (суммарным) значением. 
Надо отметить, что один и тот же индикатор может одновременно "отслеживать" изменения и "своего" модификатора, и какого-нибудь номера группы, и управляющего флага (хотя, зачем это нужно?). 
Во-вторых, индикатор может не только "отслеживать" состяние XKB, но и включаться/выключаться прикладными программами. При этом, в описании индикатора можно разрешить/запретить такое включение/выключение или установить "обратную связь" (то есть, при включении/выключении индикатора будут происходить соответствующие изменения в состоянии XKB). 
Итак. Описание поведения индикатора имеет вид 
'indicator' имя_индикатора '{' описание  '};'
Здесь "имя_индикатора" - это то символическое имя (строка символов в двойных кавычках), которое было дано ему в файле xkb_keycodes. 
А "описание" обычно имеет вид оператора присваивания (исключение - логические переменные-флаги, которые могут принимать значения только True/False). 
В этих "описаниях" могут встретиться строчки типа 
  • modifiers = ...; или mods = ...;
  • groups = ...;
  • controls = ...; или ctrls = ...;
  • whichModState = ...; или whichModifierState = ...;
  • whichGroupState = ...;
  • allowExplicit = ...;
  • drivesKeyboard = ...; (имеет кучу "синонимов", см. ниже)
  • index = ...;

modifiers, groups и controls

Определяют - какие компоненты "состояния" должен отслеживать индикатор. 
Естественно, справа от знака присваивания должен быть ...
  • для modifiers - название модификатора или нескольких модификаторов через знак "+";
  • для groups - номера групп;
  • для controls - название "управляющего флага" (флагов).
Надо отметить, что номер группы можно задавать 
  • просто числовым значением
  • в виде - group1, group2 и т.п.;
  • можно использовать слова "none" (0) и "all" (0xFF);
  • и, наконец, с помощью простых арифметических выражений, например, All-1 ("все, кроме первой")

whichModState и whichGroupState

Поскольку набор модификаторов и номер группы "размазаны" по трем переменным (base, locked, latched), эти инструкции уточняют - в каких переменных надо отслеживать модификаторы и номер группы, соответственно. 
Справа от присваивания может быть слово 
  • base - отслеживать изменение в переменных base (base Group или base Modifiers, соответственно)
  • locked - то же самое, в переменных locked
  • latched - то же самое, в переменных latched
  • effective - отслеживать изменения "эффективных" номера групп или модификаторов (то есть в суммарных значениях всех трех переменных)
  • any - отслеживать изменения во всех трех переменных (то есть, индикатор будет включаться/выключаться, если указанное значение модификатора или группы будет меняться в любой из трех переменных); надо заметить, что для модификаторов (whichModState) это значение эквивалентно effective, поскольку "включение" модификатора в любой из трех переменных, неизбежно "включит" его и в "эффективном" наборе модификаторов;
  • none - "ни в каком". Такая инструкция имеет смысл, если надо отменить "привязку" данного индикатора к номеру группы или модификатору, объявленную в другом файле.
По умолчанию (то есть, если which...State явно не указаны) подразумевается effective. 

allowExplicit

Логический флаг, который разрешает (запрещает) прикладным программам включать/выключать индикатор. Обратите внимание, конечно, для включения/выключения индикатора прикладная программа посылает специальные запросы к XKB. Но XKB по этим командам только меняет (если это разрешено) только состояние индикатора, не затрагивая свое "состояние". Естественно, при этом состояние индикатор может не соответствовать состоянию XKB. 
Поскольку allowExplicit является логической переменной, справа от присваивания должно быть только True или False. 
Можно также использовать другую форму этой инструкции. Так, просто указание 
allowExplicit;
эквивалентно 
allowExplicit = True;
а строчка 
!allowExplicit;
эквивалентна 
allowExplicit = False;
По умолчанию этот "флажок" - True. То есть, прикладным программам разрешено менять состяние индикатора, помимо "состояния клавиатуры". 

drivesKeyboard

Имеет много синонимов - drivesKbd, ledDrivesKbd, ledDrivesKkeyboard, indicatorDrivesKbd, indicatorDrivesKeyboard. 
Это тоже логический флаг, который заставляет XKB устанавливать "обратную связь" между индикатором и "состянием клавиатуры". То есть, если это флаг "взведен" (и разрешено allowExplicit), то, при изменении прикладной программой состяния индикатора, XKB должен изменить и связанные с ним компоненты "состяния клавиатуры". 
Обратите внимание, что 
  • меняться должны те компонеты, которые заданы инструкциями modifiers, group и controls (обычно задан только один из компонентов);
  • инструкции whichModState и whichGroupState указывают - в каких из трех переменных (base, locked, latched) следует поменять модификатор или группу.
При этом, если "which...state" - none, base или any, никакого эффекта не будет. А effective эквивалентно locked. Напомню, что по умолчанию подразумевается значение effective, следовательно - если инструкций вида "which...state" в описании нет, то изменения будут делаться в locked Group или locked Modifiers, соответственно. 
Как и в случае с флагом allowExplicit, объявление drivesKeyboard должно иметь вид 
drivesKeyboard = True; ( эквивалент - drivesKeyboard;)
или 
drivesKeyboard = False; ( эквивалент - !drivesKeyboard;)

index

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

Объявление "умолчания".

Это объявление является воспомогательным и позволяет определить какое-нибудь поле (инструкцию) для всех записей типа interpret или indicator. Естественно, обычно эти объявления помещаются в начале файла (или блока в файле). 
Они меют вид оператора присваивания, где в левой части указывается конструкция типа "поля структуры" в языке C. 
Например,
indicator.allowExplicit = False;
что означает - во всех дальнейших описаниях индикаторов (indicator) подразумевается "allowExplicit = False;", если конечно, эта инструкция не указана явно. 
Первым словом в левой части (то, что до точки) должно быть 
  • interpret - "умолчания" для описания "интерпретаций";
  • indicator - "умолчания" для описания индикаторов;
  • название "действия", встречающегося в описаниях interpret - задает "умолчание" для соответствующих полей "действия", которое может встретиться в дальнейших описаниях "интерпретаций".
  • Файл типа xkb_symbols.

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

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

    Надо заметить, что разные клавиши могут иметь разное количество групп, и разные группы одной клавиши могут иметь разное количество уровней.

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

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

    Итак. С каждым скан-кодом связаны

    • тип клавиши - типы описываются в файлах xkb_types и определяют зависимость уровня от состояния модификаторов. Заметьте, что тип клавиши может быть свой в каждой группе. Но если все группы для данного скан-кода имеют один и тот же тип, то в описании клавиши можно указать его один раз, не "расписывая" по всем группам.
    • "метод выравнивания" номера группы - напомню, что некоторые клавши могут иметь меньшее количество групп, чем все остальные. Поэтому, при нажатии такой клавиши может оказаться, что номер группы в "состоянии клавиатуры" выходит за границы, допустимые для данной клавиши. В этом случае он "выравнивается" до приемлимого значения. "Методы выравнивания" для отдельных клавиш такие же, как и глобальные (см. "Внутренности...":Метод Выравнивания)
    • автоповтор (autorepeat) - логический "флаг", который определяет - нужен ли автоповтор для данной клавиши.
    • "поведение" клавиши (behavior) - набор флагов и дополнительный аргумент, которые определяют...
      • "залипание" (locking) - если клавиша "залипающая", то при первом нажатии/отжатии выдается только сообщение о нажатии клавиши, а при повторном нажатии/отжатии - только сообщение об отжатии клавиши.
      • "радио-группа" - клавиша принадлежит к радио-группе клавиши, дополнительный аргумент определяет номер этой радио-группы. Напомню, что клавши одной радио-группы являются взаимозависимыми. То есть, при нажатии одной из клавиш группы, она "залипает", а остальные клавиши этой группы "отжимаются".
      • допускается "отжатие всех" (allow none) - имеет смысл для клавиш радио-группы. если этот флаг установлен, то повторное нажатие на клавшу - члена радио-группы, она "отжимается". При этом все члены группы могут находиться в отжатом состоянии. Если же этот флаг не стоит, то для отжатия клавиши надо нажать любую другую из той же группы. При этом в группе одна из клавиш остается нажатой.
      • перекрытие 1 - указывает, что клавиша относится к группе "перекрывающихся" клавиш (overlay). Если в состоянии клавиатуры установлен "управляющий флаг" Overlay1, то эта клавиша должна "отослать" XKB к другому скан-коду, который задан дополнительным аргументом.
      • перекрытие 2 - то же самое, что и предыдущий, только эти клавиши зависят от "управляющего флага" Overlay2.
      • permanent - может комбинироваться с другими флагами и означает, что соответствующая функция выполняется "железом" клавиатуры и нет необходимости эмулировать ее в XKB программно.
    • виртуальный модификатор (или несколько модификаторов) - этот модификатор может использоваться в качестве аргумента для "действия", если с клавишей связаны какие-нибудь "действия". Надо заметить, что, как правило, виртуальные модификатооры "назначаются" не в файлах xkb_symbols, а, как и "действия", в файлах xkb_compat.
    • "набор исключений" - запрещает выполнении "интепретаций" - изменения привязки "действий" при изменении привязки символов к скан-кодам. Можно запретить выполнение всех действий "интерпретации" для данной клавиши или только отдельных ее шагов - перенос виртуального модификатора, перенос "автоповтора", перенос "залипания".
    • и, наконец, в отдельной таблице может быть задана "привязка" реальных модификаторов к скан-кодам. Если с клавишей связан реальный модификатор, то, при нажатии клавиши, автоматически меняется состояние соответствующего модификатора в наборе "традиционных модификаторов", который эмулируется XKB для старых клиентских программ, "не знающих об XKB". Кроме того, "привязка" реальных модификаторов может использоваться при выполнении "интерпретаций" (interpretation).

    Объявления в файле xkb_symbols.

    В файлах этого типа могут встретиться

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

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

    Имеет вид

    'virtual_vodifiers' список_модификаторов ';'
    

    Надо заметить, что обычно ни действия, ни связанные с клавишей виртуальные модификаторы, не "привязываются" непосредственно к скан-кодам. Как правило, они описываются в файле xkb_compat, как часть "интерпретаций". Поэтому, это обявление, обычно, в файлах xkb_symbols не встречается.

    Объявление имени группы.

    Задает символическое имя для группы. Это имя может потом использоваться прикладными программами, которые рисуют изображение клавиатуры или показывают "состояние клавиатуры". Для самого XKB эти имена значаения не имеют.

    Это объявление имеет вид

    'name[' название_группы ']=' имя_группы  ';'
    
    Например,
    name[Group1] = "English" ;
    name[Group2] = "Russian" ;
    

    Описание клавиши.

    Это основное обявление в файлах этого типа. Именно оно описывает таблицу символов (и, если надо, "действий") связанных со скан-кодом.

    Имеет вид

    'key' имя_скан-кода '{' описания  '};'
    
    Напомню, что "имя_скан-кода" описывается в файлах типа xkb_keycodes и представляет собой произвольную строчку символов (но длиной не более четырех), ограниченную "угловыми скобками".
    Например,
    key  {...};
    

    "Описания" внутри фигурных скобок разделяются запятой. Обратите внимание, что именно "запятой", а не "точкой с запятой", как это делается в файлах других типов.

    Итак, внутри скобок могут быть строчки типа

    • type = ..., или type[...] = ...,
    • locks = ..., (синоним - locking)
    • repeat = ..., (синонимы - repeats, repeating)
    • groupswrap, или warpgroups,
    • groupsclanp, или clampgroups,
    • groupsredirect = ..., или redirectgroups = ...,
    • radiogroup = ...,
    • allownone = ...,
    • overlay1 = ..., или overlay2 = ...,
    • permanent...
    • vmods = ..., (синонимы - virtualmods, virtualmodifiers)
    • symbols[...] = ...,
    • actions[...] = ...,
    • просто [...]

    type

    Определяет тип клавиши. Справа от присваивания должно стоять название одного из типов, определенных в файле xkb_types.

    Обратите внимание, поскольку разные группы могут иметь разные типы (напомню, что тип определяет количество уровней в группе), то это описание в общем случае должно иметь вид

    type[ номер_группы ] = название_типа,
    
    например,
    type[ Group1 ] = "ONE_LEVEL",
    type[ Group2 ] = "ALPHABETIC",
    

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

    type = "ALPHABETIC",
    

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

    locks

    Логический флаг, который указывает на то, что клавиша должна быть "залипающей".

    Справа от присваивания могут стоять слова - true, yes, on ("поднять" флаг) или - false, no, off ("сбросить" флаг). Кроме того, там же может встретиться слово permanent. В этом случае подразумевается, что клавиша "залипающая", но ее "залипание" делается "железом" клавиатуры (в общем-то, это означает, что самому XKB об этой клавише заботиться не надо).

    По умолчанию все клавише не "залипающие".

    repeat

    Логический флаг, который определяет - нужен ли "автоповтор" для данной клавиши. Так же, как и для флага locks, справа от присваивания могут быть слова - true, yes, on (нужен автоповтор) или - false, no, off (автоповтор не нужен).

    Кроме того, там же может стоять слово default. Дело в том, что автоповтор, обычно, выполняет само "железо" клавиатуры. Поэтому, XKB не надо заботиться о повторении нажатия клавши. Чаще всего, ему приходится наоборот - "подавлять" автоповтор для некоторых клавиш. Так вот, значение "default" означает, что автоповтор надо "оставить на совести" "железа" и не пытаться что-либо менять.

    По умолчанию большинство клавиш отрабатывают автоповтор и значения repeat для них - default. А для клавиш-модификаторов - Control, Shift, Alt, CapsLock, NumLock и т.п., автоповтор подавляется, и repeat для них - false.

    groupswrap, groupsclanp, groupsredirect

    Определяют "метод выравнивания" номера группы (подробности см. в "Внутренности":Метод выравнивания). Естественно, имеет смысл в описании клавиши указывать только один из них.

    Объявления groupswrap и groupsclamp являются просто логическими переменными. Поэтому они задаются либо в виде присваивания, где в правой части могут быть только слова True или False, либо в виде
    groupswrap, - подразумевается "= True"
    или
    !groupswrap, - подразумевается "= False"

    А вот метод groupsredirect подразумевает дополнительный аргумент - "куда redirect". Поэтому всегда имеет вид присваивания, где в правой части должен стоять номер группы. Например,

    groupsredirect = 1,
    
    По умолчанию для всех клавиш метод выравнивания - Wrap.

    radiogroup и allownone

    Означает, что данная клавиша является членом радио-группы. Справа от знака присваивания должен быть номер группы.

    Номер группы может быть произвольный, в пределах 2-128 (обратите внимание, что нельзя сделать радио-группу номер 1, хотя это скорее всего "баг" в реализации XKB).

    Allownone устанавливает соответствующий флаг для этой радио-группы и является просто логической переменной.

    По умолчанию никаких радио-групп нет.

    overlay1 или overlay2

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

    overlay1 = ,
    
    По умолчанию никаих "групп перекрытий" нет.

    permanent...

    Это не отдельное слово, а префикс, который может соединяться со словами radiogroup, overlay1, overlay2. Например,

    permanentradiogroup = ...,
    permanentoverlay1 = ...,
    permanentoverlay2 = ...,
    

    Означает, что данная функция и так отрабатывается "железом" и XKB не надо об этом заботиться.

    vmods

    Задает список виртуальных модификаторов, связанных с этой клавишей. Справа от знака присваивания должно быть название модификатора (или нескольких модификаторов через знак '+').

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

    symbols

    Основная часть описания. Задает набор символов для клавиши. Одно такое объявление задает набор символов для одной группы. Поэтому, в левой части, в квадратных скобках указывается название группы, а в правой части, опять же в квадратных скобках - список символов для всех уровней этой группы (через запятую).
    Например,

    symbols[Group1] = [   semicolon, colon       ],
    symbols[Group1] = [Cyrillic_zhe, Cyrillic_ZHE],
    
    В качестве "символов" могут быть числовые значения кодов (десятичные, восьмеричные, шестнадцатеричные) или специальные "названия символов".

    Названия символов можно найти в файле X11R6/include/X11/keysymdefs.h. Только там они еще имеют префикс "XK_". То есть, если в это файле есть, например, определения

    #define XK_Escape 0xFF1B
    #define XK_Delete 0xFFFF
    ....
    
    это означает, что в файле типа xkb_symbols можно использовать слова Escape и Delete в качестве "названий символов".

    Надо заметить, что если в качестве символа указаны числа 0 - 9, то они интерпретируются как коды символов '0' - '9', а не как числовой код символа.

    Если для какого-то уровня в группе символ не нужен (не определен), можно использовать специальное "название символа" - NoSymbol.

    actions

    Аналогично предыдущему объявлению, только задает не список символов, а список "действий" для данной клавиши. Имеет такой же вид как объявление symbols, только вместо "имен символов" должны быть описания "действий". Немного подробнее об этих описаниях смотри "Описание действий".

    Здесь замечу только, что если какой-то уровень не имеет соответствующего "действия", можно использовать специальное название - NoAction().

    просто [...]

    Чаще всего, описание клавиши состоит из списков символов, заключенных в квадратные скобки без всякого указания типа - "symbols[...] =". Поскольку обычно для клавиши задается только набор символов, можно использовать сокращенную форму описания.
    Например, описание

    key  { [   3,      numbersign ], [  apostrophe,  3 ] };
    
    полностью эквивалентно описанию
    key  {
       symbols[Group1]= [               3,      numbersign ],
       symbols[Group2]= [      apostrophe,               3 ]
    };
    

    То есть, первая пара квадратных скобок (с неким содержимым внутри) интерпретируется как описание symbols для первой группы, втора пара скобок - как описание symbols для второй группы и т.д.

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

    • В каждом описании клавши явно указывать группу:
        key  {
           symbols[Group2]= [      apostrophe,               3 ]
        };
        
    • Или для пропущенной группы использовать "пустые скобки":
        key  { [], [      apostrophe,               3 ] };
        

    "Набор исключений".

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

    Заметьте, что в описании клавиши нет явных инструкций для задания "набора исключений". Но этот набор все-таки создается в некоторых случаях

    • если в описании клавши явно указан набор "действий" (инструкция actions), то устанавливается запрет "выполнения интерпретации" для этой клавиши;
    • если задан явно автоповтор (инструкция repeat) - запрещается "изменение автоповтора";
    • если задан явно флаг "залипания" или радио-группа (инструкции locks и radiogroup) - запрещается "изменение залипания";
    • и, наконец, если указан явно список виртуальных модификаторов (инструкция vmod), то устанавливается "запрет изменения" набора модификаторов.

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

    Это объявление заполняет внутреннюю табицу XKB - modmap, которая "привязывает" реальные модификаторы к клавишам (скан-кодам). Напомню, что эти модификаторы будут автоматически устанавливаться/сбрасываться, при нажатии/отпускании клавиши, в "эмулируемом наборе модификаторов".

    Объявление имеет вид

    'modifier_map' имя_модификатора '{' список_клавиш '};'
    
    Вместо слова "modifier_map" могут использоваться синонимы - modmap или mod_map.

    "Имя_модификатора" должно быть названием одного из реальных модификаторов - Shift, Lock, Control, Mod1, Mod2, Mod3, Mod4, Mod5.

    А вот "список_клавиш" может состоять из названий скан-кодов (через запятую), например,

    modifier_map Control { ,  };
    
    или из названий символов, например,
    modifier_map Mod1 { Alt_L, Alt_R };
    

    Во втором случае, XKB (точнее - xkbcomp) должен найти скан-коды, к которым "привязаны" эти символы и занести в modmap эти скан-коды.

    Обратите внимание, один и тот же модификатор может быть "привязан" ко многим скан-кодам, но не наоборот - разные модификаторы к одному скан-коду. Это означает, что название скан-кода может появиться в определениях modmap только один раз. Это же ограниичение действует, если клавиши предствлены не скан-кодами, а символами.

    Однако, как ни странно, xkbcomp не проверяет ситуацию, когда одна и та же клавиша представлена один раз скан-кодом, а другой - символом, или разными символами "привязанными" к одному скан-коду. В этом случае может получиться ситуация, когда к одному скан-коду "привязаны" несколько реальных модификаторов.

    Объявление "умолчаний".

    Это объявление задает значение "по умолчанию" для некоторых аттрибутов клавиш и выглядит как присвоение значения "полю структуры" в языке C.
    Например,

    key.repeat = no;
    

    При этом, в левой части присваивания первое слово (до точки) должно быть слово "key", а второе - любое из допустимых в описании клавиши (type, locks, radiogroup и т.п.).

    Естественно, это "умолчание" будет действовать, пока в тексте не встретится другое объявление для того же аттрибута.

    Кроме того, объявление "умолчаний" может спользоваться для "умолчаний" в описании "действий" (подробнее см. "Описание действий"). В этом случае первое слово будет названием "действия", например,

    SetMods.clearLocks = True;
    

    И, наконец, к объявлениям "умолчания" можно отнести инструкцию, которая устанавливает флаг "допускается отжатие всех" (allownone) для радио-групп.

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

    allownone = 10;
    
    означает, что для радио-группы 10 устанавливается соответствующий флаг.