Таблица символов
Что же собой представляет таблица символов, связывающая символы со скан-кодами и состоянием модификаторов? Рассмотрим сначала "традиционную" таблицу символов, которая используется в 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.)
Итак. Первые четыре колонки в таблице соответствуют "состояниям" -
В терминах core protocol можно сказать, что состояние Mode_switch выбирает одну из двух групп (не надо путать их с XKB группами, о которых мы поговорим позднее), а состояние Shift - одну из двух колонок внутри группы.
Как вы скорее всего знаете, разные группы обычно используются для разных языков (алфавитов), а 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). Но... - Назначение некоторых клавиш (той же Enter) не меняется в разных алфавитах, поэтому для них не требуется деление таблицы на несколько отдельных групп.
- Даже в пределах одной группы (алфавита) разные клавиши могут иметь разное количество колонок. То есть, "ширина" таблицы меняется не только "от группы к группе" но и "от скан-кода к скан-коду". Поэтому удобнее описывать каждую отдельную группу для каждого отдельного скан-кода.
- И, наконец, с каждым скан-кодом связаны еще некоторые параметры (см. ниже ), которые не зависят от номера группы. Поэтому, если бы мы описывали один и тот же скан-код в разных таблицах-группах, эта информация могла бы оказаться противоречивой.
- Для каждого скан-кода (keycode) в XKB "раскладке" хранится несколько однострочных таблиц символов, которые называются "группами".
- Каждая такая таблица может делиться на несколько колонок - "уровней" (shift level)
- Какая из таблиц-строчек актуальна в данный момент, определяется текущим номером группы (или просто - group). Текущий номер группы хранится в X-сервере и сообщается приложению в событии о нажатии/отпускании клавиши вместе со скан-кодом и набором модификаторов.
- Выбор нужной колонки (shift level) определяется состоянием модификаторов.
- Разные keycode могут иметь разное количество групп.
- В разных группах даже одного и того же keycode может быть разное количество shift level.
Делить таблицу на группы удобнее. Во-первых, так легче провести границу между разными алфавитами (если, конечно, таковые используются в раскладке). Заметьте, что в некоторых случаях хотелось бы иметь не два разных алфавита, а больше. Причем раскладки для разных алфавитов могли бы составлять разные люди, независимо друг от друга
Во-вторых, чем больше модификаторов участвуют в выборе колонок, тем сложнее и запутаннее становятся соответствующие описания зависимостей.
Поэтому, авторы XKB использовали радикальный подход - в одной и той же раскладке может быть несколько (до четырех) отдельных таблиц. Вот эти таблицы и называются группами XKB (или просто groups).
Вообще-то, правильнее сказать не "несколько двумерных таблиц в одной раскладке", а - у каждого скан-кода (keycode) может быть до четырех "однострочных" таблиц - групп.
Потому, что ...
Итак.
36 | 1 | одна колонка | Enter | ||
38 | 1 | две колонки | a | A | |
2 | две колонки | Cyrillic_ef | Cyrillic_EF | ||
3 | две колонки | Greek_alpha | Greek_ALPHA | ||
21 | 1 | две колонки | + | = | |
2 | четыре колонки | + | = | \ | ; |
... |
Наконец, надо сказать, что групп может быть от одной до четырех, а уровней - до 64.