Включение сочетаний клавиш в MATLAB для Mac - PullRequest
14 голосов
/ 11 марта 2011

Начиная с 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
};

to:

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 Keymap OS-level?


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

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


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

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

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


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

Ответы [ 3 ]

3 голосов
/ 04 января 2012

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

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

  1. Нажата клавиша.
  2. В активном текстовом компоненте inputMap выполняется поиск, чтобы увидеть, есть ли привязка для этого нажатия клавиши.
    • Если с этим нажатием клавиши связано действие, отправьте actionPerformed метод этого действия
    • Если с этим сочетанием клавиш связана строка, найдите действие из actionMap текстового компонента, а затем отправьте actionPerformed метод этого действия
  3. Независимо от того, что , в качестве последнего шага отправьте действие, найденное в текстовом компоненте 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;
    }
}

Компилировать в .jar:

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

Шаг 2. Переопределить стандартный обработчик раскладки клавиатуры 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 голосов
/ 25 марта 2011

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

Сочетания клавиш в 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 + цифровых клавиш для символов Юникода.Если бы MATLAB знал о сочетаниях клавиш, это указывало бы на возможный конфликт в MATLAB>Preferences>Keyboard>Shortcuts, но это не так.Я не знаю достаточно XML, чтобы сказать вам, можете ли вы отключить Opt-f = ƒ, отредактировав этот файл.

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

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

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

1 голос
/ 31 марта 2011

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

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

Кстати: под Linux этой проблемы не существует с matlab, поэтому похоже, что она действительно специфична для MacOS.

...