habrahabr

XKB: перенастроим клавиши под себя любимого

  • суббота, 10 мая 2014 г. в 03:10:34
http://habrahabr.ru/post/222285/

В один прекрасный день надоедает нажимать Shift, чтобы вывелся символ ~ вместо `.
Надоедает тянуться до Esc, при этом клавишей CapsLock пользуетесь РЕДКО.
Надоедает смещать кисть вниз и нажимать его слабым мизинчиком, либо, не дай бог, тянуться до него большим пальцем.
Надоедает лезть за PgUp, PgDn, Home и End, двигая руку каждый раз, чтобы всего лишь промотать страницу вниз.
Надоедает каждый раз, когда вы делаете опечатку, со злобой смотреть на клавиатуру в поисках кнопки Backspace.



Сегодня мы узнаем, как навсегда избавиться от этих мучений.

Зачем это всё?


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

Многие раскладки для печати (Dvorak, Colemak и т.п.) сильно улучшают расположение клавиш, ставя их ближе к тем местам, куда нужно меньше тянуться. Но при этом совершенно забывают о модификаторах, спец. символах и командных клавишах (Enter, Backspace, Tab, Esc, Delete). А мы подумаем о том, как улучшить существующее положение вещей.

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

Первые шаги калеки


Стандартную раскладку нужно модифицировать под себя. Сделать это можно многими способами. Не думаю, что кто-то здесь пользуется экзотическими ibus, Fcitx, SCIM или UIM, поэтому предположу, что у всех работает стандартный X Keyboard extension, XKB. Стоит заметить, что в грядущем на десктопе Wayland, XKB, скорее всего останется отвечать за клавиатуру, также как и в Xorg. Если вдруг тут есть смельчаки, которые уже работают с XWayland, поделитесь своими впечатлениями, работает ли описанное мной у вас. Про альтернативный Wayland Mir от Canonical ничего сказать не могу, кроме того, что вряд ли они возьмутся переписывать и подсистему взаимодействия с клавиатурой.

Первое, что приходит в голову — воспользоваться какими-то графическими утилитами. Если честно, то этот этап я пропустил, и сразу воспользовался xmodmap. Чуть ниже я расскажу, что не так с этим подходом и как делать правильно.

Xmodmap позволяет, например, поменять слоями ; и :, особенно это полезно тем, кто программирует на современном языке, который уже не требует обязательной точки с запятой в конце строки. Даже в JavaScript этого уже делать не нужно. И помогает вот такая простая команда:
$ xmodmap -e "keycode 47 = colon semicolon Cyrillic_zhe Cyrillic_ZHE"

Запускать её нужно из .xsession или .xinitrc. Последние два аргумента в кавычках помогут не потерять при обмене буквы ж и Ж.

А вот такая, например, поменяет местами ~ и `:
$ xmodmap -e "keycode 49 = asciitilde grave Cyrillic_io Cyrillic_IO"

Переключение раскладки


Часто ли вам приходится пользоваться Alt? Если вдруг нет, а мне, я заметил, приходится это делать только в богатых менюшками интерфейсах, типа Gimp или LibreOffice, то его можно использовать в качестве переключателя правый Alt, известный как AltGr:
$ setxkbmap -layout us,ru -option grp:toggle

Esc vs CapsLock


Многие, кто часто пользуются Vim, или используют vi сочетания в консоли, и кто мало ругается на форумах, предпочитают иметь Escape на клавише CapsLock:
 $ xmodmap -e "clear lock"
 $ xmodmap -e "keycode 0x42 = Escape"

То же самое можно сделать ещё немного проще:
  setxkbmap -option caps:escape

Или даже вот так, сохраняя CapsLock на месте старого Escape на случай переписки на повышенных тонах:
  setxkbmap -option caps:swapescape

Откуда эти загадочные параметры, мы с вами узнаем чуть позже.

Цветочки


Наверное, удивлю вас, если скажу, что то, что мы делали до этого было не совсем правильно. setxkbmap ещё ничего, а вот xmodmap появился ещё до XKB, и живёт только для совместимости. Мало того, он ничего не знает и о половине клавиш, синтаксис и принцип работы у него более, чем загадочен, он переводит keycode и keysym, а в некоторых случаях и обратно. Разбираться в этом нет никакого смысла, потому что он в какой-то момент отомрёт, и все ваши ухищрения нужно будет повторять, только уже с помощью другой утилиты, а вы расстроитесь и назло всем опять станете печатать двумя указательными пальцами.

Так вот, всё это работает до одного прекрасного момента, пока не начинаешь понимать, что нужных клавиш много, а пальцы, которые лежат на домашней строке (ASDF JKL;) до всех не дотягиваются.
Я, например, часто пользуюсь клавишей с обозначением Win, которая является модификатором Mod4. Расположена она на моей клавиатуре не слишком удобно, а именно между левыми Alt и Ctrl.

Правильный способ


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

Запомните, многие в интернете советуют модифицировать файлы, лежащие в /usr/share/X11/xkb/symbols, а именно us, pc и ru. Не делайте этого. Это файлы, действующие на всю систему сразу. На других пользователей (если вдруг у вас такие есть), и если вы там с чем-то накосячите, то набирать текст, даже логин и пароль, бкдшт труднее. Не стоит даже класть туда и модифицированные файлы, и ничего не нужно прописывать в evdev.xml.

Важно: если вы вдруг сделаете что-то не так, то перезагрузка X'ов вам поможет. Есть и более простой способ, можно запустить команду setxkbmap без параметров, и она сбросит почти все ваши настройки на раскладку по умолчанию.

Первым делом нам нужно узнать текущие настройки раскладки, сделать это нужно до всех манипуляций:
$ setxkbmap -layout us,ru -print

На выходе получим что-то вроде этого:
xkb_keymap {
  xkb_keycodes  { include "evdev+aliases(qwerty)" };
  xkb_types     { include "complete" };
  xkb_compat    { include "complete" };
  xkb_symbols   { include "pc+us+ru:2+inet(evdev)" };
  xkb_geometry  { include "pc(pc104)" };
};

Запишем всё это в файл, причем будем следовать указаниям XDG, и положим его в ~/.config/xkb/my.

В этом файле нас больше всего интересует строка xkb_symbols, остальное оставим без изменений. Развернём фигурные скобки, и поменяем эту строку на следующее:
xkb_keymap {
  xkb_keycodes  { include "evdev+aliases(qwerty)" };
  xkb_types     { include "complete" };
  xkb_compat    { include "complete" };
  xkb_geometry  { include "pc(pc104)" };

  xkb_symbols "my" {
    include "pc+us+ru:2+inet(evdev)"

    key <AC10> { [ colon, semicolon ] };
    key <TLDE> { [ asciitilde, grave ] };
  };
};

Ну, скрестим пальцы, и загрузим эту конфигурацию:
$ xkbcomp $HOME/.config/xkb/my $DISPLAY

Пробуем. Если при нажатии клавиши, на которой у вас нарисована буква Ж, печатается символ :, а не ;, а при нажатии на Ё печатается тильда ~, а с Shift'ом всё происходит наоборот, то мы на верном пути.

Стоит заметить, что тут же не нужно заморачиваться с Cyrillic_zhe Cyrillic_ZHE, всё работает и так.

Идём дальше. Что мы делали? Мы запускали setxkbmap -option с параметром. Давайте посмотрим, что он меняет.
$ setxkbmap -print | grep symbols
  xkb_symbols   { include "pc+us+ru:2+inet(evdev)" };
$ setxkbmap -option caps:escape
$ setxkbmap -print | grep symbols
  xkb_symbols   { include "pc+us+ru:2+inet(evdev)+capslock(escape)" };

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

Стоит заметить, что точка с запятой после include не нужна, в отличии от точки с запятой в других местах этого конфигурационного файла.
Если внимательно посмотреть, то приходит понимание, что вот эти два способа записи идентичны:
    include "pc+us+ru:2+inet(evdev)"
    include "capslock(escape)"

    include "pc+us+ru:2+inet(evdev)+capslock(escape)"

При этом первый куда более нагляден.

Что же это значит? Мы загружаем нашу раскладку, говорим, что у нас qwerty (xkb_keycodes), что у нас 104 клавиши (xkb_geometry), и переопределяем символы. При этом в разделе символов мы включаем целиком несколько конфигурационных файлов, pc, us, ru. Где они лежат, можно ли на них посмотреть? Естественно, все они лежат в /usr/share/X11/xkb/symbols. Посмотреть их полезно, особенно если вы соберётесь сделать что-то более масштабное, чем мы уже сделали.
Хорошо, а где лежат те файлы, которые определяют, что CapsLock и Escape нужно поменять местами? Да там же. Выглядит это примерно вот так:
partial hidden modifier_keys
xkb_symbols "swapescape" {
    key <CAPS> { [ Escape ] };
    key <ESC>  { [ Caps_Lock ] };
};

partial hidden modifier_keys
xkb_symbols "escape" {
    key <CAPS> { [ Escape ] };
};

Что такое partial? Это кусок раскладки, который можно включить в другую раскладку. В некоторых конфигурационных файлах щедрые авторы даже добавили комментарии. Но не во всех.

Почему мы просто не делаем свой partial, и не включаем его? К стыду своему готов признать, что пытался делать это по описаниям, но у меня не вышло.

Как это нужно делать в теории
В файл раскладки не нужно класть целиком xkb_keymap, достаточно только секцию xkb_symbols:

  xkb_symbols "my" {
    include "pc+us+ru:2+inet(evdev)"

    key <AC10> { [ colon, semicolon ] };
    key <TLDE> { [ asciitilde, grave ] };
  };


Загрузка должна идти с помощью команды:
setxkbmap -I$HOME/.config/xkb my -print | xkbcomp - $DISPLAY

Увы, вывод setxkbmap не меняется ни от каких параметров, кроме одного случая:
setxkbmap -I$HOME/.config/xkb -symbols my -print

Но, увы, в случае передачи этого вывода в xkbcomp, тот выдаёт ошибку.

Некоторые ещё советуют вместо $DISPLAY писать ${DISPLAY%%.*}

Ягодки


Не хочу просто Escape на CapsLock. Хочу чтобы Control тоже.
Как? Как такое возможно? Пришло время магии.

Сначала сделаем так, чтобы при нажатии на CapsLock получался LCTL, добавив вот это в секцию xkb_symbols:
    replace key <CAPS> { [ Control_L ] };
    replace key <LCTL> { [ Caps_Lock ] };

Вторая строчка нужна для того, чтобы избавиться от вредной привычки нажимать старый левый Ctrl. Можно чуть смягчить это:
    replace key <LCTL> { [ VoidSymbol ] };

Тепепь нам понадобится глаз дятла утилита xcape, позволяющая назначить модификатору второе действие. Так, что если он нажат в сочетании с какой-то буквенно-циферной клавишей, то он срабатывает как модификатор, а если он нажат и отпущен в одиночку — он срабатывает как-то по-другому, как мы захотим. В бой!
$ xcape -t 1000 -e "Control_L=Escape"

xcape демонизируется под действием глаза дятла. Стоит ещё заметить интересный параметр -t 1000. Нет, он не призывает терминатора, он говорит о том, что если мы таки нажали левый Ctrl, и продержали его нажатым больше 1000 мс, то Escape не сработает. Отличная опция для нерешительных.

Из недостатков такого подхода можно назвать то, что Escape будет срабатывать не по нажатию, а по отпусканию клавиши. Кому-то эта задержка не страшна, а кому-то будет критична. А кто-то пойдёт на компромисс.

Бонус


Для всяких полезных, но редких символов существует такая вещь, как Compose Key, которая позволяет после её нажатия и отпускания набрать некую последовательность, которая соответствует какому-то Unicode символу, который и появится на экране. Например, последовательность нажатий «Compose o o» выдаст символ °. А «Compose c c c p» выдаст . Забавно? Символов очень много, а сочетания подобраны так, что запонмить их легко, причём в большинстве случаев порядок нажатия не важен, например «Compose e =» и «Compose = e» оба выдают . С полным списком стандартных сочетаний можно ознакомиться тут, а также можно назначать свои в файле ~/.XCompose.
А сделать так, чтобы в качестве Compose работал правый Ctrl можно добавлением следующей строки в наш файл:
    include "compose(rctrl)"

В путь-дорогу


Я сознательно не публикую свой конфиг целиком, чтобы читатель захотел поэкспериментировать. Вот вам пару идей в дорогу:
— нажимая клавишу F, сделайте так, чтобы HJKL работали как обычные стрелки;
— сделайте так, чтобы левая половина клавиатуры сдвигала регистр только с правым Shift, а правая — с левым. Это очень полезно для рук, хотя и не привычно;
— сделайте так, чтобы левый Shift не обязательно было зажимать, а чтобы было достаточно его однократно нажать и отпустить, а следом нажать, например, клавишу 5, так, чтобы напечатался символ % (подсказка: Latch);
— повесьте два разных модификатора на одну клавишу

Придумывайте, делитесь. Буду рад услышать интересные идеи.

PS Если вдруг кто скажет, что потом вот сядешь к кому-нибудь другому за клавиатуру, и сразу всё не так, то скажу так: пересаживаясь из Бентли помочь другу довезти до дома жигули, тоже ругаешься. Тем приятнее садиться обратно в Бентли.

Печатайте с удовольствием и берегите себя!