Mac OS X Key Bindings
Home
Blog
Articles
Papers
Software
Resume

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

Unfortunately, this file is XML and is very painful to read. You shouldn't touch this file anyway, and you should make your modifications by creating the file where USERNAME is the name of your user account. If the KeyBindings directory doesn't exist then you should create it. Note that the file name differs between the system default (StandardKeyBinding.dict) and the user override (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

Apple Documentation - Text Defaults And Bindings

Apple Documentation - NSResponder supported actions

Copyright © 2007 Llew Mason All rights reserved.