Почему они не работают
Согласно статье ArchWiki, которую вы упомянули:
X-сервер получает коды клавиш от устройства ввода и преобразует их в состояние и keyym.
состояние - битовая маска модификаторов X (Ctrl/Shift/ и т. д.).
keysym является (в соответствии с /usr/include/X11/keysymdef.h
) целым числом, которое
идентифицировать символы или функции, связанные с каждой клавишей (например, посредством видимой гравировки) раскладки клавиатуры.
Каждый печатный символ имеет свою собственную клавиатуру, например, plus
, a
, A
или Cyrillic_a
, но другие клавиши также генерируют свои клавиши, например Shift_L
, Left
или F1
.
Приложение в ключе события нажатия / выпуска получает всю эту информацию.
Некоторые приложения сами отслеживают ключевые символы, такие как Control_L
, другие просто ищут биты модификатора в состоянии.
Так что же происходит, когда вы нажимаете AltGr+j:
Вы нажимаете AltGr. Приложение получает событие KeyPressed с ключевым кодом 108 (<RALT>
) и keysym 0xfe03 (ISO_Level3_Shift
), состояние 0.
Вы нажимаете j (который отображается на «h» в двораке без модификаторов).
Приложение получает событие KeyPressed с кодом ключа 44 (<AC07>
), keysym 0xff51 (Left
) и состоянием 0x80 (модификатор Mod5 включен).
Вы отпускаете j. Приложение получает событие KeyRelease для ключа <AC07>
/Left
с теми же параметрами.
Затем отпустите событие AltGr - KeyRelease для AltGr. (Кстати, состояние здесь все еще 0x80, но это не имеет значения.)
Это можно увидеть, если вы запустите утилиту xev
.
Таким образом, все это означает, что, хотя приложение получает тот же код keysym (Left
), что и от обычного ключа <LEFT>
, оно также получает код keysym и состояние модификатора от AltGr. Скорее всего, те программы, которые не работают, следят за модификаторами и не хотят работать, когда некоторые активны.
Как заставить их работать
Очевидно, мы не можем изменить каждую программу, чтобы не искать модификаторы. Тогда единственная возможность избежать этой ситуации - не генерировать ключи и биты состояния модификаторов.
1. Отдельная группа
Единственный способ, который приходит мне в голову: определить клавиши перемещения курсора в отдельной группе и переключиться с помощью отдельного нажатия клавиши на эту группу до нажатия клавиш j, k, l, i (h
, t
, n
, c
) (групповая фиксация является предпочтительным методом для смены одной временной группы, как я понимаю).
Например:
xkb_keymap {
xkb_keycodes { include "evdev+aliases(qwerty)" };
xkb_types { include "complete" };
xkb_compatibility {
include "complete"
interpret ISO_Group_Latch { action = LatchGroup(group=2); };
};
xkb_symbols {
include "pc+us(dvorak)+inet(evdev)"
key <RALT> { [ ISO_Group_Latch ] };
key <AC07> {
type[Group2] = "ONE_LEVEL",
symbols[Group2] = [ Left ]
};
key <AC08> {
type[Group2] = "ONE_LEVEL",
symbols[Group2] = [ Down ]
};
key <AC09> {
type[Group2] = "ONE_LEVEL",
symbols[Group2] = [ Right ]
};
key <AD08> {
type[Group2] = "ONE_LEVEL",
symbols[Group2] = [ Up ]
};
};
xkb_geometry { include "pc(pc104)" };
};
Теперь, если вы сначала нажмете AltGr, а затем (отдельно) одну из клавиш перемещения, это должно сработать.
Однако это не очень полезно, более уместным будет LockGroup
вместо защелки и нажатие AltGr до и после группового переключения. Еще лучше может быть SetGroup
- тогда AltGr выберет эту группу только во время нажатия, но это откроет keyym приложения AltGr (ISO_Group_Shift
/ISO_Group_Latch
/все, что определено) (но состояние модификатора остается чистым).
Но ... также существует вероятность того, что приложение также считывает коды клавиш (коды реальных ключей). Затем он заметит «поддельные» клавиши курсора.
2. оверлей
Более «низкоуровневым» решением будет оверлей (как описано в той же статье ).
Наложение просто означает, что некоторая (настоящая клавиатура) клавиша возвращает код клавиши другой клавиши. X-сервер изменяет код ключа ключа и вычисляет состояние модификатора и код ключа для этого нового кода ключа, поэтому приложение не должно замечать это изменение.
Но оверлеи очень ограничены:
- В X-сервере есть только 2 управляющих бита наложения (т. Е. Может быть максимум 2 наложения).
- Каждый ключ может иметь только 1 альтернативный код ключа.
В остальном реализация очень похожа на метод с отдельной группой:
xkb_keymap {
xkb_keycodes { include "evdev+aliases(qwerty)" };
xkb_types { include "complete" };
xkb_compatibility {
include "complete"
interpret Overlay1_Enable {
action = SetControls(controls=overlay1);
};
};
xkb_symbols {
include "pc+us(dvorak)+inet(evdev)"
key <RALT> {
type[Group1] = "ONE_LEVEL",
symbols[Group1] = [ Overlay1_Enable ]
};
key <AC07> { overlay1 = <LEFT> };
key <AC08> { overlay1 = <DOWN> };
key <AC09> { overlay1 = <RGHT> };
key <AD08> { overlay1 = <UP> };
};
xkb_geometry { include "pc(pc104)" };
};
SetControls
означает изменение управляющего бита при нажатии клавиши и восстановление его при отпускании клавиши. Должна быть похожая функция LatchControls
, но xkbcomp
дает мне
Error: Unknown action LatchControls
на компиляции раскладки.
(Кстати, я также использую Дворжак, а также переназначил некоторые символы движения на высокие уровни букв алфавита. А также натолкнулся на некоторые неработающие функции (выбор в заметках Xfce и переключение рабочего стола по Ctrl-Alt-Left/Right). Благодаря вашему вопросу и этому ответу теперь я знаю, что такое оверлей :).)