Mat*_* B. 14 java matlab swing keyboard-shortcuts
自R2009b起,MATLAB通过其键盘快捷键首选项获得了非常出色的键盘快捷键.这非常适合在Mac上使用命令和控件自定义快捷方式.
不幸的是,那些键绑定似乎无法覆盖MATLAB的内置字符映射.例如,如果我将option-f定义为cursor-next-word(a la emacs),则它接受绑定.按下组合键可以将光标正确移动到下一个单词,但它还可以打印ƒ字符!我相信这是来自角色地图(也许与输入地图相对?).无论EditorMacro也不键绑定能够覆盖此行为.
我从一个与我相关的问题中偶然发现了这个问题.简而言之,他定义了一个Java类,它可以处理键盘事件并用其他键击输入替换它们.但是,该解决方案仅适用于Windows上的规定.要在Mac上运行,需要进行以下修改:
我需要将密钥代码更改为重新映射以在字符串中"按下",如下所示:
map = {
'$' '^'
'#' char(181) % might be useful for text formatting
};
Run Code Online (Sandbox Code Playgroud)
至:
map = {
'alt pressed F' '^'
'alt pressed B' char(181) % might be useful for text formatting
};
Run Code Online (Sandbox Code Playgroud)
不幸的是,在运行代码之后,按下选项-f yield cursor-next-word和ƒ字符,就像之前一样.但是,如果我cursor-next-word从首选项中禁用绑定,那么我得到两个 ƒ和^!实际上,即使我使用类似的简单动作pressed F,KeyReplacementAction也不会取代动作,而是增加动作.看起来这种行为对OS X上的MATLAB来说是独一无二的.
好像我只是没有覆盖正确的键盘映射.我已经尝试过挖掘Java运行时,但我对事件调度模型不太熟悉,知道接下来要去哪里看.也许是Java的OS级关键映射中的某些内容?
编辑:我已经做了更多的挖掘.似乎Mac版的MATLAB没有正确地遵守keyEvent的'consume'属性.我可以KeyReplacementAction重视无论是inputMap或keymap,在上述两种情况下,我增加了按键绑定,而不是替换它.我使用反射'取消保护' consume()AWTEvents 的方法,但效果和以前一样.
在堆栈跟踪之后,看起来好像keyEvent正在落入一个实例javax.swing.KeyboardManager.看起来我应该能够取消绑定KeyboardManager中的键击,但我无法弄清楚如何从我的MATLAB句柄访问该实例.也许更熟悉Swing的事件模型和Java调试器的人可能会更进一步.
编辑2:flolo的回答促使我研究X11的键盘图.几点说明:
~/.Xmodmap或任何当前加载的模式映射.$XKEYSYMDB如果环境变量在启动时存在,它将使用它.否则,它从中加载它$MATLAB/X11/app-defaults/XKeysymDB.$MATLAB/X11/app-defaults/目录看起来很有趣; 或许有些hackery可以使这项工作?编辑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 如何处理按键事件的知识:
inputMap以查看是否存在该击键的绑定。
actionPerformed方法actionMap,然后分派该操作的actionPerformed方法Keymap.getDefaultAction(). 问题就出在这里。此解决方案使用包装器覆盖键盘映射的默认操作,该包装器仅检查是否按下了任何修饰键。如果是的话,该操作将被默默地忽略。
第 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;
}
}
Run Code Online (Sandbox Code Playgroud)
编译为.jar:
javac IgnoreModifiedKeystrokesAction.java && jar cvf IgnoreModifiedKeystrokesAction.jar IgnoreModifiedKeystrokesAction.class
Run Code Online (Sandbox Code Playgroud)
步骤 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
Run Code Online (Sandbox Code Playgroud)
现在可以在使用选项键的标准首选项窗口中定义键绑定!
步骤 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')
Run Code Online (Sandbox Code Playgroud)