简体   繁体   English

在MATLAB for Mac中启用选项键快捷键

[英]Enabling option-key shortcuts in MATLAB for Mac

Since R2009b, MATLAB has had marvelously customizable keyboard shortcuts through its Keyboard Shortcuts Preferences . 自R2009b起,MATLAB通过其键盘快捷键首选项获得了非常出色的键盘快捷 This works very well for customizing shortcuts using command and control on a Mac. 这非常适合在Mac上使用命令和控件自定义快捷方式。

Unfortunately, those keybindings seem to be unable to override MATLAB's built-in character map. 不幸的是,那些键绑定似乎无法覆盖MATLAB的内置字符映射。 For example, if I define option-f as cursor-next-word (a la emacs), it accepts the binding. 例如,如果我将option-f定义为cursor-next-word (la emacs),则它接受绑定。 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. EditorMacroKeyBindings都无法覆盖此行为。

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. 简而言之,他定义了一个Java类,它可以处理键盘事件并用其他键击输入替换它们。 The solution, however, only works as prescribed on Windows. 但是,该解决方案仅适用于Windows上的规定。 The following modifications were required to run on a Mac: 要在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
};

to: 至:

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

Unfortunately, after running the code, pressing option-f yields cursor-next-word and the ƒ character, just like before. 不幸的是,在运行代码之后,按下option-f会产生cursor-next-wordƒ字符,就像之前一样。 However, if I disable the cursor-next-word binding from the preferences, then I get both ƒ and ^ ! 但是,如果我禁用cursor-next-word从喜好结合,然后我得到两个 ƒ^ Indeed, even if I use a simple action like pressed F , the KeyReplacementAction doesn't replace the action but rather augments it. 实际上,即使我使用像pressed F一样的简单动作,KeyReplacementAction也不会取代动作,而是会增加动作。 It seems like this behavior is unique to MATLAB on OS X. 看起来这种行为对OS X上的MATLAB来说是独一无二的。

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. 我已经尝试过挖掘Java运行时,但我对事件调度模型不太熟悉,知道接下来要去哪里看。 Perhaps something within Java's OS-level keymap? 也许是Java的OS级关键映射中的某些内容?


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. 似乎Mac版的MATLAB没有正确地遵守keyEvent的'consume'属性。 I can attach the KeyReplacementAction to either the inputMap or the keymap , and in both cases I augment the keybinding instead of replacing it. 我可以将KeyReplacementAction附加到inputMapkeymap ,在这两种情况下我都会增加键绑定而不是替换它。 I used reflection to 'unprotect' the consume() method for AWTEvents, but the effect was the same as before. 我使用反射'unprotect'为AWTEvents的consume()方法,但效果与以前相同。

Following the stack trace around, it appears as though the keyEvent is falling through to an instance of javax.swing.KeyboardManager . 在堆栈跟踪之后,似乎keyEvent正在落入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. 看起来我应该能够取消绑定KeyboardManager中的键击,但我无法弄清楚如何从我的MATLAB句柄访问该实例。 Perhaps someone more familiar with Swing's event model and the Java debugger could get farther. 也许更熟悉Swing的事件模型和Java调试器的人可能会更进一步。


Edit 2 : flolo 's answer spurred me to look into X11's keymaps. 编辑2flolo的回答促使我研究X11的键盘图。 Several notes: 几点说明:

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

Edit 3 : Hrm, I think X11 is a red herring. 编辑3 :嗯,我认为X11是红鲱鱼。 lsof -c MATLAB shows that it is accessing /System/Library/Keyboard Layouts/AppleKeyboardLayouts.bundle . lsof -c MATLAB显示它正在访问/System/Library/Keyboard Layouts/AppleKeyboardLayouts.bundle Working on that now… 现在正在努力......


Edit 4 : MATLAB does indeed use the system keyboard layout. 编辑4 :MATLAB确实使用系统键盘布局。 I created one without any bindings as RM suggested. 我创建了一个没有任何绑定为RM建议。 This appeared to work — MATLAB does behave properly. 这似乎有效 - MATLAB确实表现得很好。 Unfortunately, it also breaks my custom Cocoa keybindings in all other programs. 不幸的是,它也破坏了我在所有其他程序中的自定义Cocoa键绑定。 Close, but no cigar. 关闭,但没有雪茄。 (Close enough, in fact, that RM 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.) (实际上,足够接近,RM因为一直认为它已经奏效而赢得了+500赏金......直到我试图撰写我的祝贺评论并发现我无法照常浏览文本字段。)

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; 请注意,这是在运行时动态更改Matlab GUI使用的Java类; it is completely unsupported and is likely to be very fragile. 它完全不受支持,可能非常脆弱。 It works on my version of Matlab (r2011a) on OS X Lion. 它适用于OS X Lion上我的Matlab版本(r2011a)。

Here's what I've learned about how Swing/Matlab process keypress events: 以下是我对Swing / Matlab如何处理按键事件的了解:

  1. A keystroke is pressed. 按下按键。
  2. The active text component's inputMap is searched to see if there's a binding for that keystroke. 搜索活动文本组件的inputMap以查看是否存在该键击的绑定。
    • If there is an action bound to that keystroke, dispatch that action's actionPerformed method 如果有一个绑定到该击键的动作,则调度该动作的actionPerformed方法
    • 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 如果有一个与该击键相关联的字符串,请从文本组件的actionMap找到该操作,然后调度该操作的actionPerformed方法
  3. No matter what , as a final step, dispatch the action found within the text component's Keymap.getDefaultAction() . 无论如何 ,作为最后一步,调度在文本组件的Keymap.getDefaultAction()找到的动作。 Here's where the problem lies. 这就是问题所在。

This solution overrides the Keymap's default action with a wrapper that simply checks to see if any modifier keys were pressed. 此解决方案使用包装器覆盖Keymap的默认操作,该包装器只检查是否按下了任何修改键。 If they were, the action is silently ignored. 如果是,那么行动就会被默默地忽略。


Step 1: Create a custom TextAction in Java to ignore modifier keys 步骤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;
    }
}

Compile to a .jar : 编译为.jar

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

Step 2: Override MATLAB's default Keymap handler in both the command window and editor (from within MATLAB) 第2步:在命令窗口和编辑器中覆盖MATLAB的默认Keymap处理程序(在MATLAB中)

The hardest part here is getting the java handles to the command window and editor. 这里最难的部分是获取命令窗口和编辑器的java句柄。 It is dependent upon the layout and classnames of the individual editor panes. 它取决于各个编辑器窗格的布局和类名。 This may change between versions of Matlab. 这可能会在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! 现在可以在标准首选项窗口中定义使用选项键的键绑定!


Step 3 (optional): Remove the custom action 步骤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')

I don't have a complete solution, but I have some possible approaches you can try, if you haven't looked at them yet. 我没有一个完整的解决方案,但如果你还没有看过它,我有一些你可以尝试的方法。

MATLAB's keyboard shorcuts are saved in an XML file in /Users/$user/.matlab/$version/$name_keybindings.xml , where $user is your user name, $version the version of MATLAB and $name is whatever you've saved the keybindings as. MATLAB的键盘shorcuts保存在一个XML文件/Users/$user/.matlab/$version/$name_keybindings.xml ,其中$user是你的用户名, $version MATLAB的版本和$name是您保存任何键绑定为。 It looks something like this 它看起来像这样

<?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>

I tried changing the derivedfrom value to EmptyBaseSet to see what happens. 我尝试将derivedfrom值更改为EmptyBaseSet以查看会发生什么。 As expected, none of the shortcuts work, but Opt - character still reproduced a unicode character. 正如预期的那样,没有一个快捷方式可以工作,但Opt - character仍然会复制一个unicode角色。 This seems indicates that the Opt-f or any option based shortcut behaviour is due to Mac, and out of MATLAB's hands. 这似乎表明Opt-f或任何基于选项的快捷方式行为都归功于Mac,并且不在MATLAB手中。 It's the Windows equivalent of pressing Alt +numpad keys for unicode characters. 这是Windows相当于按下Alt +小键盘的unicode字符。 If MATLAB knew about the option shortcuts, it would indicate a possible conflict in MATLAB>Preferences>Keyboard>Shortcuts , but it doesn't. 如果MATLAB知道选项快捷方式,则表明MATLAB>Preferences>Keyboard>Shortcuts可能存在冲突,但事实并非如此。 I don't know enough XML to tell you whether or not you can disable Opt-f = ƒ by editing this file. 我不知道足够的XML告诉你是否可以通过编辑这个文件来禁用Opt-f = ƒ

My guess is that there is a very high probability that Apple has ensured that applications don't get to tinker very much with this feature, as several non-English (German/Slavic/Latin) languages use these keyboard shortcuts very often. 我的猜测是,Apple很有可能确保应用程序不会对此功能进行修补,因为一些非英语(德语/斯拉夫语/拉丁语)语言经常使用这些键盘快捷键。

An alternate option is to try Ukelele , which is a keyboard layout editor for macs. 另一种选择是尝试Ukelele ,这是一个用于mac的键盘布局编辑器。 There have been questions on SO and related sites, where they've used Ukelele to remap dead keys , another example for dead keys , configure the left & right Cmd differently , swapping € and $ , etc. You can try redefining your keyboard layout to disable Opt-f (unless if you need that particular character outside of MATLAB), which should solve the problem. 在SO和相关网站上存在一些问题,他们使用Ukelele 重新映射死键另一个 死键 示例,以 不同方式配置左右Cmd交换€和$等。您可以尝试重新定义键盘布局禁用Opt-f (除非您需要MATLAB之外的特定字符),这应该可以解决问题。

Lastly, I don't mean to be saying "you should be doing something else" when the question is "how do I do this?", but in general, with macs, I've found mapping Ctrl to the windows/emacs Alt shortcuts to be easier than Opt . 最后,当问题是“我该怎么做?”时,我并不是说“你应该做其他事情”,但一般来说,使用macs,我发现将Ctrl映射到windows / emacs Alt快捷方式比Opt更容易。 Mostly, for the very same reasons, and also because Opt is so damn close to the Cmd key on my laptop that my fat fingers end up pressing Cmd when I don't mean to (it never happens the other way around). 大多数情况下,出于同样的原因,也因为Opt非常接近我的笔记本电脑上的Cmd键,我的胖手指在我不想要的时候最终按下Cmd (它从来没有发生过相反的情况)。

As request an ugly workaround: I am not working on MacOS, so I am entering the realms of "maybe a good tip": Under X exist tools which can capture X-events and execute commands on demand, a quick google gave that eg xkbevd also exist under MacOS (and I assume the java tool you mentioned does something similar). 作为请求一个丑陋的解决方法:我没有在MacOS上工作,所以我进入了“可能是一个好的提示”的领域:在X下存在可以捕获X事件并按需执行命令的工具,快速谷歌给了例如xkbevd也存在于MacOS下(我假设您提到的java工具做了类似的事情)。 There you could maybe catch the ctrl-f and replace it with ctrl-f backspace so you negate the additional character. 在那里你可以捕获ctrl-f并用ctrl-f退格替换它,这样你就可以否定附加字符。 (Very ugly, and it breaks those codes outside matlab). (非常难看,它在matlab之外打破了那些代码)。

Another option in case you dont want to change the behaviour on the commandline, but just in the editor - use external editor: you can define in the preferences another, different from the default. 如果您不想更改命令行上的行为,而只是在编辑器中使用外部编辑器,则可以使用另一个选项:您可以在首选项中定义另一个,与默认值不同。 There you can chose emacs, vi, or whatever suits you (and where the remapping works) 在那里你可以选择emacs,vi或任何适合你的地方(以及重映射的工作地点)

BTW: Under Linux this problem doesnt exist with matlab, so it looks like its really MacOS specific. 顺便说一句:在Linux下这个问题与matlab不存在,所以看起来它真的是MacOS特有的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM