Включение сочетаний клавиш быстрого доступа в MATLAB для Mac

С R2009b у MATLAB были великолепно настраиваемые сочетания клавиш с помощью "Настройки ярлыков клавиатуры" . Это очень хорошо подходит для настройки ярлыков с помощью команды и управления на Mac.

К сожалению, эти привязки клавиш, похоже, не могут переопределить встроенную карту символов MATLAB. Например, если я определяю параметр -f как cursor-next-word (a la emacs), он принимает привязку. Нажатие комбинации клавиш правильно перемещает курсор на следующее слово, но дополнительно печатает символ ƒ! Я считаю, что это от карты персонажа (возможно, в отличие от входной карты?). Ни EditorMacro, ни KeyBindings не могут переопределить это поведение.

Я наткнулся на этот ответ из касательно связанного вопроса, который дает мне надежду. Короче говоря, он определил класс Java, который может обрабатывать события клавиатуры и заменять их другим вводом клавиш. Решение, однако, работает только в соответствии с требованиями Windows. Для работы на Mac потребовались следующие изменения:

Мне нужно было изменить коды клавиш для переназначения, чтобы "нажать" в строке, например:

map = {
    '$' '^'
    '#' char(181)  % might be useful for text formatting
};

в

map = {
    'alt pressed F' '^'
    'alt pressed B' char(181)  % might be useful for text formatting
};

К сожалению, после запуска кода нажатие опции-f дает cursor-next-word и символ ƒ, как и раньше. Однако, если я отключу привязку cursor-next-word от предпочтений, я получаю как ƒ, так и ^! Действительно, даже если я использую простое действие вроде pressed F, KeyReplacementAction не заменяет действие, а увеличивает его. Похоже, что это поведение уникально для MATLAB на OS X.

Кажется, я просто не переопределяю правильную раскладку. Я пробовал копать через среду выполнения Java, но я недостаточно знаком с моделью отправки событий, чтобы узнать, где искать дальше. Возможно, что-то в Java-клавиатуре на уровне ОС?


Изменить. С тех пор я немного поработал. Похоже, что версия Mac MATLAB должным образом не учитывает свойство "потребляемого" ключа. Я могу привязать KeyReplacementAction к inputMap или keymap, и в обоих случаях я увеличиваю привязку клавиш вместо их замены. Я использовал отражение для "снятия защиты" метода consume() для AWTEvents, но эффект был таким же, как и раньше.

После трассировки стека, кажется, что keyEvent проваливается к экземпляру javax.swing.KeyboardManager. Похоже, что я должен иметь возможность развязывать нажатия клавиш в KeyboardManager, но я не могу понять, как получить доступ к экземпляру с помощью ручек MATLAB, которые у меня есть. Возможно, кто-то, более знакомый с моделью событий Swing и отладчиком Java, может пройти дальше.


Изменить 2: flolo ответ заставил меня взглянуть на раскладки клавиатуры X11. Несколько примечаний:

  • Matlab, похоже, не уважает ~/.Xmodmap или любые загруженные в текущий момент модемы.
  • Matlab использует переменную среды $XKEYSYMDB, если она существует при запуске. В противном случае он загружает его из $MATLAB/X11/app-defaults/XKeysymDB.
  • Весь каталог $MATLAB/X11/app-defaults/ выглядит очень интересным; возможно, некоторые хакеры могут сделать эту работу?
  • Где находятся раскладки клавиатуры X11 на Mac? Как MATLAB переключается на международные раскладки клавиатуры?

Изменить 3: Хм, я думаю, что X11 - это красная селедка. lsof -c MATLAB показывает, что он обращается к /System/Library/Keyboard Layouts/AppleKeyboardLayouts.bundle. Работая над этим сейчас...


Изменить 4: MATLAB действительно использует раскладку системной клавиатуры. Я создал один без каких-либо привязок в качестве R.M.. Это, похоже, сработало - MATLAB ведет себя правильно. К сожалению, он также нарушает мои пользовательские привязки Cocoa для всех других программ. Близко, но не сигара. (На самом деле достаточно близко, что RM выиграл +500 баунти из-за короткой мысли, что это сработало... пока я не попытался составить свой поздравительный комментарий и обнаружил, что я не мог перемещаться по текстовому полю, как обычно.)

Ответы

Ответ 1

У меня наконец был шанс продолжить это в течение праздников. И я нашел клочок решения. Обратите внимание, что это динамическое изменение классов Java, используемых графическим интерфейсом Matlab во время выполнения; он полностью не поддерживается и, вероятно, будет очень хрупким. Он работает над моей версией Matlab (r2011a) на OS X Lion.

Вот что я узнал о том, как Swing/Matlab обрабатывает события нажатия клавиш:

  • Нажимается нажатие клавиши.
  • Выполняется поиск активного текстового компонента inputMap, чтобы увидеть, есть ли привязка для этого нажатия клавиши.
    • Если есть действие, связанное с этим нажатием клавиши, отправьте это действие actionPerformed method
    • Если есть строка, связанная с этим нажатием клавиши, найдите действие из текстового компонента actionMap, а затем отправьте это действие actionPerformed method
  • Независимо от того, что, в качестве последнего шага, отправьте действие, найденное в текстовом компоненте Keymap.getDefaultAction(). Здесь, где проблема.

Это решение переопределяет действие по умолчанию для Keymap оболочкой, которая просто проверяет, были ли нажаты какие-либо клавиши-модификаторы. Если они были, действие тихо игнорируется.


Шаг 1. Создайте пользовательский TextAction в Java, чтобы игнорировать ключи-модификаторы

import javax.swing.text.TextAction;
import javax.swing.Action;
import java.awt.event.ActionEvent;

public class IgnoreModifiedKeystrokesAction extends TextAction
{
    private static final int ignoredModifiersMask = 
        ActionEvent.CTRL_MASK | ActionEvent.ALT_MASK;
    private Action original;

    public IgnoreModifiedKeystrokesAction(Action act)
    {
        super((String)act.getValue("Name"));
        original = act;
    }

    public void actionPerformed(ActionEvent e)
    {
        if ((e.getModifiers() & ignoredModifiersMask) == 0) {
            /* Only dispatch the original action if no modifiers were used */
            original.actionPerformed(e);
        }
    }

    public Action getOriginalAction()
    {
        return original;
    }
}

Скомпилировать :

javac IgnoreModifiedKeystrokesAction.java && jar cvf IgnoreModifiedKeystrokesAction.jar IgnoreModifiedKeystrokesAction.class

Шаг 2: переопределите обработчик Keymap по умолчанию MATLAB как в окне команд, так и в редакторе (из MATLAB)

Самая сложная часть здесь - получение дескрипторов java в командном окне и редакторе. Это зависит от макета и имени класса отдельных панелей редактора. Это может измениться между версиями Matlab.

javaaddpath('/path/to/IgnoreModifiedKeystrokesAction.jar')
cmdwin = getCommandWindow();
editor = getEditor();

for t = [cmdwin,editor]
    defaultAction = t.getKeymap().getDefaultAction();
    if ~strcmp(defaultAction.class(),'IgnoreModifiedKeystrokesAction')
        newAction = IgnoreModifiedKeystrokesAction(defaultAction);
        t.getKeymap().setDefaultAction(newAction);
    end
end

%% Subfunctions to retrieve handles to the java text pane elements
function cw = getCommandWindow()
    try
        cw = handle(com.mathworks.mde.desk.MLDesktop.getInstance.getClient('Command Window').getComponent(0).getComponent(0).getComponent(0),'CallbackProperties');
        assert(strcmp(cw.class(),'javahandle_withcallbacks.com.mathworks.mde.cmdwin.XCmdWndView'));
    catch %#ok<CTCH>
        cw_client = com.mathworks.mde.desk.MLDesktop.getInstance.getClient('Command Window');
        cw = searchChildComponentsForClass(cw_client,'com.mathworks.mde.cmdwin.XCmdWndView');
    end
    if isempty(cw)
        error('Unable to find the Command Window');
    end
end

function ed = getEditor()
    try
        ed = handle(com.mathworks.mde.desk.MLDesktop.getInstance.getGroupContainer('Editor').getComponent(1).getComponent(0).getComponent(0).getComponent(0).getComponent(1).getComponent(0).getComponent(0).getComponent(0).getComponent(0).getComponent(1).getComponent(0).getComponent(0),'CallbackProperties');
        assert(strcmp(ed.class(),'javahandle_withcallbacks.com.mathworks.mde.editor.EditorSyntaxTextPane'));
    catch %#ok<CTCH>
        ed_group = com.mathworks.mde.desk.MLDesktop.getInstance.getGroupContainer('Editor');
        ed = searchChildComponentsForClass(ed_group,'com.mathworks.mde.editor.EditorSyntaxTextPane');
        % TODO: When in split pane mode, there are two editor panes. Do I need
        % to change actionMaps/inputMaps/Keymaps on both panes?
    end
    if isempty(ed)
        error('Unable to find the Editor Window');
    end
end

function obj = searchChildComponentsForClass(parent,classname)
    % Search Java parent object for a child component with the specified classname
    obj = [];
    if ~ismethod(parent,'getComponentCount') || ~ismethod(parent,'getComponent')
        return
    end
    for i=0:parent.getComponentCount()-1
        child = parent.getComponent(i);
        if strcmp(child.class(),classname)
            obj = child;
        else
            obj = searchChildComponentsForClass(child,classname);
        end
        if ~isempty(obj)
            obj = handle(obj,'CallbackProperties');
            break
        end
    end
end

Теперь можно определить привязки клавиш в окне стандартных настроек, которые используют ключ опции!


Шаг 3 (необязательно): удалить пользовательское действие

cmdwin = getCommandWindow();
editor = getEditor();

for t = [cmdwin,editor]
    defaultAction = t.getKeymap().getDefaultAction();
    if strcmp(defaultAction.class(),'IgnoreModifiedKeystrokesAction')
        oldAction = defaultAction.getOriginalAction();
        t.getKeymap().setDefaultAction(oldAction);
    end
end
javarmpath('/path/to/IgnoreModifiedKeystrokesAction.jar')

Ответ 2

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

Шрифты клавиатуры MATLAB сохраняются в файле XML в /Users/$user/.matlab/$version/$name_keybindings.xml, где $user - ваше имя пользователя, $version версия MATLAB и $name - это то, что вы сохранили привязки клавиш как. Это выглядит примерно так.

<?xml version="1.0" encoding="utf-8"?>
<CustomKeySet derivedfrom="Mac" modifieddefault="false">
   <Context id="Global">
      <Action id="eval-file">
         <Stroke alt="on" code="VK_ENTER" meta="on" sysctrl="on"/>
      </Action>
      <stuff here /stuff>
   </Context>
</CustomKeySet>

Я попытался изменить значение derivedfrom на EmptyBaseSet, чтобы узнать, что произойдет. Как и ожидалось, ни одна из ярлыков не работает, но Opt - character все еще воспроизводит символ Юникода. Это, по-видимому, указывает на то, что поведение Opt-f или любого параметра, основанного на ярлыке, происходит из-за Mac и из рук MATLAB. Это эквивалент Windows, который нажимает клавиши Alt + numpad для символов Unicode. Если MATLAB знал о ярлыках параметров, это указывало бы на возможный конфликт в MATLAB>Preferences>Keyboard>Shortcuts, но это не так. Я не знаю достаточно XML, чтобы сообщить вам, можно ли отключить Opt-f= ƒ, отредактировав этот файл.

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

Альтернативный вариант - попробовать Ukelele, который является редактором макетов клавиатуры. Были вопросы по С.О. и связанные сайты, где они использовали Ukelele для remap dead keys, еще один пример для мертвых ключей, настроить левую и правую Cmd по-разному, заменять € и $ и т.д. Вы можете попробовать переопределить клавиатуру макет для отключения Opt-f (если вам не нужен этот конкретный символ вне MATLAB), который должен решить проблему.

Наконец, я не хочу сказать, что "вы должны делать что-то еще", когда возникает вопрос "как это сделать?", но в целом с помощью macs я нашел отображение Ctrl в Ярлыки windows/emacs Alt будут проще, чем Opt. В основном, по тем же причинам, а также потому, что Opt настолько чертовски близко к клавише Cmd на моем ноутбуке, что мои толстые пальцы заканчиваются нажатием Cmd, когда я не хочу этого делать (это никогда не происходит путь вокруг).

Ответ 3

Как запросить уродливое обходное решение: я не работаю над MacOS, поэтому я вхожу в сферы "возможно, хороший совет": в X есть инструменты, которые могут захватывать X-события и выполнять команды по требованию, что, например, xkbevd также существует под MacOS (и я предполагаю, что инструмент java, о котором вы говорили, делает что-то подобное). Там вы можете поймать ctrl-f и заменить его на ctrl-f backspace, чтобы вы сбрасывали дополнительный символ. (Очень уродливый, и он нарушает эти коды за пределами Matlab).

Другая опция, если вы не хотите изменять поведение в командной строке, но только в редакторе - используйте внешний редактор: вы можете определить в настройках другой, отличный от значения по умолчанию. Там вы можете выбрать emacs, vi или что вам подходит (и где работает переназначение)

BTW: В Linux эта проблема не существует с помощью matlab, поэтому она выглядит как ее конкретный MacOS.