[英]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. EditorMacro和KeyBindings都无法覆盖此行为。
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附加到inputMap
或keymap
,在这两种情况下我都会增加键绑定而不是替换它。 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. 编辑2 : flolo的回答促使我研究X11的键盘图。 Several notes: 几点说明:
~/.Xmodmap
or any currently-loaded modmaps. Matlab似乎不尊重~/.Xmodmap
或任何当前加载的modmaps。 $XKEYSYMDB
environment variable if it exists at startup. 如果$XKEYSYMDB
环境变量在启动时存在,它将使用它。 Otherwise, it loads it from $MATLAB/X11/app-defaults/XKeysymDB
. 否则,它从$MATLAB/X11/app-defaults/XKeysymDB
加载它。 $MATLAB/X11/app-defaults/
directory looks very interesting; 整个$MATLAB/X11/app-defaults/
目录看起来非常有趣; perhaps some hackery there could make this work? 或许有些hackery可以使这项工作? 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如何处理按键事件的了解:
inputMap
is searched to see if there's a binding for that keystroke. 搜索活动文本组件的inputMap
以查看是否存在该键击的绑定。
actionPerformed
method 如果有一个绑定到该击键的动作,则调度该动作的actionPerformed
方法 actionMap
, and then dispatch that action's actionPerformed
method 如果有一个与该击键相关联的字符串,请从文本组件的actionMap
找到该操作,然后调度该操作的actionPerformed
方法 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.