让普通Mac程序也能使用emacs的键绑定

最近给mac配了一个码农神器HHKB Pro 2键盘,然后在AppCode中配置Emacs键绑定的时候发现Emacs的键绑定在Mac下不好使,搜了一下他们官方的说法,是因为AppCode以及其他JetBrain公司的产品的Emacs键绑定最初就不是给Mac设计的,所以在Mac下使用option + 字符按钮会使用系统默认设置,而不会触发编辑器的动作。
然后搜这个解决方案的时候无意中找到mac可以修改按键的键绑定,而这个改动可以应用到几乎所有使用Cocoa Text的应用程序,方法是创建 ~/Library/KeyBindings目录,编辑~/Library/KeyBindings/DefaultKeyBinding.dict文件,内容为:

/* ~/Library/KeyBindings/DefaultKeyBinding.dict */
{
/* Keybindings for emacs emulation.  Compiled by Jacob Rus.
 *
 * This is a pretty good set, especially considering that many emacs bindings
 * such as C-o, C-a, C-e, C-k, C-y, C-v, C-f, C-b, C-p, C-n, C-t, and
 * perhaps a few more, are already built into the system.
 *
 * BEWARE:
 * This file uses the Option key as a meta key.  This has the side-effect
 * of overriding Mac OS keybindings for the option key, which generally
 * make common symbols and non-english letters.
 */

    /* Ctrl shortcuts */
    "^l"        = "centerSelectionInVisibleArea:";  /* C-l          Recenter */
    "^/"        = "undo:";                          /* C-/          Undo */
    "^_"        = "undo:";                          /* C-_          Undo */
    "^\@"       = "setMark:";                       /* C-@          Set mark */

    /*Edit*/
    "^t"    = "transpose:";                 /* C-t */
    "~t"    = "transposeWords:";            /* M-t */
    "~/"    = "complete:";                  /* M-/ */
    "^g"    = "_cancelKey:";                /* C-g */
    "^a"    = "moveToBeginningOfLine:";     /* C-a */
    "^e"    = "moveToEndOfLine:";           /* C-e */
    "~w"    = "copy:";                      /* M-w */
    "^w"    = "cut:";                       /* C-w */
    "^k"    = "deleteToEndOfLine:";          /* C-k */
    "^y"    = "paste:";                     /* C-y */
    /* Incremental search. */
/* Uncomment these lines If Incremental Search IM is installed */
/*  "^s"        = "ISIM_incrementalSearch:";        /* C-s          Incremental search */
/*  "^r"        = "ISIM_reverseIncrementalSearch:"; /* C-r          Reverse incremental search */
/*  "^g"        = "abort:";                         /* C-g          Abort */


    /* Meta shortcuts */
    "~f"        = "moveWordForward:";               /* M-f          Move forward word */
    "~b"        = "moveWordBackward:";              /* M-b          Move backward word */
    "~<"        = "moveToBeginningOfDocument:";     /* M-<          Move to beginning of document */
    "~>"        = "moveToEndOfDocument:";           /* M->          Move to end of document */
    "~v"        = "pageUp:";                        /* M-v          Page Up */
    "~/"        = "complete:";                      /* M-/          Complete */
    "~c"        = ( "capitalizeWord:",              /* M-c          Capitalize */
                    "moveForward:",
                    "moveForward:");
    "~u"        = ( "uppercaseWord:",               /* M-u          Uppercase */
                    "moveForward:",
                    "moveForward:");
    "~l"        = ( "lowercaseWord:",               /* M-l          Lowercase */
                    "moveForward:",
                    "moveForward:");
    "~d"        = "deleteWordForward:";             /* M-d          Delete word forward */
    "^~h"       = "deleteWordBackward:";            /* M-C-h        Delete word backward */
    "~\U007F"   = "deleteWordBackward:";            /* M-Bksp       Delete word backward */
    "~t"        = "transposeWords:";                /* M-t          Transpose words */
    "~\@"       = ( "setMark:",                     /* M-@          Mark word */
                    "moveWordForward:",
                    "swapWithMark");
    "~h"        = ( "setMark:",                     /* M-h          Mark paragraph */
                    "moveToEndOfParagraph:",
                    "swapWithMark");

    /* C-x shortcuts */
    "^x" = {
        "u"     = "undo:";                          /* C-x u        Undo */
        "k"     = "performClose:";                  /* C-x k        Close */
        "^f"    = "openDocument:";                  /* C-x C-f      Open (find file) */
        "^x"    = "swapWithMark:";                  /* C-x C-x      Swap with mark */
        "^m"    = "selectToMark:";                  /* C-x C-m      Select to mark*/
        "^s"    = "saveDocument:";                  /* C-x C-s      Save */
        "^w"    = "saveDocumentAs:";                /* C-x C-w      Save as */
    };

}

这里^表示Control,~表示option/meta按键,后面对应的操作是NSResponder类的selector,完整的可以参考Apple的文档
保存后重启下电脑,或者重启下程序即可生效。
我重启了AppCode之后发现这个方法可以让AppCode的Emacs键绑定生效了,不光如此,其他程序里也可以使用emacs的键绑定了。


Last modified on 2014-08-29