在Mac版MATLAB中启用选项键快捷方式 [英] Enabling option-key shortcuts in MATLAB for Mac

查看:136
本文介绍了在Mac版MATLAB中启用选项键快捷方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

自R2009b起,MATLAB通过其键盘快捷键首选项.这对于在Mac上使用命令和控制来自定义快捷方式非常有用.

Since R2009b, MATLAB has had marvelously customizable keyboard shortcuts through its Keyboard Shortcuts Preferences. This works very well for customizing shortcuts using command and control on a Mac.

不幸的是,这些键绑定似乎无法覆盖MATLAB的内置字符映射.例如,如果我将option-f定义为cursor-next-word(一个emacs),则它接受绑定.击中组合键确实可以将光标移动到下一个单词,但是它还会打印ƒ字符!我相信这是从字符映射表(也许与输入映射表相反?)中获得的. 键盘绑定能够覆盖此行为.

Unfortunately, those keybindings seem to be unable to override MATLAB's built-in character map. For example, if I define option-f as cursor-next-word (a la emacs), it accepts the binding. Hitting the key combination does properly move the cursor to the next word, but it additionally prints the ƒ character! I believe this is from the character map (perhaps as opposed to the input map?). Neither EditorMacro nor KeyBindings are able to override this behavior.

我偶然发现了这个与切向相关的答案问题,这给了我希望.简而言之,他定义了一个Java类,该类可以处理键盘事件并将其替换为其他按键输入.但是,该解决方案只能在Windows上按规定使用.要在Mac上运行,必须进行以下修改:

I stumbled across this answer from a tangentially related question which gives me hope. In short, he defined a Java class that can handle keyboard events and replace them with other keystroke input. The solution, however, only works as prescribed on Windows. The following modifications were required to run on a Mac:

我需要更改键码以重新映射为已在字符串中按下",例如:

I needed to change the keycodes to remap to have 'pressed' in the string, like so:

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

收件人:

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

不幸的是,在运行代码之后,按option -f会产生cursor-next-wordƒ字符,就像以前一样.但是,如果我从首选项中禁用cursor-next-word绑定,那么我会得到两者ƒ^!确实,即使我使用了pressed F之类的简单动作,KeyReplacementAction也不会代替动作,而是 augments .看来这种行为是OS X上的MATLAB所特有的.

Unfortunately, after running the code, pressing option-f yields cursor-next-word and the ƒ character, just like before. However, if I disable the cursor-next-word binding from the preferences, then I get both ƒ and ^! Indeed, even if I use a simple action like pressed F, the KeyReplacementAction doesn't replace the action but rather augments it. It seems like this behavior is unique to MATLAB on OS X.

似乎我只是没有覆盖正确的键盘映射.我已经尝试了Java运行时的挖掘,但是我对事件分发模型还不够熟悉,无法知道下一步该怎么看.也许是Java的操作系统级键盘映射中的某些内容?

It seems as though I'm simply not overriding the correct keymap. I've tried digging through the Java runtime, but I'm not familiar enough with the event dispatch model to know where to look next. Perhaps something within Java's OS-level keymap?

编辑:此后,我做了一些进一步的研究.似乎Mac版本的MATLAB不能正确遵守keyEvent的'consumed'属性.我可以将KeyReplacementAction附加到inputMapkeymap上,在两种情况下,我都增加了键绑定而不是替换键绑定.我使用反射来取消保护" AWTEvents的consume()方法,但效果与以前相同.

Edit: I've since done some more digging around. It appears as though the Mac version of MATLAB does not properly respect the 'consumed' property of a keyEvent. I can attach the KeyReplacementAction to either the inputMap or the keymap, and in both cases I augment the keybinding instead of replacing it. I used reflection to 'unprotect' the consume() method for AWTEvents, but the effect was the same as before.

在堆栈跟踪之后,似乎keyEvent陷入了javax.swing.KeyboardManager的实例.看起来我应该能够在KeyboardManager中解除键击的绑定,但是我无法弄清楚如何从已有的MATLAB句柄访问实例.也许更熟悉Swing的事件模型和Java调试器的人可能会走得更远.

Following the stack trace around, it appears as though the keyEvent is falling through to an instance of javax.swing.KeyboardManager. It looks like I should be able to unbind keystrokes within the KeyboardManager, but I cannot figure out how to access the instance from the MATLAB handles I have. Perhaps someone more familiar with Swing's event model and the Java debugger could get farther.

编辑2 : flolo 的答案促使我研究X11的键盘映射.几点注意事项:

Edit 2: flolo's answer spurred me to look into X11's keymaps. Several notes:

  • Matlab似乎不尊重~/.Xmodmap或任何当前加载的modmap.
  • Matlab使用$XKEYSYMDB环境变量(如果在启动时存在).否则,它将从$MATLAB/X11/app-defaults/XKeysymDB加载.
  • 整个$MATLAB/X11/app-defaults/目录看起来非常有趣;也许那里的一些黑客可以使这项工作成功?
  • 在Mac上Xem键盘上的 在哪里? MATLAB如何切换到国际键盘布局?
  • Matlab does not seem to respect ~/.Xmodmap or any currently-loaded modmaps.
  • Matlab makes use of the $XKEYSYMDB environment variable if it exists at startup. Otherwise, it loads it from $MATLAB/X11/app-defaults/XKeysymDB.
  • The whole $MATLAB/X11/app-defaults/ directory looks very interesting; perhaps some hackery there could make this work?
  • Where are the X11 keymaps on a Mac? How does MATLAB switch to international keyboard layouts?

编辑3 :嗯,我认为X11是红鲱鱼. lsof -c MATLAB表示它正在访问/System/Library/Keyboard Layouts/AppleKeyboardLayouts.bundle.现在正在努力……

Edit 3: Hrm, I think X11 is a red herring. lsof -c MATLAB shows that it is accessing /System/Library/Keyboard Layouts/AppleKeyboardLayouts.bundle. Working on that now…

编辑4 :MATLAB确实确实使用了系统键盘布局.我按照 R.M. 的建议创建了一个没有任何绑定的对象.这似乎可以正常工作-MATLAB的行为正常.不幸的是,它也破坏了我在所有其他程序中的自定义可可键绑定.关闭,但没有雪茄. (事实上​​,由于简短地认为RM有效,RM赢得了+500赏金,直到我试图撰写祝贺的评论并发现我无法像往常一样浏览文本字段为止.)

Edit 4: MATLAB does indeed use the system keyboard layout. I created one without any bindings as R.M. suggested. This appeared to work — MATLAB does behave properly. Unfortunately, it also breaks my custom Cocoa keybindings in all other programs. Close, but no cigar. (Close enough, in fact, that R.M. won the +500 bounty due to a brief thought that it had worked… until I attempted to compose my congratulatory comment and discovered that I couldn't navigate the text field as usual.)

推荐答案

在假期期间,我终于有机会进一步追求这一点.我发现了解决方案的麻烦.注意,这是在运行时动态更改Matlab GUI使用的Java类.它是完全不受支持的,并且可能非常脆弱.它可以在我的OS X Lion版本的Matlab(r2011a)上运行.

I finally had a chance to further pursue this over the holidays. And I found a kludge of a solution. Note that this is dynamically changing the Java classes used by the Matlab GUI in runtime; it is completely unsupported and is likely to be very fragile. It works on my version of Matlab (r2011a) on OS X Lion.

这是我对Swing/Matlab如何处理按键事件的了解:

Here's what I've learned about how Swing/Matlab process keypress events:

  1. 按下了按键.
  2. 搜索活动文本组件的inputMap,以查看该击键是否存在绑定.
    • 如果该键绑定了一个动作,请分派该动作的actionPerformed方法
    • 如果有与该击键相关的字符串,请从文本组件的actionMap中找到该动作,然后分派该动作的actionPerformed方法
  1. A keystroke is pressed.
  2. The active text component's inputMap is searched to see if there's a binding for that keystroke.
    • If there is an action bound to that keystroke, dispatch that action's actionPerformed method
    • If there is a string associated with that keystroke, find the action from the text component's actionMap, and then dispatch that action's actionPerformed method

此解决方案使用包装器覆盖了Keymap的默认操作,该包装器仅检查是否按下了任何修饰键.如果是这样,则该操作将被静默忽略.

This solution overrides the Keymap's default action with a wrapper that simply checks to see if any modifier keys were pressed. If they were, the action is silently ignored.

步骤1:使用Java创建自定义TextAction来忽略修饰键

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的默认Keymap处理程序

这里最难的部分是使Java句柄进入命令窗口和编辑器.它取决于各个编辑器窗格的布局和类名.不同版本的Matlab可能会有所不同.

The hardest part here is getting the java handles to the command window and editor. It is dependent upon the layout and classnames of the individual editor panes. This may change between versions of 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

现在可以在使用选项键的标准首选项窗口中定义键绑定了!

Now it's possible to define keybindings in the standard preferences window that use the option key!

第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')

这篇关于在Mac版MATLAB中启用选项键快捷方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆