Как эмулировать цифровую клавиатуру/клавиатуру для использования в программном обеспечении для дизайна (например, Blender)?

Как эмулировать цифровую клавиатуру/клавиатуру для использования в программном обеспечении для дизайна (например, Blender)?

Проблема

При использовании определенного программного обеспечения, такого какБлендерВажно иметь возможность использовать цифровую клавиатуру, чтобы пользователь мог ориентироваться в пространстве дизайна, но многие ноутбуки не оснащены физической цифровой клавиатурой.. Это усложняется тем фактом, что обычные цифровые панели ввода (от 1 до 9 в верхней части клавиатуры) на самом деле представляют собой разные «символы» для компьютера, поэтому часто имеют совершенно разные функции в этом виде программного обеспечения.

Попытки решения

Поскольку многие ноутбуки не оснащены цифровой клавиатурой,Распространенным решением на многих платформах является эмуляция цифровой клавиатуры., например, удерживая клавишу при использовании других клавиш на клавиатуре (например, jkluio789 для представления 123456789). Многие ноутбуки реализуют это на уровне BIOS (например, используя клавишу Fn). Однако без такой низкоуровневой реализации реализовать эту эмуляцию очень сложно.

Некоторые решения существуют в Интернете, ноих часто недостаточно для использования с программным обеспечением для проектирования(так как они не реализуют правильный символ, а также требуют использования клавиш-модификаторов), илиони не объясняются подробно. Большинство решений сосредоточены вокруг использованияхкб, что является сложной и крайне сложной архитектурой для начала использования.

Требования к хорошему решению

Хорошим решением этой проблемы будет эмулированная клавиатура, которую графическое программное обеспечение будет воспринимать как настоящий ввод с клавиатуры, и которая проста в использовании. Еще одним ограничением является тот факт, что Blender обнаруживает использование клавиш-модификаторов (таких как Shift, Alt, Super("Command", "Windows Key" и т. д.), Hyper) даже когда xkbему сообщают об удалении модификаторов, и поэтому будет интерпретировать решение "эмуляция клавиатуры при удержании клавиши-модификатора" как совершенно другой ввод (т. е. [ Numpad1+ Alt] вместо просто Numpad1). Поэтому идеальным решением будет фактически включать механизм блокировки (например, заглавные буквы Caps Lock) вместо механизма удержания (например, заглавные буквы Shift), чтобы никакие модификаторы случайно не передавались программному обеспечению.

решение1

Быстрый старт

Если вас не интересуют никакие объяснения (я знаю, что могу быть многословным), просто следуйте{жирные цифры в фигурных скобках}в начале некоторых абзацев. Следуйте каждому из этих шагов по порядку, и вы, вероятно, сможете реализовать это за несколько минут. Обратите внимание, что это руководство предполагает некоторую степень компетентности в Unix (умение создавать каталоги, создавать файлы, sudoповышать до root-доступа и т. д.). Также обратите внимание, чтоroot-доступ требуется только там, где это указано, поэтому вам не нужно его использовать, sudoесли вам не сказали об этом.

Общее описание решения

Мы будем использовать xkb для добавления "запирающей" (типа Caps Lock) эмуляции цифровой клавиатуры в Linux. Я бы хотел, чтобы мои клавиши "jkluio789" представляли представления цифровой клавиатуры для чисел "123456789", а также несколько других включений ("m,"->"0", "-=[]"->[numpad]"-+*", "."->[numpad]"."). Я буду переключать этот "режим цифровой клавиатуры" с помощью комбинации клавиш [ Shift+ Mod4+ [key]], где Mod4- код модификатора для клавиши моей операционной системы (также называемой "Command" или "Windows Key", и иногда назначаемой коду модификатора или Super) Hyper, а [key]- любая из клавиш, используемых в моей эмулируемой цифровой клавиатуре (например, "j" или "["). Простые изменения в этой настройке должны быть относительно простыми после прочтения полного решения.

Для этого мы определим пользовательский файл xkb "type", который сообщает xkb, как интерпретировать различные клавиши-модификаторы, которые мы будем использовать для инициализации нашей эмуляции клавиатуры, а также пользовательский файл xkb "symbols", который сообщает xkb, как каждая нажимаемая нами клавиша должна вести себя нормально (группа 1), как она должна вести себя во время эмуляции цифровой клавиатуры (группа 2) и как переключаться между ними (действие уровня 3 для обеих групп). Наконец, мы сделаем наше решение постоянным, интегрировав его в текущую xkbmap, используя sedкаждый раз, когда мы начинаем новый сеанс (чтобы наше решение не стиралось при каждом xkbобновлении).

Подробное описание решения

Структура каталога

{1}Первое, что мы сделаем, это определим каталог, в котором мы будем хранить наши различные файлы. Ваш каталог может выглядеть как угодно, но мой выглядит так

/home
  +-<username>
    +-.xkb
      +-symbols
      +-types
      +-keymap
      +-log

Тип файла

Как только у нас будет дерево каталогов, давайте определим реальные файлы в нашем решении. Первое, что мы сделаем, это определим наш файл "type". Этот файл расскажет, xkbкак перемещаться между "уровнями" (например, как Shiftсделать букву заглавной, переходя с первого уровня строчной буквы на уровень заглавной буквы). Эти уровни немного сложны для понимания, особенно для носителей английского языка, но международные клавиатуры используют их с большим эффектом для альтернативных букв и символов, а также диакритических знаков.

Мы будем использовать его для определения того, как мы намерены указывать на изменение наших клавиш. Другими словами, мы говорим ему, что ожидаем поведение "уровня 1", когда не нажат ни один модификатор (обычно это стандартная строчная буква в нашем "нормальном режиме"), поведение "уровня 2", когда мы удерживаем клавишу Shift(обычно это стандартная заглавная буква в нашем "нормальном режиме"), и поведение "уровня 3", когда мы удерживаем оба Shift+ Mod4(особый случай для наших целей, который мы используем, чтобы указать, что при использовании для изменения клавиши клавиша теперь будет переключаться между режимами).

{2}Откройте новый файл, который мы назовем togglekeypad. Скопируйте в него следующий блок кода и сохраните его в своей typesдиректории в \home\<username>\.xkb\types. ПРИМЕЧАНИЕ: вам может потребоваться изменить все экземпляры на Mod4любой модификатор, которому соответствует ваша кнопка "Command"/"Windows Key" (вам может потребоваться поэкспериментировать, см.эта веб-страница в разделе «Клавиши-модификаторы»для справки) или любой другой модификатор, который вам нравится.

partial default xkb_types "togglekeypad" { // Name of this type file
        type "TOGGLEKEYPAD" { // Name of this "type"
                modifiers = Shift+Mod4; // The modifiers that this type concerns itself with
                map[Shift] = level2; // Shift brings us to level 2
                map[Mod4+Shift] = level3; // Windows key plus shift brings us to level 3
                level_name[Level1] = "Base"; // Human-readable names for each level (not really used, but convenient)
                level_name[Level2] = "Shift";
                level_name[Level3] = "Transfer";
        };
};

{3}Мы также должны скопировать этот файл в каталог /usr/share/X11/xkb/types/. Для этого потребуются права root, что, к сожалению, несколько сводит на нет смысл xkbбыть приложением пользовательского пространства, но я, похоже, не могу setxkbmapраспознать файл без этого. Предложения приветствуются!

Файл символов

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

Мы скажем, что хотим использовать две группы в нашем файле символов. Это означает, что каждая клавиша имеет два различных общих поведения, между которыми мы будем переключаться каким-то образом, эти поведения — обычное поведение набора текста и новое поведение эмуляции цифровой клавиатуры. Для каждой клавиши мы скажем, что 1) мы хотим использовать тип TOGGLEKEYPAD, 2) мы определим символы (т. е. то, что видит компьютер), связанные с каждой из физических клавиш в обеих группах для всех уровней, и 3) мы определим любые действия (любые специальные вещи, которые xkbдолжны выполняться), связанные с каждой клавишей для обеих групп на всех уровнях. Это звучит довольно запутанно, но должно иметь немного больше смысла, если посмотреть на пример.

Первая клавиша, которую мы видим в файле символов, который я вставил ниже, — это клавиша <AC07>. Она соответствует клавише «J» на большинстве клавиатур,согласно карте, которую можно увидеть здесь(Рисунок 2). Для этой физической клавиши мы говорим, что в обычном режиме: на уровне 1 (без модификаторов, согласно нашему файлу типов) она просто наберет «j», а на уровне 2 ( Shiftмодификатор) она просто наберет «J». На уровне 3 она делает что-то особенное: с уровнем 3 не связан символ, но есть действие, и это действие — LockGroup(group=2). Другими словами, перейдем ко второй группе, нашей группе «Клавиатура». Если мы посмотрим на следующие несколько строк, то увидим, что для группы 2 для этой же клавиши определено больше символов и действий. Она говорит, что на уровне 1 (без модификаторов) не наберите символ, а RedirectKey(keycode=<KP1>). Другими словами, зарегистрируйте эту клавишу так, как будто мы на самом деле просто нажали клавишу <KP1>, что соответствует «1» на клавиатуре. (Примечание: мы могли бы снова поставить NoAction() и использовать символ KP_1, который является символом, которому <KP1>соответствует эта клавиша, но я подумал, что это даст лучшую совместимость). Для уровня 2 делаем то же самое, но добавляем модификатор Shiftк ключу. Наконец, для уровня 3 мы возвращаемся к Группе 1, режиму «Стандарт».

{4}Откройте новый файл, который мы назовем togglekeypad_symbols. Скопируйте в него следующий блок кода и сохраните его в своем symbolsкаталоге под \home\<username>\.xkb\symbols.

default partial
xkb_symbols "togglekeypad" {
    name[Group1]= "Standard";
    name[Group2]= "Keypad";

    key <AC07> { // J
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ j,  J, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP1>), RedirectKey(keyCode=<KP1>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AC08> { // K
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ k,  K, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP2>), RedirectKey(keyCode=<KP2>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AC09> { // L
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ l,  L, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP3>), RedirectKey(keyCode=<KP3>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AD07> { // U
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ u,  U, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP4>), RedirectKey(keyCode=<KP4>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AD08> { // I
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ i,  I, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP5>), RedirectKey(keyCode=<KP5>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AD09> { // O
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ o,  O, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP6>), RedirectKey(keyCode=<KP6>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AE07> { // 7
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ 7,  ampersand, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP7>), RedirectKey(keyCode=<KP7>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AE08> { // 8
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ 8,  asterisk, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP8>), RedirectKey(keyCode=<KP8>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AE09> { // 9
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ 9,  parenleft, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP9>), RedirectKey(keyCode=<KP9>), LockGroup(group=1)]
    };
    
    // NumLock
    key <AE06> { // 6
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ 6,  asciicircum, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<NMLK>), RedirectKey(keyCode=<NMLK>), LockGroup(group=1)]
    };
    
    // Bottom Row (and zero)
    key <AB07> { // M
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ m,  M, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP0>), RedirectKey(keyCode=<KP0>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AE10> { // 0
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ 0,  parenright, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP0>), RedirectKey(keyCode=<KP0>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AB09> { // .
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ period,  greater, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KPDL>), RedirectKey(keyCode=<KPDL>, modifiers=Shift), LockGroup(group=1)]
    };
    
    // Arithmetic Operators
    key <AE11> { // -
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ minus,  underscore, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KPSU>), RedirectKey(keyCode=<KPSU>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AE12> { // +
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ equal,  plus, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KPAD>), RedirectKey(keyCode=<KPAD>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AD12> { // [
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ bracketleft,  braceleft, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KPDV>), RedirectKey(keyCode=<KPDV>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AD12> { // ]
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ bracketright,  braceright, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KPMU>), RedirectKey(keyCode=<KPMU>, modifiers=Shift), LockGroup(group=1)]
    };
};

Проверьте нашу клавиатуру

{5}Чтобы проверить текущую конфигурацию клавиатуры, откройте Terminalокно и введите

setxkbmap -types complete+togglekeypad -print | sed -e '/xkb_symbols/s/"[[:space:]]/+togglekeypad_symbols(togglekeypad)&/' > $HOME/.xkb/keymap/customMap
xkbcomp -I$HOME/.xkb -R$HOME/.xkb keymap/customMap $DISPLAY

Это захватит текущие настройки нашей xkbкарты (используя setxkbmap - print) при установке используемых типов complete+togglekeypad(все в файле /usr/share/X11/xkb/types/complete, а также включая наш файл типов в /usr/share/X11/xkb/types/togglekeypad). Затем это будет передано в sed, который добавит наши символы togglekeypadиз нашего файла togglekeypad_symbolsв файлы используемых символов. Наконец, мы использовали xkbcompдля компиляции новой раскладки.

Обратите внимание, что на моем компьютере NumLock, как предполагается, выключен (потому что на нем нет цифровой панели), поэтому клавиши цифровой панели фактически будут отправлять свои основные функции на компьютер, то есть Home, End, PG Up, PG Down и т. д. Чтобы набирать числа при использовании эмулируемой цифровой панели, удерживайте Shift. Я пробовал разные методы, чтобы изменить это поведение (переставляя аргумент modifersмежду уровнями в файле символов, назначая новую клавишу для эмуляции клавиши NumLock <NMLK>и переключая ее), но ничего пока не сработало. К счастью, при тестировании в Blender все работает именно так, как и ожидалось, без необходимости удерживать Shift.

{6}Если на этом этапе все пошло ужасно неправильно, то не волнуйтесь, просто выйдите/войдите (или в худшем случае перезапустите), отладьте и попробуйте снова. Если все работает, давайте сделаем это постоянным.

Сделать решение постоянным

Конечно, есть несколько более элегантных способов сделать наше решение постоянным между сеансами, но самым простым и надежным для меня было просто поместить приведенные выше команды в конец моего ~/.bashrcфайла. Я использовалрешение, предложенное здесьчто добавляет немного проверки ошибок и добавляет немного больше (чтобы я мог видеть любые выходные данные об ошибках).

{7}Откройте файл ~/.bashrc. Добавьте в его конец следующий скрипт:

    # Setup custom keyboard remapping to emulate a number pad when "Shift+Cmd+numap_key" is pressed to initialize
if [ -d $HOME/.xkb/keymap ]; then
  setxkbmap -types complete+togglekeypad -print | \
    sed -e '/xkb_symbols/s/"[[:space:]]/+togglekeypad_symbols(togglekeypad)&/' > $HOME/.xkb/keymap/customMap 2> $HOME/.xkb/log/sedErrors
  xkbcomp -w0 -I$HOME/.xkb -R$HOME/.xkb keymap/customMap $DISPLAY > $HOME/.xkb/log/outputOfCommand 2>&1
fi

{8}После перезапуска эмуляция цифровой клавиатуры должна стать постоянной!

Заключение

Хотя объяснение длинное, сам метод относительно короткий. Недостатки в том, что Blender требует метод блокировки для правильной работы, тогда как я бы предпочел метод удержания, а также в том, что xkbпо какой-то причине он требует доступа root для распознавания нашего файла пользовательских типов. Однако в целом, это, похоже, работает хорошо для меня. Если у вас есть какие-либо вопросы или предложения, пожалуйста, не стесняйтесь оставлять их ниже!

Связанный контент