11

Мне не нравится прыгать между основной клавиатурой и клавишами перемещения, поэтому я добавил следующее в свой файл макета 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 оба способа могут быть использованы для выбора.
  • Здесь, в конце, они говорят о наложениях, которые выглядят как нечто, что может быть решением, но я не понял, как их использовать.

3 ответа3

10

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

Согласно статье 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). Благодаря вашему вопросу и этому ответу теперь я знаю, что такое оверлей :).)

3

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

Поэтому заголовок «Как заставить все приложения уважать мой измененный макет 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) макетом. На уровне Neo есть клавиши со стрелками на уровне 5, но я не могу заставить его работать в моем собственном макете.

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

1

Как заставить их работать - Решение 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)" 
    };
};

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .