繁体   English   中英

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

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

自R2009b起,MATLAB通过其键盘快捷键首选项获得了非常出色的键盘快捷 这非常适合在Mac上使用命令和控件自定义快捷方式。

不幸的是,那些键绑定似乎无法覆盖MATLAB的内置字符映射。 例如,如果我将option-f定义为cursor-next-word (la emacs),则它接受绑定。 按下组合键可以正确地将光标移动到下一个单词,但它还会打印ƒ字符! 我相信这是来自角色地图(也许与输入地图相对?)。 EditorMacroKeyBindings都无法覆盖此行为。

从一个与相关的问题中偶然发现了这个问题 简而言之,他定义了一个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
};

不幸的是,在运行代码之后,按下option-f会产生cursor-next-wordƒ字符,就像之前一样。 但是,如果我禁用cursor-next-word从喜好结合,然后我得到两个 ƒ^ 实际上,即使我使用像pressed F一样的简单动作,KeyReplacementAction也不会取代动作,而是会增加动作。 看起来这种行为对OS X上的MATLAB来说是独一无二的。

好像我只是没有覆盖正确的键盘映射。 我已经尝试过挖掘Java运行时,但我对事件调度模型不太熟悉,知道接下来要去哪里看。 也许是Java的OS级关键映射中的某些内容?


编辑 :我已经做了更多的挖掘。 似乎Mac版的MATLAB没有正确地遵守keyEvent的'consume'属性。 我可以将KeyReplacementAction附加到inputMapkeymap ,在这两种情况下我都会增加键绑定而不是替换它。 我使用反射'unprotect'为AWTEvents的consume()方法,但效果与以前相同。

在堆栈跟踪之后,似乎keyEvent正在落入javax.swing.KeyboardManager的实例。 看起来我应该能够取消绑定KeyboardManager中的键击,但我无法弄清楚如何从我的MATLAB句柄访问该实例。 也许更熟悉Swing的事件模型和Java调试器的人可能会更进一步。


编辑2flolo的回答促使我研究X11的键盘图。 几点说明:

  • Matlab似乎不尊重~/.Xmodmap或任何当前加载的modmaps。
  • 如果$XKEYSYMDB环境变量在启动时存在,它将使用它。 否则,它从$MATLAB/X11/app-defaults/XKeysymDB加载它。
  • 整个$MATLAB/X11/app-defaults/目录看起来非常有趣; 或许有些hackery可以使这项工作?
  • Mac上的X11的键盘布局? MATLAB如何切换到国际键盘布局?

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


编辑4 :MATLAB确实使用系统键盘布局。 我创建了一个没有任何绑定为RM建议。 这似乎有效 - MATLAB确实表现得很好。 不幸的是,它也破坏了我在所有其他程序中的自定义Cocoa键绑定。 关闭,但没有雪茄。 (实际上,足够接近,RM因为一直认为它已经奏效而赢得了+500赏金......直到我试图撰写我的祝贺评论并发现我无法照常浏览文本字段。)

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

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

  1. 按下按键。
  2. 搜索活动文本组件的inputMap以查看是否存在该键击的绑定。
    • 如果有一个绑定到该击键的动作,则调度该动作的actionPerformed方法
    • 如果有一个与该击键相关联的字符串,请从文本组件的actionMap找到该操作,然后调度该操作的actionPerformed方法
  3. 无论如何 ,作为最后一步,调度在文本组件的Keymap.getDefaultAction()找到的动作。 这就是问题所在。

此解决方案使用包装器覆盖Keymap的默认操作,该包装器只检查是否按下了任何修改键。 如果是,那么行动就会被默默地忽略。


步骤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的默认Keymap处理程序(在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')

我没有一个完整的解决方案,但如果你还没有看过它,我有一些你可以尝试的方法。

MATLAB的键盘shorcuts保存在一个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仍然会复制一个unicode角色。 这似乎表明Opt-f或任何基于选项的快捷方式行为都归功于Mac,并且不在MATLAB手中。 这是Windows相当于按下Alt +小键盘的unicode字符。 如果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 (它从来没有发生过相反的情况)。

作为请求一个丑陋的解决方法:我没有在MacOS上工作,所以我进入了“可能是一个好的提示”的领域:在X下存在可以捕获X事件并按需执行命令的工具,快速谷歌给了例如xkbevd也存在于MacOS下(我假设您提到的java工具做了类似的事情)。 在那里你可以捕获ctrl-f并用ctrl-f退格替换它,这样你就可以否定附加字符。 (非常难看,它在matlab之外打破了那些代码)。

如果您不想更改命令行上的行为,而只是在编辑器中使用外部编辑器,则可以使用另一个选项:您可以在首选项中定义另一个,与默认值不同。 在那里你可以选择emacs,vi或任何适合你的地方(以及重映射的工作地点)

顺便说一句:在Linux下这个问题与matlab不存在,所以看起来它真的是MacOS特有的。

暂无
暂无

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

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