簡體   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