Как заставить все приложения уважать мой измененный макет xkb?


15

Мне не нравится прыгать между основной клавиатурой и клавишами перемещения, поэтому я добавил следующее в свой файл макета xkb.

hidden partial xkb_symbols "movement"
{
    key <AD08> { [ NoSymbol, NoSymbol, Up,          Up          ] };
    key <AC08> { [ NoSymbol, NoSymbol, Down,        Down        ] };
    key <AC07> { [ NoSymbol, NoSymbol, Left,        Left        ] };
    key <AC09> { [ NoSymbol, NoSymbol, Right,       Right       ] };
    key <AD09> { [ NoSymbol, NoSymbol, Prior,       Prior       ] };
    key <AB09> { [ NoSymbol, NoSymbol, Next,        Next        ] };
    key <AB07> { [ NoSymbol, NoSymbol, Home,        Home        ] };
    key <AB08> { [ NoSymbol, NoSymbol, End,         End         ] };
    key <AC06> { [ NoSymbol, NoSymbol, Delete,      Delete      ] };
}

Затем я включаю их в макет на более позднем этапе файла. Теперь у меня должны быть клавиши курсора, доступные через AltGr + j, k, l, i (или h, t, n, c, поскольку я использую dvorak) и т. Д. Это работает во многих случаях (например, Firefox, urxvt, Eclipse, основной текстовой области LyX), но некоторые программы ничего не делают, когда я пытаюсь, скажем, переместить курсор с помощью этих «горячих клавиш» (например, диалогов NetBeans и LyX).

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

Редактировать:

  • Вот полный, но упрощенный файл раскладки клавиатуры. У меня есть это, /usr/share/X11/xkb/symbols/nonpopи я загружаю его setxkbmap nonpop.
  • Я заметил, что в MonoDevelop передвижение работает, а выбор - нет. То есть, если я нажимаю Shift + вправо, текст выделяется как обычно, но если я нажимаю AltGr + Shift + n, курсор просто перемещается без выбора. Например, в Firefox оба способа могут быть использованы для выбора.
  • Здесь, в конце, они говорят о наложениях, которые выглядят как нечто, что может быть решением, но я не понял, как их использовать.

1
У меня нет решения, но если вам не удастся получить ответ, несмотря на щедрость, которую вы выставили, вы можете попробовать обратиться к unix.SE , более ориентированному на Unix / Linux сайту Stackexchange.
Glutanimate

Ответы:


16

Почему они не работают

Согласно статье ArchWiki, которую вы упомянули:

  • X-сервер получает коды клавиш от устройства ввода и преобразует их в состояние и KeySym .

    • состояние - это битовая маска модификаторов X (Ctrl / Shift / и т. д.).

    • KeySym (в соответствии с /usr/include/X11/keysymdef.h) целое число, которое

      идентифицировать символы или функции, связанные с каждой клавишей (например, посредством видимой гравировки) раскладки клавиатуры.

      Каждый печатный символ имеет свой собственный символ клавиши, как plus, a, Aили Cyrillic_a, но другие клавиши также генерируют свои символы клавиш, как Shift_L, Leftили F1.

  • Приложение в ключе события нажатия / выпуска получает всю эту информацию.

    Некоторые приложения отслеживают ключевые символы подобно Control_Lсебе, другие просто ищут биты модификатора в состоянии .

Итак, что происходит, когда вы нажимаете AltGr+ j:

  • Вы нажимаете AltGr. Приложение получает событие KeyPressed с <RALT>ключевым кодом 108 ( ) и keysym 0xfe03 ( ISO_Level3_Shift), состояние 0.

  • Вы нажимаете j(что соответствует «h» в двораке без модификаторов). Приложение получает событие KeyPressed с <AC07>кодом клавиши 44 ( ), 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 выберет эту группу только во время нажатия, но это откроет клавише 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

на компиляции раскладки.

(Кстати, я также использую dvorak, а также переназначил некоторые ключевые символы движения на высокий уровень буквенных клавиш. А также натолкнулся на некоторые неработающие функции (выбор в примечаниях Xfce и переключение рабочего стола с помощью Ctrl-Alt-Left / Right). Благодаря ваш вопрос и этот ответ, теперь я знаю, что такое оверлей :).)


Благодарность! На самом деле я получил другой ответ на unix.se, который на первый взгляд казался идеальным, но оказалось, что некоторые приложения по-прежнему плохо себя ведут. Это решение (оверлеи) работает и в этих случаях.
nonpop

Я только что заметил, что Google Chrom [e | ium] тоже не заботится об этом! :( К счастью, я их мало использую.
nonpop

@nonpop проклятый хром… Я добавил обновление в свой ответ superuser.com/a/1000320/521612
Алекс-Даниил Якименко

Удивительный! Я искал это годами! Есть еще небольшая проблема с Chromium, где он интерпретирует нажатие клавиши Overlay1_Enable. У меня есть один и тот же симптом , как здесь: github.com/GalliumOS/galliumos-distro/issues/362
Тарраша

1
Мне просто удалось исправить вышеуказанную проблему. Клавиши со стрелками моего домашнего ряда теперь работают и в Chromium! Мне нужно было внести следующие изменения в этот ответ. gist.github.com/Tarrasch/1293692/...
Тарраш

4

У меня точно такая же проблема. Это так больно.

Итак, заголовок «Как заставить все приложения уважать мой измененный макет xkb?». Ну, я думаю, что единственный способ - это исправить все программы, которые делают это неправильно. Давайте сделаем это!

Что ж, после сообщения об этой ошибке в NetBeans ( обновление: я попробовал последнюю версию, и она работает сейчас! ), Я подумал, что буду просто сообщать об этой ошибке для каждого приложения. Следующим приложением в списке был Speedcrunch .

Однако после поиска похожих сообщений об ошибках я обнаружил эту проблему . У кого-то такая же проблема, отлично!

Прочитав комментарии, вы поймете, что эта ошибка должна присутствовать во всех приложениях QT. Вот отчет об ошибке QT . Не решен, но похоже, что проблема решена в Qt5 .

Однако, если вы посмотрите на комментарии, есть обходной путь! Вот как это работает. Если вы делаете это:

key <SPCE> { [ ISO_Level3_Shift ] };

Тогда вы можете изменить это на это:

key <SPCE> {
  type[Group1]="ONE_LEVEL",
  symbols[Group1] = [ ISO_Level3_Shift ]
};

И это действительно решит проблему для некоторых приложений! Например, Speedcrunch теперь работает для меня! Ура!

Резюме

Прямо сейчас любое приложение должно работать правильно. Если это не так, то вы должны использовать type[Group1]="ONE_LEVEL". Если он у вас уже есть, вам нужно обновить программное обеспечение. Если это все еще не работает, то это зависит от приложения, и вы должны отправить отчет об ошибке.

ОБНОВЛЕНИЕ (2017-09-23)

На сегодняшний день все приложения соответствуют моей раскладке клавиатуры. Все, кроме одного.

Серьезно, обработка клавиатуры в Chromium - это мусор . Есть несколько проблем с этим:

  • Выбор сдвига не с пользовательскими клавишами со стрелками (но сами клавиши со стрелками работают нормально)
  • Если у вас есть несколько макетов, и на одном из макетов какая-то клавиша является особенной (например, стрелки, Backspace и т. Д.), То на другом макете эта клавиша будет зафиксирована на том, что есть в вашем первом макете. Например, если у вас есть две раскладки: foo, barи некоторые ключевые делает Backspace в foo, то он будет продолжать работать , как Backspace в barдаже если он переопределен там.

В течение многих лет я игнорировал эти проблемы, просто не используя хром. Тем не менее, в настоящее время вещи, как правило, используют Electron , который, к сожалению, построен на хроме.

Правильный способ решить эту проблему - отправить сообщение об ошибке в Chromium и надеяться на лучшее. Я не знаю, сколько времени им понадобится, чтобы решить проблему, которая затрагивает только пару пользователей ... но, похоже, это единственный выход. Проблема в том, что хром на самом деле хорошо работает с neo(de)макетом. Нео макет имеет клавиши со стрелками на уровне 5, но я не могу заставить его работать в моем собственном макете.

Все еще открытые отчеты об ошибках:


Спасибо за информацию! Обходной путь не помогает мне, поэтому я думаю, что мне придется просто сообщать об ошибках и ждать преобразований qt5.
nonpop

4

Как заставить их работать - Решение 3

Использование дополнительных уровней и действий RedirectKey

Следующее решение использует левую клавишу Alt для предоставления клавиш курсора на jkli, Home / End / PageUp / PageDown на uopö и Delete на Backspace.

Левая клавиша Alt остается пригодной для других целей для всех остальных клавиш (например, для меню приложения). Левый Alt (Mod1) удаляется из состояния модификатора, когда используется блок курсора, поэтому приложения не могут его видеть.

xkb_keymap {
    xkb_keycodes { 
        include "evdev+aliases(qwertz)" 
    };
    xkb_types { 
        include "complete"  
    };
    xkb_compat { 
        include "complete"
        interpret osfLeft {
            action = RedirectKey(keycode=<LEFT>, clearmodifiers=Mod1);
        };
        interpret osfRight {
            action = RedirectKey(keycode=<RGHT>, clearmodifiers=Mod1);
        };
        interpret osfUp {
            action = RedirectKey(keycode=<UP>, clearmodifiers=Mod1);
        };
        interpret osfDown {
            action = RedirectKey(keycode=<DOWN>, clearmodifiers=Mod1);
        };
        interpret osfBeginLine {
            action = RedirectKey(keycode=<HOME>, clearmodifiers=Mod1);
        };
        interpret osfEndLine {
            action = RedirectKey(keycode=<END>, clearmodifiers=Mod1);
        };
        interpret osfPageUp {
            action = RedirectKey(keycode=<PGUP>, clearmodifiers=Mod1);
        };
        interpret osfPageDown {
            action = RedirectKey(keycode=<PGDN>, clearmodifiers=Mod1);
        };
        interpret osfDelete {
            action = RedirectKey(keycode=<DELE>, clearmodifiers=Mod1);
        };
    };
    xkb_symbols { 
        include "pc+de(nodeadkeys)"
        include "inet(evdev)"
        include "compose(rwin)"
        key <LALT> {
            type[Group1] = "ONE_LEVEL",
            symbols[Group1] = [ ISO_Level5_Shift ]
        };
        modifier_map Mod1 { <LALT> };
        key <AC07> {
            type[Group1] = "EIGHT_LEVEL_SEMIALPHABETIC",
            symbols[Group1] = [ j, J, dead_belowdot, dead_abovedot, osfLeft, osfLeft, osfLeft, osfLeft ]
        };
        key <AC08> {
            type[Group1] = "EIGHT_LEVEL_SEMIALPHABETIC",
            symbols[Group1] = [ k, K, kra, ampersand, osfDown, osfDown, osfDown, osfDown ]
        };
        key <AC09> {
            type[Group1] = "EIGHT_LEVEL_ALPHABETIC",
            symbols[Group1] = [ l, L, lstroke, Lstroke, osfRight, osfRight, osfRight, osfRight ]
        };
        key <AC10> {
            type[Group1] = "EIGHT_LEVEL_SEMIALPHABETIC",
            symbols[Group1] = [ odiaeresis, Odiaeresis, doubleacute, doubleacute, osfPageDown, osfPageDown, osfPageDown, osfPageDown ]
        };
        key <AD07> {
            type[Group1] = "EIGHT_LEVEL_SEMIALPHABETIC",
            symbols[Group1] = [ u, U, downarrow, uparrow, osfBeginLine, osfBeginLine, osfBeginLine, osfBeginLine ]
        };
        key <AD08> {
            type[Group1] = "EIGHT_LEVEL_SEMIALPHABETIC",
            symbols[Group1] = [ i, I, rightarrow, idotless, osfUp, osfUp, osfUp, osfUp ]
        };
        key <AD09> {
            type[Group1] = "EIGHT_LEVEL_ALPHABETIC",
            symbols[Group1] = [ o, O, oslash, Oslash, osfEndLine, osfEndLine, osfEndLine, osfEndLine ]
        };
        key <AD10> {
            type[Group1] = "EIGHT_LEVEL_ALPHABETIC",
            symbols[Group1] = [ p, P, thorn, THORN, osfPageUp, osfPageUp, osfPageUp, osfPageUp ]
        };
        key <BKSP> {
            type[Group1] = "EIGHT_LEVEL_ALPHABETIC",
            symbols[Group1] = [ BackSpace, BackSpace, BackSpace, BackSpace, osfDelete, osfDelete, osfDelete, osfDelete ] 
        };
    };
    xkb_geometry { 
        include "pc(pc105)" 
    };
};

Святой моли! Это на самом деле работает! Он работает вокруг сломанных приложений, таких как Chromium. Можете ли вы объяснить, что это за определения osf? Кажется, они предопределены, поэтому вы не можете назвать их случайным образом.
Алекс-Даниил Якименко
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.