Mac OS X Key Bindings
April 24 2005 (Updated May 16 2008)I recently wanted to change some key bindings on Mac OS X. After spending a lot of time searching I found the information that I needed. However, the information was spread across several different sites. This article aims to collect all of the information that I found in a single document.
Mac OS X allows for some powerful control over key bindings. The method I describe below allows you to modify the key binding behavior for every program that uses the standard Cocoa AppKit text edit objects.
The default key bindings are stored in
-
/System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict.
-
/Users/USERNAME/Library/KeyBindings/DefaultKeyBinding.dict.
The non-XML file format is basically key / action pairs:
/* ~/Library/KeyBindings/DefaultKeyBinding.dict */
{
"KEY1" = "ACTION1"; /* Bind KEY1 to ACTION1 */
"KEY2" = "ACTION2"; /* Bind KEY2 to ACTION2 */
...
}
An example is shown below:
/* ~/Library/KeyBindings/DefaultKeyBinding.dict */
{
"^f" = "moveWordForward:"; /* Ctrl-f = next word */
"^b" = "moveWordBackward:"; /* Ctrl-b = previous word */
"^v" = "pageUp:"; /* Ctrl-v = page up */
"\UF729" = "moveToBeginningOfLine:"; /* Home = start of line */
"^\UF729" = "moveToBeginningOfDocument:"; /* Ctrl-Home = start of doc */
}
A key is defined either as a printable key character (e.g., "a"), or a non-printable key character in either octal (e.g, "\177" for delete) or Unicode (e.g., "\UF700" for up arrow) encoding. The key can be preceded by one or more key 'modifiers':
Key Modifiers ^ : Ctrl $ : Shift ~ : Option (Alt) @ : Command (Apple) # : Numeric Keypad
For example, Control-Shift-Home would be "^$\UF729", and Command-a would be "@a". I've had some issues with the ordering of these key modifiers on OS X 10.5 Leopard. For example, "$^\UF703" (Ctrl-Shift Right Arrow) doesn't work, but "^$\UF703" does. If you are combining multiple modifiers and it doesn't work, try reordering them.
A list of the most common non-printable key codes is shown below. A complete list can be found in the NSEvent.h header file.
Non-Printable Key Codes Up Arrow: \UF700 Backspace: \U0008 F1: \UF704 Down Arrow: \UF701 Tab: \U0009 F2: \UF705 Left Arrow: \UF702 Escape: \U001B F3: \UF706 Right Arrow: \UF703 Enter: \U000A ... Insert: \UF727 Page Up: \UF72C Delete: \UF728 Page Down: \UF72D Home: \UF729 Print Screen: \UF72E End: \UF72B Scroll Lock: \UF72F Break: \UF732 Pause: \UF730 SysReq: \UF731 Menu: \UF735 Help: \UF746
An action is simply a specific string denoting the action. A list of the most common supported actions is shown below. Note the colon at the end of each action. This is required.
Supported Actions alignCenter: newDocument: alignJustified: openDocument: alignLeft: orderBack: alignRight: orderFront: breakUndoCoalescing orderFrontLinkPanel: cancelOperation: orderFrontListPanel: capitalizeWord: orderFrontSpacingPanel: center orderFrontTablePanel: centerSelectionInVisibleArea: outline: changeCaseOfLetter: pageDown: checkSpelling: pageUp: clearRecentDocuments: paste: complete: pasteAsPlainText: copy: pasteAsRichText: copyFont: pasteFont: copyRuler: pasteRuler: cut: performClose: delete: performMiniaturize: deleteBackward: performZoom: deleteBackwardByDecomposingPreviousCharacter: printDocument: deleteForward: raiseBaseline: deleteToBeginningOfLine: revertDocumentToSaved: deleteToBeginningOfParagraph: runPageLayout: deleteToEndOfLine: saveAllDocuments: deleteToEndOfParagraph: saveDocument: deleteToMark: saveDocumentAs: deleteWordBackward: saveDocumentTo: deleteWordForward: scrollLineDown: hide: scrollLineUp: ignoreSpelling: scrollPageDown: indent: scrollPageUp: insertBacktab: selectAll: insertContainerBreak: selectLine: insertLineBreak: selectParagraph: insertNewline: selectToMark: insertNewlineIgnoringFieldEditor: selectWord: insertParagraphSeparator: setMark: insertTab: showContextHelp: insertTabIgnoringFieldEditor: showGuessPanel: insertText: startSpeaking: loosenKerning: stopSpeaking: lowerBaseline: subscript: lowercaseWord: superscript: moveBackward: swapWithMark: moveBackwardAndModifySelection: terminate: moveDown: tightenKerning: moveDownAndModifySelection: toggleBaseWritingDirection: moveForward: toggleContinuousSpellChecking: moveForwardAndModifySelection: toggleRuler: moveLeft: transpose: moveLeftAndModifySelection: transposeWords: moveRight: turnOffKerning: moveRightAndModifySelection: turnOffLigatures: moveToBeginningOfDocument: underline: moveToBeginningOfDocumentAndModifySelection: unscript: moveToBeginningOfLine: uppercaseWord: moveToBeginningOfLineAndModifySelection: useAllLigatures: moveToBeginningOfParagraph: useStandardKerning: moveToEndOfDocument: useStandardLigatures: moveToEndOfDocumentAndModifySelection: yank: moveToEndOfLineAndModifySelection: moveToEndOfLine: moveToEndOfParagraph: moveUp: moveUpAndModifySelection: moveWordBackward: moveWordBackwardAndModifySelection: moveWordForward: moveWordForwardAndModifySelection: moveWordLeft: moveWordLeftAndModifySelection: moveWordRight: moveWordRightAndModifySelection:
There are two other variants of entries that allow you to do multi-key bindings and to bind a key to a sequence of actions.
/* ~/Library/KeyBindings/DefaultKeyBinding.dict */
{
/* Bind KEY1 to ACTION1 and ACTION2 */
"KEY1" = ("ACTION1", "ACTION2", ...);
/* Multi-key bindings */
"KEY1" = {
/* Bind KEY1 followed by KEY2 to ACTION1 */
"KEY2" = "ACTION1";
/* Bind KEY1 followed by KEY3 to ACTION2 */
"KEY3" = "ACTION2";
...
};
...
}
An example is shown below:
/* ~/Library/KeyBindings/DefaultKeyBinding.dict */
{
/* An example of binding a sequence of actions to a single key.
Bind Control-Shift-Home to select the region from the cursor to the
beginning of the line. Windows-style Control-Shift-Home. */
"$\UF729" = ("setMark:","moveToBeginningOfLine:","selectToMark:");
/* An example of binding a sequence of keys to an action.
Bind Control-x Control-s to save. Emacs style C-x C-s. */
"^x" = { "^s" = "save:"; }
}
Examples
An example key binding file for partial Windows emulation.
/* ~/Library/KeyBindings/DefaultKeyBinding.dict */
{
"^\010" = "deleteWordBackward:";
"\UF729" = "moveToBeginningOfLine:";
"^\UF729" = "moveToBeginningOfDocument:";
"$\UF729" = "moveToBeginningOfLineAndModifySelection:";
"^$\UF729" = "moveToBeginningOfDocumentAndModifySelection:";
"\UF72B" = "moveToEndOfLine:";
"^\UF72B" = "moveToEndOfDocument:";
"$\UF72B" = "moveToEndOfLineAndModifySelection:";
"^$\UF72B" = "moveToEndOfDocumentAndModifySelection:";
"^\UF702" = "moveWordLeft:";
"^\UF703" = "moveWordRight:";
"\UF72C" = "pageUp:";
"\UF72D" = "pageDown:";
"^z" = "undo:";
"$\UF728" = "cut:";
"$\UF746" = "paste:";
"^\UF746" = "copy:";
"$\UF700" = "moveUpAndModifySelection:";
"$\UF701" = "moveDownAndModifySelection:";
"$\UF702" = "moveLeftAndModifySelection:";
"$\UF703" = "moveRightAndModifySelection:";
"^$\UF702" = "moveWordLeftAndModifySelection:";
"^$\UF703" = "moveWordRightAndModifySelection:";
}
An example key binding file for partial Emacs emulation.
/* ~/Library/KeyBindings/DefaultKeyBinding.dict */
/* The original bindings are from Mike Ferris of lorax.com as shipped
* with his TextExtras package. They were further modified by Mishka Gorodnitzky
* (misaka@pobox.com), Patrick Linskey, and Llew Mason.
*/
{
"~f" = "moveWordForward:"; /* M-f */
"~b" = "moveWordBackward:"; /* M-b */
"~<" = "moveToBeginningOfDocument:"; /* M-< */
"~>" = "moveToEndOfDocument:"; /* M-> */
"~v" = "pageUp:"; /* M-v */
"^v" = "pageDown:"; /* C-v */
"~d" = "deleteWordForward:"; /* M-d */
"~^h" = "deleteWordBackward:"; /* M-C-h */
"~\010" = "deleteWordBackward:"; /* M-backspace */
"~\177" = "deleteWordBackward:"; /* M-delete */
"~\UF728" = "deleteWordForward:"; /* delete */
"\UF729" = "moveToBeginningOfDocument:"; /* home */
"\UF72B" = "moveToEndOfDocument:"; /* end */
"@\UF729" = "moveToBeginningOfParagraph:"; /* A-home */
"@\UF72B" = "moveToEndOfParagraph:"; /* A-end */
"@\UF700" = "moveToBeginningOfDocument:"; /* A-up */
"@\UF701" = "moveToEndOfDocument:"; /* A-down */
"^\UF700" = "pageUp:"; /* C-up */
"^\UF701" = "pageDown:"; /* C-down */
"\UF72C" = "pageUp:"; /* page-up */
"\UF72D" = "pageDown:"; /* page-down */
"^/" = "undo:"; /* C-/ */
"~c" = "capitalizeWord:"; /* M-c */
"~u" = "uppercaseWord:"; /* M-u */
"~l" = "lowercaseWord:"; /* M-l */
"^t" = "transpose:"; /* C-t */
"~t" = "transposeWords:"; /* M-t */
"~/" = "complete:"; /* M-/ */
"^g" = "_cancelKey:"; /* C-g */
"^a" = "moveToBeginningOfLine:"; /* C-a */
"^e" = "moveToEndOfLine:"; /* C-e */
"^x" = {
"^x" = "swapWithMark:"; /* C-x C-x */
"^m" = "selectToMark:"; /* C-x C-m */
"^s" = "save:"; /* C-x C-s */
"^w" = "saveAs:"; /* C-x C-w */
"k" = "performClose:"; /* C-x C-k */
};
/* Mark-point stuff (Emacs-style mark and point bindings are
* implemented but not bound by default. In the text system the
* mark and point are ranges, not just locations. The "point" is
* the selected range.)
*/
"^@" = "setMark:"; /* C-@ */
"^ " = "setMark:"; /* C-space */
"^w" = "deleteToMark:"; /* C-w */
/* Mac Style F1-F5 bindings */
"\UF704" = "undo:"; /* F1 */
"\UF705" = "cut:"; /* F2 */
"\UF706" = "copy:"; /* F3 */
"\UF707" = "paste:"; /* F4 */
"\UF708" = "_cancelKey:"; /* F5 */
}
Links
Customizing the Cocoa Text System by Jacob Rus
TextMate Blog - Key bindings for switchers