Если ваша клавиатура размечена под латиницу или кириллицу, а вам приходится набирать тексты на другом языке, особенно, используя сложные, неалфавитные письменности, то данная заметка о системах ввода в Linux (упрощенно "клавиатурных раскладках") может вас заинтересовать.
Заранее прошу прощение за нечёткую терминологию и не претендую на исчерпывающее техническое описание. Основная задача статьи — описание возможностей, а не реализация.
Методы ввода
Основным методом ввода символов (input method, IM) в Linux является XKB, он установлен по умолчанию и активируется сразу после установки операционной системы. XKB предназначен для работы с алфавитными письменностями, и не может обслуживать комплексные письменности типа китайских иероглифов или силлабариев Индии и Африки. Систему можно настроить на работу с не более чем 4 раскладками. Последнее ограничение можно обойти, повесив на горячие клавиши вызов команды с нужной комбинацией параметров для каждого языка.
Если требуется большая гибкость, то следует перейти к фреймворкам (input method framework). Основные представители подобных систем в Linux: IBus, SCIM, Fcitx. Сам по себе фреймворк текст вводить не умеет, а различные письменности должны подключаться в виде плагинов (engines). Из опыта использования IBus и Fcitx могу сказать, что обе системы поддерживают примерно равное количество плагинов. Зачастую, это могут быть практически одни и те же плагины. Например, метод ввода Pinyin для китайского языка реализован в виде самостоятельной библиотеки libpinyin и при подключении через IBus или Fcitx предоставляет идентичные возможности.
Можно считать, что за последние 6-7 лет разница между фреймворками нивелировалась, хотя какие-то особенности могут проявляться. Далее я перечислю основные плагины IBus, как более знакомой мне системы.
Во-первых, IBus способен прозрачно использовать xkb и все его возможности. Единственная проблема в том, что IBus не умеет динамически генерировать конфигурации XKB. Наиболее популярные из них заранее прописаны в файле /usr/share/ibus/component/simple.xml
, который можно изменять и дополнять по необходимости. (При обновлении IBus файл будет заменён на стандартный.)
Например, русская раскладка описана следующим образом:
<engine>
<name>xkb:ru::rus</name>
<language>ru</language>
<license>GPL</license>
<author>Peng Huang <shawn.p.huang@gmail.com></author>
<layout>ru</layout>
<longname>Russian</longname>
<description>Russian</description>
<icon>ibus-keyboard</icon>
<rank>99</rank>
</engine>
В дополнение к layout
можно указать layout_variant
, остальные параметры setxkbmap
недоступны, в том числе и известная типографская раскладка Ильи Бирмана, которая задаётся в xkb через аргумент misc:typo
. Чтобы обойти это ограничение или просто создать раскладку под свои задачи, её нужно полностью описать. Для этого, в папке /usr/share/X11/xkb/symbols
нужно создать файл custom
(если дополнять существующие файлы, то при обновлении системы они будут затёрты) и задать конфигурацию раскладки. Например, русская с дополнениями Ильи Бирмана:
partial alphanumeric_keys
xkb_symbols "ru-typo" {
include "ru(winkeys)"
include "typo(base)"
include "level3(ralt_switch)"
// 1th keyboard row
key <TLDE> { [ NoSymbol, NoSymbol, U0301, NoSymbol ] }; // "~"
};
Где строки include
собирают конфигурацию из готовых шаблонов. Соответственно, из файла "ru" берётся вариант русской раскладки "winkeys". Потом дополняется раскладкой "base" из файла "typo" и задаётся переключатель третьего слоя AltGr (см. файл "level3"), что аналогично команде:
setxkbmap -layout ru -variant winkeys -option lv3:ralt_switch,misc:typo
При желании, можно внести собственные изменения. В приведённом выше примере знак ударения "U+0301" (Combining Acute Accent) вынесен на сочетание AltGr+~. Позиции, в которых указано NoSymbol
, используют определения из предыдущих шаблонов: "ё" и "Ё" из "winkeys", "≈" из "typo":
key <TLDE> { [ Cyrillic_io, Cyrillic_IO, NoSymbol, NoSymbol ] }; // winkeys
key <TLDE> { [ NoSymbol, NoSymbol, NoSymbol, approxeq ] }; // typo
key <TLDE> { [ NoSymbol, NoSymbol, U0301, NoSymbol ] }; // custom
Далее, созданную раскладку нужно внести в файл /usr/share/ibus/component/simple.xml
в следующем виде:
<engine>
<name>xkb:ru:typo:rus</name>
<language>ru</language>
<layout>custom,us</layout>
<layout_variant>ru-typo,</layout_variant>
<longname>Russian (with Typo)</longname>
<description>Russian (with Typo)</description>
<icon>ibus-keyboard</icon>
<rank>1</rank>
</engine>
Где custom
— имя файла из папки /usr/share/X11/xkb/symbols
, а ru-typo
указывает на содержащуюся в нём раскладку. Дополнительная раскладка us
указана, чтобы корректно работали горячие клавиши (Ctrl+С, Ctrl+V и т.п.). После перезагрузки IBus (ibus restart
) в настройках появится новая раскладка "Russian (with Typo)".
Второй метод ввода — m17n. Это довольно богатая библиотека клавиатурных раскладок для разнообразных письменностей. IBus имеет собственный схожий метод ввода ibus-table, который описан как обладающий "чуть меньшими возможностями". Мне приходилось использовать последний для создания раскладки с однозначным соответствием между латинскими буквами и буквами требуемого алфавита без задействования сложно логики, поэтому я не могу судить, какая из двух систем более функциональная и выразительная — описание раскладки в формате m17n или ibus-table. Метод ibus-table включает в себя любопытную раскладку "LaTeX" для ввода символов в соответствующей нотации: "\Delta
" для "Δ", "\ge
" для "≥" и т.д.
Следующий из универсальных методов ввода — KMFL. Это Linuх-версия метода ввода Keyman для Windows. Не очень распространённый IM, который поддерживает самые редкие письменности. В отличие от оригинального Keyman, с заявленной возможностью печатать на более чем 1000 письменностях, KMFL не настолько развит, но тоже может быть полезен. Формат описания раскладок текстовый, существует программа для их создания под Ms Windows. Я использую раскладку EuroLatin, в которой текст "2//3
" преобразуется в дробь "⅔", а последовательность "-a
" превращается в макрон "ā". Напоминает Compose key в xkb, но не требует отдельного модификатора — KMFL сам распознает последовательности во время набора.
Остальные методы ввода специализируются на отдельных письменностях: "ibus-libpinyin" для китайского языка, "ibus-unikey" для вьетнамского и т.д. Настройки этих плагинов также находятся в /usr/share/ibus/component/
. В соответствующих файлах может потребоваться задать базовую раскладку клавиатуры, иначе при переключении с нелатинской раскладки они будут нерабочими. Например, в libpinyin.xml
нужно найти параметр "layout" и вписать "us" для клавиатуры QWERTY или "fr" для AZERTY и т.п.
<layout>us</layout>
Переключение раскладок
Большую часть времени я работаю с языковыми парами: русский-английский, китайский-испанский и т.п. Поэтому предпочитаю иметь одну горячую клавишу для переключения между двумя последними раскладками (CapsLock), а сами раскладки переключаются по отдельным горячим клавишам (Win + 1…9 на цифровом блоке). Таким образом, сначала я задаю рабочие раскладки, Win+1 (en) и Win+2 (ru), а далее переключаюсь между ними по CapsLock (en <-> ru).
В IBus можно задать две горячих клавиши: одна для циклического переключения по списку раскладок, вторая для последних двух раскладок. Так же можно выбирать нужную раскладку через консоль и, соответственно, назначить скрипт на горячую клавишу.
Замечу, что переназначить CapsLock с помощью xmodmap
не получится, так как IBus сбрасывает подобные настройки. Поэтому я предпочитаю через udev
глобально переопределять CapsLock как F14 (файл /etc/udev/hwdb.d/90-custom-keyboard.hwdb
):
evdev:input:b0003v1A2Cp0E24* # my keyboard id
KEYBOARD_KEY_70039=f14 # bind capslock to f14
И использовать уже F14 как горячую клавишу в IBus. По моему опыту это обеспечивает наиболее стабильную конфигурацию.
Подробнее о настройке udev см. в конце статьи.
Виртуальная клавиатура
Промышленно выпускаются клавиатуры, размеченные под определённую письменность, лишь для языков с большим количеством пользователей — например, для русского (ЙЦУКЕН). Ни в Армении, ни в Грузии вы не сможете купить клавиатуру с клавишами, подписанными буквами национальных алфавитов. Аналогично, в Казахстане и Узбекистане используют русско-английские клавиатуры и вынуждены учить, где располагаются буквы, не входящие в стандартную латиницу или кириллицу.
Если вы осваиваете новую раскладку, советую воспользоваться виртуальной клавиатурой. Мне нравитcя Onboard, потому что она самостоятельно подстраивается под активную раскладку и обновляется при переключении на другую. Но это работает только с xkb (также при использовании xkb через IBus).
Onboard очень удобна для тестирования раскладок xkb и позволяет посмотреть назначенные символы на всех слоях (AltGr и т.п.).
Заключение
Не все программы корректно поддерживают языковые фреймворки. В частности, Sublime Text 3 работает лишь со SCIM, а используя IBus, независимо от выбранной раскладки, будет печатать исключительно латинские буквы.
Я довольно давно использую IBus, а другие системы знаю очень поверхностно. По отзывам в интернете, Fctix описывается как более функциональный и лучше адаптированный для ввода китайского текста. В любом случае, при работе с китайскими текстами IBus меня полностью устраивает и различия должны быть непринципиальными. Последний раз, когда мне приходилось использовать Fctix (2 года назад), этот фреймворк не позволял переключать раскладки, если курсор не находится в текстовом поле. Надеюсь, к настоящему моменту эту недоработку исправили.
Ещё одно подспорье для работы с разнообразными письменностями — силиконовые накладки на клавиатуру. Китайские интернет-маркеты предлагают накладки (保护膜 или 键盘膜) для Apple Magic Keyboard под самые различные письменности. Пример некитайского дистрибьютора. Но учтите, что выпускалось три поколения Apple Magic (и каждая в модификациях для США, Европы и Японии), а китайские реплики отличаются линейными размерами и расположением клавиш. Временами, я сожалению, что не существует единого стандарта на компьютерные клавиатуры.
Цифровой код нажатой клавиши несколько раз меняет своё значение.
- scancode: При нажатии клавиши клавиатура (или драйвер?) отправляет в ядро Linux scancode.
- keycode: Далее в ядре scancode преобразуется в keycode (подсистема Linux input API). Управлять преобразованием можно с помощью программ udev, keyfuzz, setkeycodes.
- keysym: X Window System получает из ядра keycode и транслирует его в keysym — это уже конечный символ, который клиентская программа получит в качестве ввода. Настройка преобразования осуществляется через XKB или xmodmap (deprecated).
Из приведённой последовательности видно, что переназначение клавиш на этапе scancode > keycode предпочтительнее, так как это не вызывает пересечений с KXB.
Трансляция scancode в keycode производится для каждого устройства ввода независимо, поэтому сперва требуется узнать уникальный идентификатор клавиатуры (на самом деле evdev работает также с большим классом периферийных устройств, имеющих кнопки — от мышек до принтеров и веб-камер). Пользователи Arch Linux могут воспользоваться следующим скриптом (для других дистрибутивов, возможно, потребуется корректировка путей):
#!/bin/sh
for DEVICE in /dev/input/by-id/*; do
echo $(basename $DEVICE)
DEVID=$(basename $(readlink $DEVICE))
printf "evdev:input:b%sv%sp%se%s*\n\n" \
`cat /sys/class/input/$DEVID/device/id/bustype` \
`cat /sys/class/input/$DEVID/device/id/vendor` \
`cat /sys/class/input/$DEVID/device/id/product` \
`cat /sys/class/input/$DEVID/device/id/version`
done
Одно и то же устройство может быть представлено в системе в нескольких экземплярах под разными именами, но идентификатор будет одинаковым. Например, моя клавиатура определяется как два устройства:
usb-SEM_USB_Keyboard-event-if01
evdev:input:b0003v1a2cp0e24e0110*
usb-SEM_USB_Keyboard-event-kbd
evdev:input:b0003v1a2cp0e24e0110*
Примечание: идентификатор можно сокращать (например, до b0003v1a2cp0e24*
), что бывает полезно при создании единых правил для серии однотипных моделей. Звёздочка “*” здесь играет роль символа подстановки (wildcard).
Теперь нужно создать файл 90-custom-keyboard.hwdb
в /etc/udev/hwdb.d/
со следующим содержанием (образцы см. в /usr/lib/udev/hwdb.d/60-keyboard.hwdb
):
evdev:input:b0003v5c0ap0003e0110* # ваш идентификатор
KEYBOARD_KEY_70039=f14 # переназначение клавиши
Строка KEYBOARD_KEY начинается с пробела, это важно. Обновите конфигурацию:
sudo udevadm hwdb --update && udevadm trigger
В последующем, при перезагрузке или переподключении устройства конфигурация будет обновляться автоматически.
Переназначение клавиш задаётся парами KEYBOARD_KEY_<scancode>=<keycode>
. Значения keycode (обязательно в нижнем регистре) находятся в /usr/include/linux/input-event-codes.h
(для Ubuntu 14.04 в /usr/include/linux/input.h
).
Получить scancode можно с помощью программы evtest. Сперва, нужно определиться с номером eventXX, для этого запустите команду и найдите свою клавиатуру:
> ls -l /dev/input/by-id/
…
usb-SEM_USB_Keyboard-event-if01 -> ../event11
usb-SEM_USB_Keyboard-event-kbd -> ../event10
…
Выбираем "Keyboard-event-kbd" и узнаем нужный номер (в данном примере — 10). Теперь можно обратиться к evtest:
> sudo evtest /dev/input/event10
…
Event: time 1531562530.720076, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70039
…
При нажатии клавиши "CapsLock", получается код "70039" — это и есть искомый scancode.