Mac – Emacs key bindings on other programs

emacskeybindingskeyboardproductivity

I am a heavy Emacs user and would love to have some of my Emacs keyboard bindings when editing text on other apps.

I understand I could program these macros with Keyboard Maestro manually, but I was surprised I could not find any pre-defined macros for this. Before I reinvent the wheel, are there any repositories of keyboard maestro macros out there? Does Keyboard Maestro come with any set of macros that facilitate this process?

Best Answer

Keyboard Maestro macros often have noticeable delays and it's not really the best method for keyboard remapping.

You could create ~/Library/KeyBindings/ and save a property list like this as DefaultKeyBinding.dict instead:

{
  "~b" = moveWordBackward:;
  "~f" = moveWordForward:;
  "~F" = moveWordForwardAndModifySelection:;
  "~B" = moveWordForwardAndModifySelection:;
  "~d" = deleteWordForward:;
  "~u" = (uppercaseWord:, moveForward:, moveForward:);
  "~l" = (lowercaseWord:, moveForward:, moveForward:);
  "~c" = (capitalizeWord:, moveForward:, moveForward:);
  "~v" = pageUp:;
  "~V" = pageUpAndModifySelection:;
  "^V" = pageDownAndModifySelection:;
  "^ " = setMark:;
  "^w" = deleteToMark:;
  "~<" = moveToBeginningOfDocument:;
  "~>" = moveToEndOfDocument:;
  "~/" = complete:;
  "^l" = selectParagraph:;
  "~h" = selectParagraph:;
  "^_" = undo:;
  "^/" = undo:;
  "^x" = {
    "^x" = swapWithMark:;
    "^m" = selectToMark:;
  };
}

DefaultKeyBinding.dict doesn't work in some applications like Xcode or Firefox. Key combinations that enter dead key states (like ⌥U in the U.S. keyboard layout) can't be reassigned. There are also methods like performClose: and openDocument:, but they don't work in all applications. See http://www.hcs.harvard.edu/~jrus/site/KeyBindings/Emacs%20Esc%20Bindings.dict or http://www.hcs.harvard.edu/~jrus/site/selectors.html.

Another option is to use a private.xml like this with KeyRemap4Macbook:

<?xml version="1.0"?>
<root>
  <item>
    <name>test</name>
    <identifier>test</identifier>
    <not>{{EMACS_MODE_IGNORE_APPS}}</not>
    <autogen>__KeyToKey__ KeyCode::P, VK_CONTROL | ModifierFlag::NONE, KeyCode::CURSOR_UP</autogen>
    <autogen>__KeyToKey__ KeyCode::N, VK_CONTROL | ModifierFlag::NONE, KeyCode::CURSOR_DOWN</autogen>
    <autogen>__KeyToKey__ KeyCode::B, VK_CONTROL | ModifierFlag::NONE, KeyCode::CURSOR_LEFT</autogen>
    <autogen>__KeyToKey__ KeyCode::F, VK_CONTROL | ModifierFlag::NONE, KeyCode::CURSOR_RIGHT</autogen>
    <autogen>__KeyToKey__ KeyCode::P, VK_CONTROL | VK_SHIFT | ModifierFlag::NONE, KeyCode::CURSOR_UP, VK_SHIFT</autogen>
    <autogen>__KeyToKey__ KeyCode::N, VK_CONTROL | VK_SHIFT | ModifierFlag::NONE, KeyCode::CURSOR_DOWN, VK_SHIFT</autogen>
    <autogen>__KeyToKey__ KeyCode::B, VK_CONTROL | VK_SHIFT | ModifierFlag::NONE, KeyCode::CURSOR_LEFT, VK_SHIFT</autogen>
    <autogen>__KeyToKey__ KeyCode::F, VK_CONTROL | VK_SHIFT | ModifierFlag::NONE, KeyCode::CURSOR_RIGHT, VK_SHIFT</autogen>
    <autogen>__KeyToKey__ KeyCode::B, VK_OPTION | ModifierFlag::NONE, KeyCode::CURSOR_LEFT, VK_OPTION</autogen>
    <autogen>__KeyToKey__ KeyCode::F, VK_OPTION | ModifierFlag::NONE, KeyCode::CURSOR_RIGHT, VK_OPTION</autogen>
    <autogen>__KeyToKey__ KeyCode::B, VK_OPTION | VK_SHIFT | ModifierFlag::NONE, KeyCode::CURSOR_LEFT, VK_OPTION | VK_SHIFT</autogen>
    <autogen>__KeyToKey__ KeyCode::F, VK_OPTION | VK_SHIFT | ModifierFlag::NONE, KeyCode::CURSOR_RIGHT, VK_OPTION | VK_SHIFT</autogen>
    <autogen>__KeyToKey__ KeyCode::D, VK_OPTION | ModifierFlag::NONE, KeyCode::FORWARD_DELETE, VK_OPTION</autogen>
    <autogen>__KeyToKey__ KeyCode::V, VK_OPTION | ModifierFlag::NONE, KeyCode::PAGEUP</autogen>
    <autogen>__KeyToKey__ KeyCode::V, VK_OPTION | VK_SHIFT | ModifierFlag::NONE, KeyCode::PAGEUP, VK_SHIFT</autogen>
    <autogen>__KeyToKey__ KeyCode::V, VK_CONTROL | VK_SHIFT | ModifierFlag::NONE, KeyCode::PAGEDOWN, VK_SHIFT</autogen>
  </item>
</root>

The key codes have to be changed for keyboard layouts like Dvorak or Colemak. EMACS_MODE_IGNORE_APPS includes terminal emulators, Emacs applications, and VMs, but you can also add custom appdef elements.

There is also a predefined Emacs mode group, but for example the setting for changing ⌥F to ⌥→ also changes ⌥⌘F to ⌥⌘→.