Как сделать кастомную раскладку клавиатуры в Linux

Зачем?

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

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

В какой-то момент я подумал, что можно сделать свою раскладку, взяв за основу английскую и добавив сербские символы через правый Alt. Например, RightAlt + s = š, RightAlt + d = đ и т.д.

Я ожидал что есть какой-то GUI в котором можно потыкать кнопки и получить нужную раскладку. Но такого я не нашел. Все делается через редактирование файлов. Плюс я не нашел понятного туториала. Что-то конечно я смог найти, но в некоторых местах приходилось догадываться и действовать методом тыка.

Теория

Все раскладки лежат в папке /usr/share/X11/xkb/symbols/, например все русские раскладки находятся в файле ru, а английские в файлах us и gb.

Откроем файл ru, чтобы на примере понять что там находится. В начале фала имеются следующие строки:

// Windows layout
default partial alphanumeric_keys
xkb_symbols "winkeys" {

    include "ru(common)"
    name[Group1]= "Russian";

    key <AE03>  {[          3,  numerosign  ]};
    key <AE04>  {[          4,   semicolon  ]};
    key <AE05>  {[          5,     percent  ]};
    key <AE06>  {[          6,       colon  ]};
    key <AE07>  {[          7,    question  ]};
    key <AE08>  {[          8,    asterisk,      U20BD  ]}; // ruble

    key <AB10>  {[     period,       comma  ]};
    key <BKSL>  {[  backslash,       slash  ]};
};

Это одна из русских раскладок, а ниже находятся другие,  вот начало следующей.

hidden partial alphanumeric_keys
xkb_symbols "common" {

    key <AE01>  {[          1,      exclam  ]};
    key <AE02>  {[          2,    quotedbl  ]};
    key <AE03>  {[          3,  numbersign  ]};
    key <AE04>  {[          4,    asterisk  ]};
    key <AE05>  {[          5,       colon  ]};
    key <AE06>  {[          6,       comma  ]};
...

Методом дедукции я выяснил, что строка include "ru(common)" означает, что раскладка "winkeys", а точнее "ru(winkeys)", наследуется от раскладки "ru(common)". ru в данном случае это название файла, а "common" это то что определено в строке xkb_symbols "common" {

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

Далее идет name[Group1]= "Russian"; - это то как расклада будет отображаться в интерфейсе выбора раскладок.

Далее строчка

 key <AE01>  {[          1,      exclam  ]};

Это значит что на клавишу AE01 мы биндим цифру 1, а при нажатом шифте - exclam - т.е. восклицательный знак. Совершенно не понятно, что такое AE01. А это то, как клавиша физически расположена на клавиатуре.

"А" означает что-то мы ищем клавишу на цифро-буквенном блоке клавиатуры. Другие значения могут быть "KP" - для блока с цифрами and "FK" для функциональных клавиш (видимо F1-F12, но я не проверял).

E означает - это ряд при счете снизу. Ряд с пробелом - это А, далее B, C, D, E - т.е. пятый ряд снизу.

01 означает, что эта первая клавиша слева, не считая табов, капслоков, шифтов и т.п.

Более подробно можно почитать вот тут.

Ок, а как добавить правый Alt?

Для этого нужно добавить еще два столбца.

Например вот, как это выглядит в одной из раскладок:

    key <AD01> { [         q,          Q,    adiaeresis,       Adiaeresis ] };

Тут на клавишу Q добавлены дополнительные слои. Первый слой - просто нажатие, второй - через Shift, третий - через правый Alt и четвертый - правый Alt + Shift. Однако само по себе оно не заработает. Методом наблюдения за другими раскладками, я выяснил что альтовая магия добавляется строкой include "level3(ralt_switch)".

Еще осталось разобрать строчку default partial alphanumeric_keys, но я сам с этим не стал разбираться, т.к. свою задачу я решил.

Но это еще не все что нужно знать. Латинские символы добавляются просто, но тот же восклицательный знак добавлен специальным кодом "exclam". Откуда взять этот код?

Получить код нужного символа можно с помощью следующей команды, предварительно установив xev через apt, pacman, dnf или что там у вас.

xev | awk -F'[ )]+' '/^KeyPress/ { a[NR+2] } NR in a { printf "%-3s %s\n", $5, $8 }'

Например, запустив эту команду и нажав "š" - получаем следующий вывод:

39  scaron

Это значит, что код символа š - scaron.

Практика

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

Переходим в папку /usr/share/X11/xkb/symbols/ и создаем файл с названием rs_latin_custom, с таким содержимым:

default partial alphanumeric_keys modifier_keys
xkb_symbols "rs_latin_custom" {

    include "us(basic)"
    name[Group1]= "Serbian (Latin, AltGr)";

    // Serbian
    key <AC02>  {[   s,  S, scaron, Scaron      ]};
    key <AC03>  {[   d,  D, dstroke, Dstroke      ]};
    key <AB01>  {[   z,  Z, zcaron, Zcaron      ]};
    key <AB02>  {[   x,  X, ccaron, Ccaron     ]};
    key <AB03>  {[   c,  C, cacute, Cacute      ]};

    include "level3(ralt_switch)"
};

Название в строке xkb_symbols "rs_latin_custom" можно выбрать любое, оно может не совпадать с названием файла.

Далее я понаследовался от стандартной английской раскладки "us(basic)" и добавил сербские символы на 3й слой и их заглавные варианты на 4й. Чтобы переключение слоев происходило через правый Alt - добавлена строка include "level3(ralt_switch)"

Получившаяся раскладка выглядит вот так:

Чтобы отобразить ее в GUI можно воспользоваться командами:

gkbd-keyboard-display -l "rs_latin_custom(rs_latin_custom)"

или

tecla "rs_latin_custom(rs_latin_custom)"

Но это еще не все. Чтобы раскладка появилась в списке раскладок, нужно отредактировать файл /usr/share/X11/xkb/rules/evdev.xml

Нужно открыть его, найти в нем закрывающий элемент

 </layoutList>

И добавить перед ним описание нашей раскладки:

    <layout>
      <configItem>
        <name>rs_latin_custom</name>
        <shortDescription>sr</shortDescription>
        <description>Serbian (Latin, AltGr)</description>
        <languageList>
          <iso639Id>eng</iso639Id>
          <iso639Id>srp</iso639Id>
        </languageList>
      </configItem>
      <variantList/>
    </layout>
  </layoutList>

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

После этого нужно перелогиниться в моем случае в Gnome, и можно будет выбрать новую раскладку.

Уменьшение количества раскладок

Дополнительно мне удалось уменьшить количество моих раскладок на одну. Вместо 5 их стало 4. На русской раскладке я добавил сербскую кириллицу и украинские символы.

Обо мне

Я программист, в свободное время изучаю иностранные языки. Мои языки ?? ?? ?? ?? ?? ?? ?? ??. Я веду телеграм канал Заметки полиглота, где я делюсь своими мыслями по поводу изучения языков.

@un1t
23.01.2024 18:38 UTC
Первоисточник

Комментарии

@alex_shpak
23.01.2024 14:44 UTC
+1

На достаточно свежих версиях Linux, кстати, файл evdev.xml менять не обязательно (изменения в нем могут потеряться при обновлении) - начиная с версии xkeyboard-config 2.33 свою раскладку можно сохранять в файле /usr/share/X11/xkb/symbols/custom

@un1t
23.01.2024 16:18 UTC
0

Про то что evdev.xml может слететь при обновлении я читал, но пока не сталкивался. Файл custom удобен, т.к. он уже прописан в evdev.xml по умолчанию. Но он позволяет сделать только одну раскладку, которая к тому же в переключалке будет отобаржаться странным значением - "custom". Мне нужно на данный момент две раскладки, так что этот вариант не подходит.

Может есть какая-то способ модифицировать файл evdev.xml автоматически?

25.01.2024 21:11 UTC
0
НЛО прилетело и опубликовало эту надпись здесь
12.02.2024 16:09 UTC
0

Вот и дождался. При обновлении слетели изменения в evdev.xml.

@NickDoom
23.01.2024 16:07 UTC
+1

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

Я смотрю в сторону dead keys, но они вроде требуют двойного нажатия, а не отпускания…

@Rigidus
23.01.2024 22:44 UTC
+1

Меня тоже очень интересует этот вопрос (аккордовая печать в Linux). Подпишусь здесь

@Cheater
24.01.2024 10:38 UTC
+1

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

key <AD01> { [ q, Q ], actions[Group1] = [SetMods(modifiers=LevelThree),NoAction() ] };
key <AC01> { [ a, A, ae, AE ], type[Group1] = "FOUR_LEVEL" };

(Не нашёл вашей буквы в хедерах X11, видимо не реализовано, взял похожую)

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

24.01.2024 21:05 UTC
0

Спасибо, а это покатит, если, допустим, у «D» должно быть 6 дополнительных значений в зависимости от того, какая из «ромашки» ERSFXC вместе с ней нажата? Ну, и плюс её родное седьмое значение, то есть сама D.

Или там только один-два уровня захардкодено?

25.01.2024 14:16 UTC
+1

В xkb не уверен что такое возможно, тк если делать это через модификаторы как в примере выше, то нужно 6 различных модификаторов, по одному на каждую префиксную клавишу ERSFXC. В X11 штатных модификаторов ровно 8 (Shift, Lock, Control, Mod1, Mod2, Mod3, Mod4, Mod5) и как минимум 4 из них заняты под реально нужные функции которые переназначать не следует. Можно пойти другим путём: Функциональность, которой вы хотите добиться, в терминологии XKB называется Compose Keys - замена одного предопределённого ввода на другой, ввод и вывод могут быть из нескольких символов. Именно через Compose в XKB делается ввод диакритики, æ, и т.д., можно вывести хоть "Hello world". Но если во вводе количество символов (не модификаторов) более одного, то все символы кроме последнего введённого должны являться т.н. "Dead keys" - клавишами, не вводящими никакого реального символа, тк в XKB нет такой вещи как дерево решений и стирание/изменение предыдущего ввода. Соответственно невозможно на чистом XKB сделать так, что просто в процессе ввода какого-то текста на латинице на 1м слое вводится секретная последовательность символов и она транслируется в æ.

Можно сделать клавиши ERSFXC "Dead keys" на другом слое и тогда описанное мной сработает - можно будет создать 6 Compose-последовательностей. Но на этот другой слой надо будет вначале переключиться для набора начального Dead key.

Вам судя по всему в высокоуровневые клавиатурные скриптеры наподобие Autohotkey (есть под Linux)

25.01.2024 17:43 UTC
0

Спасибо, значит, 4 из 8… тогда действительно лучше сразу «по-плохому» :)

@Cheater
23.01.2024 16:21 UTC
+1

пишут еще нужно поправить файл evdev.lst, но зачем это нужно я не знаю

Для совместимости с устаревшим кодом в ксорге, читающим .lst. Современным форматом конфига является evdev.xml
 

AltGt

AltGr
 

нужно отредактировать файл /usr/share/X11/xkb/rules/evdev.xml

Это не получится проделать на машине где вы не админ. Свои конфиги xkb можно хранить в домашней директории и загружать примерно как:

# конфиг в ~/.config/xkb/symbols/rs_latin_custom

setxkbmap -geometry "pc(pc104)"  -layout "rs_latin_custom(rs_latin_custom)" -print | xkbcomp -I/home/user/.config/xkb - "${DISPLAY%%.*}"

(Не представляю правда как это будет взаимодействовать с виджетом выбора языка в GUI)

@Johan_Palych
23.01.2024 20:16 UTC
+1

Просто почитать(X system or Wayland ):
https://wiki.debian.org/Keyboard
How to dynamically manage input source settings from the command line (modern strategy)
gsettings, dconf, or dconf-editor

@UncleAndy
24.01.2024 20:17 UTC
+1

Очень полезно! Спасибо большое! Иногда хочется написать что-то на сербском латиницей правильно, но опыт с подключением обычной сербской раскладки оказался неудачным. Попробую ваш вариант.