Saturday, April 26, 2008

Fixing up the Mac Key Bindings for Windows Users

[Note: Edited on 2010-02 to switch the order of the shift and command key modifiers.  Apparently, Mac OS is particular about the order.]

[Edited on 2010-10-22 to describe how to use TextEdit to apply this key mapping]
[Edited on 2010-11-12 to mention that TextEdit sometimes adds a .txt extension]


I'm a longtime Windows user who recently purchased a Macbook. Overall I'm very impressed with the machine, but it does have a learning curve, especially for the key bindings.

The first thing I noticed was that the Macbook does not have the Del and Ins keys at all, and the Home, End, PageUp and PageDown keys require pressing 'Fn' and then an Arrow key (which is understandable because the keyboard on a small Macbook is somewhat cramped -- also, I've asked a couple users who have not used PCs much before using a Mac, and they did not even know these keys existed, or what they would do with them)

However, when I'm not on the road, I like to use a nice full sized Microsoft Natural Keyboard, to reduce tendinitis. As a (former) hard-core programmer, I very extensively use the Home, End, PageUp and PageDown keys to quickly navigate code or text documents. I was very dismayed to discover that Apple pretty much doesn't do anything with these keys.

In hunting through all the configuration options, I noticed that you can reconfigure a lot of key mappings through the System Preferences utility (go to the apple in the upper-left corner, select System Preferences..., click on Keyboard & Mouse, and click the Keyboard Shortcuts tab). This was useful for a start, but I quickly determined that the Mac wouldn't allow me to bind keys to any of the 6 special keys (Home, End, PageUp, PageDown, Delete, Insert). This made me sad.

I did discover, however, that it is possible to switch the Control and Command keys. This is a big help because now all the windows favorites like Ctrl+c for copy, Ctrl+v for paste, Ctrl+x for cut, and Ctrl+z for undo now work the same on both systems. I still switch frequently between Windows and Mac platforms, so it's very nice to have the same key mappings.

Most recently, I discovered that there is a special file you can create that allows special mappings to the 6 special keys. This made me happy. I was now able to get much closer to having a unified key mapping. For more details, see this article.

To do this, create a new file called ~/Library/KeyBindings/DefaultKeyBinding.dict and put the following text into it (You'll probably have to create the directory the first time -- this is okay).


/* ~/Library/KeyBindings/DefaultKeyBinding.Dict
This file remaps the key bindings of a single user on Mac OS X 10.5 to more closely
match default behavior on Windows systems.  This particular mapping assumes
that you have also switched the Control and Command keys already.

This key mapping is more appropriate after switching Ctrl for Command in this menu:
Apple->System Preferences->Keyboard & Mouse->Keyboard->Modifier Keys...->
Change Control Key to Command
Change Command key to Control
This applies to OS X 10.5 and possibly other versions.

Here is a rough cheatsheet for syntax.
Key Modifiers
^ : Ctrl
$ : Shift
~ : Option (Alt)
@ : Command (Apple)
# : Numeric Keypad

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

NOTE: typically the Windows 'Insert' key is mapped to what Macs call 'Help'.  
Regular Mac keyboards don't even have the Insert key, but provide 'Fn' instead, 
which is completely different.
*/

{
"\UF729"   = "moveToBeginningOfLine:";                       /* Home         */
"@\UF729"  = "moveToBeginningOfDocument:";                   /* Cmd  + Home  */
"$\UF729"  = "moveToBeginningOfLineAndModifySelection:";     /* Shift + Home */
"@$\UF729" = "moveToBeginningOfDocumentAndModifySelection:"; /* Shift + Cmd  + Home */
"\UF72B"   = "moveToEndOfLine:";                             /* End          */
"@\UF72B"  = "moveToEndOfDocument:";                         /* Cmd  + End   */
"$\UF72B"  = "moveToEndOfLineAndModifySelection:";           /* Shift + End  */
"@$\UF72B" = "moveToEndOfDocumentAndModifySelection:";       /* Shift + Cmd  + End */
"\UF72C"   = "pageUp:";                                      /* PageUp       */
"\UF72D"   = "pageDown:";                                    /* PageDown     */
"$\UF728"  = "cut:";                                         /* Shift + Del  */
"$\UF727"  = "paste:";                                       /* Shift + Ins */
"@\UF727"  = "copy:";                                        /* Cmd  + Ins  */
"$\UF746"  = "paste:";                                       /* Shift + Help */
"@\UF746"  = "copy:";                                        /* Cmd  + Help (Ins) */
"@\UF702"  = "moveWordBackward:";                            /* Cmd  + LeftArrow */
"@\UF703"  = "moveWordForward:";                             /* Cmd  + RightArrow */
"@$\UF702" = "moveWordBackwardAndModifySelection:";   /* Shift + Cmd  + Leftarrow */
"@$\UF703" = "moveWordForwardAndModifySelection:";   /* Shift + Cmd  + Rightarrow */
}
Remember: These key mappings assume that you've switched Control and Command. If you don't want to make this switch, replace each @ (command) with ^ (control).

Here are steps to take to apply these changes:
  • Open TextEdit under the Applications folder.  If TextEdit was already open, create a new document using File->New.  There should be a window labeled 'Untitled'.
  • Select the text within the window above, copy it, and then paste it into your new TextEdit window.
  • In TextEdit, convert this to plain text (the default is rich text) by selecting Format->Make Plain Text.
  • Next, select File->Save As...  In the "Save As" dialog box, navigate to your home directory (look under PLACES on the left side for a house picture that has your name next to it).  In your home directory, double-click on the Library folder.  If you see a KeyBindings folder then double-click on it.  If not, then click on "New Folder" (within the Library directory), name the new folder KeyBindings (with no space), and then double-click on it.  Type DefaultKeyBinding.dict for the filename (at the top) and then click Save.
  • Warning:  TextEdit will sometimes try to 'help' you by appending a .txt extension to the filename.  Make sure this doesn't happen.  If asked to use a .txt extension, tell TextEdit to instead use .dict.  It will not work if you use .txt.  If you have trouble, see comment by Nathan below.
  • Before these changes take effect, you need to log out and then log back in.

There you have it! I know this emulation isn't perfect (not all applications honor this mapping), but it's a good start. Please drop comments if you have any questions or suggestions for improvements.

27 comments:

  1. Thanks much! I've been looking for something like this.

    ReplyDelete
  2. Perfect! Many thanks, that's very helpful!

    ReplyDelete
  3. thank you so very very very much!

    ReplyDelete
  4. Thanks for this post! They all seem to work for me on Leopard 10.5.6, except for one. I am having trouble making Shift-Insert work for paste. Strangely, Shift-Delete works for cut just fine. Any ideas?

    ReplyDelete
  5. Aaron: This is a problem that I have in other non-Cocoa applications as well. I really do miss the Shift-Insert paste option, because I use my left-hand for the mouse, and my right hand for cursor navigation and cut/copy/paste (at least on Windows systems). On Mac, having to use Ctrl/Cmd-V forces me to either take my hand off the mouse, or move my right hand to the left-side of the keyboard, either of which slows me down.

    I suspect that the 'Insert' key is actually some kind of help key on Macs -- pressing Insert sometimes changes the mouse cursor to a question mark. A real Mac keyboard doesn't even have the Insert key, but has the 'fn' key in it's place (which is completely different than Insert).

    I think that the bindings to the Insert key are at a higher level and have to be remapped using a different approach. Since this key is not on any standard mac keyboard, I suspect it may be a low-level hack. I would be very interested in finding this out too!

    ReplyDelete
  6. Thanks a lot for your perfect work! It'll be cool if Shift + Insert became work too... Let's keep us informed! // Dmitry Kovba

    ReplyDelete
  7. moveWordBackwardAndModifySelection doesn't work too:( // Dmitry Kovba

    ReplyDelete
  8. WRT moveWorkBackwardAndModifySelection not working, it seems Cocoa doesn't like the $ to be infront of the @

    I was able to make it work using this minor change:

    "@$\UF702" = "moveWordBackwardAndModifySelection:"; /* Shift + Cmd + Leftarrow */
    "@$\UF703" = "moveWordForwardAndModifySelection:"; /* Shift + Cmd + Rightarrow */

    ReplyDelete
  9. Thanks for the suggestion to swap shift and cmd! I've confirmed that this works and have modified the code with this change.

    ReplyDelete
  10. Cool, so in addition to swapping $ and @, I have another binding suggestion for you. Many times I've hit delete to backspace by word which is the windows behaviour. On mac, it deletes the whole line! So, here's another binding to try:

    "@\U007F" = "deleteWordBackward:"; // cmd + delete left

    Kevin G

    ReplyDelete
  11. Oops, I had a typo in my previous comment, I intended to write that on Windows backspace that deletes by word. -- Kevin G

    ReplyDelete
  12. Thanks a lot for your post - it made my life a lot easier.
    However, I managed to switch command and control on the desktop applications as you suggested, but they don't switch in the terminal - do you know how to do that in the terminal as well?

    ReplyDelete
  13. @Anonymous: For Mac Terminal.app key bindings, I wrote up a brief discussion here: http://mavaball.net/wiki/Changing_KeyBindings_on_Mac_Terminal

    This doesn't include ctrl and cmd, but will hopefully give enough information to get started... :)

    ReplyDelete
  14. Awesome, thanks for this info!
    I'd like to switch my control and command keys like you mentioned but then I can't quite get used to pressing ctrl+tab to switch applications. Do you know if it's possible to change that shortcut?

    ReplyDelete
  15. Noah: I haven't found a way to change ctrl+tab to alt+tab for switching windows, so I've been having to re-learn that aspect of the windowing system. I would be interested if anyone else finds a way to change this... :)

    ReplyDelete
  16. I ended up not switching the Control and Command keys; instead I added Keyboard Shortcuts for All Applications, setting ^C for Copy, ^Z for Undo, etc. This way I can keep my precious Alt+Ta... oops, I mean Command+Tab :)

    ReplyDelete
  17. Thanks for posting here I have switched the Control and Command keys, what is the next step (where I have to past your code..?). Please explain me once. I am not familiar with programming. If it’s works for me it would great help for me…

    ReplyDelete
  18. Siva: I've added new instructions for non-programmers that should hopefully help. Look back at the main article, possibly pressing 'Refresh' on your browser, and you should see these instructions.

    ReplyDelete
  19. Hi Matthew V Ball, Thanks for your great, great help I am looking for this change from so many years. I also tried in the way of keyboard keys power supply changes which was not a great IDEA. I need one more facility in Windows 7. I need every NEW FOLDER WITH NOTE PAD in single click. I strongly believe you are the correct person to do that. If you do this that would be great help for me.

    ReplyDelete
  20. Siva: Unfortunately, I never used Windows 7, and won't be able to help in that regard.

    ReplyDelete
  21. OK, to save anyone else the hours of pain I've just endured trying to get this working, here's a little tip.
    I'm a total Mac newbie, so you'll have to forgive me my ignorance here...

    I'd tried time and time again to get this working and the DefaultKeyBinding.dict file I'd created simply wasn't being picked up. No shortcuts were working, even ludicrous ones like mapping letters to other letters.

    The cause? The file I'd created using TextEdit had an invisible .txt extension on it. *facepalm*
    I only realised this after I downloaded the KeyBindingsEditor utility (http://www.cocoabits.com/KeyBindingsEditor/) and it created the correct file for me, showing up the other file with the txt extension.

    Thinking about it now, I'm not surprised that OS X is hiding extensions, it's what Windows does by default too and I turned that off loooong ago :-) But what got me is that I had no idea that TextEdit would add its own extension if you'd specified one in the save dialog. Perhaps the instructions above can be modified to warn for this?

    Well you live and learn. I hope this helps anyone else who runs into a brick wall on this!

    ReplyDelete
  22. Nathan: Interesting point! I typically run in a mode where all the extensions are always shown, so I didn't notice the feature where TextEdit can silently append a .txt. I'll update the blog to mention this.

    ReplyDelete
  23. Serenity Now! Just switched from 16 years of Windows to Mac and was going crazy. On top of just normal Mac usage, I use Citrix for work so I would have to use Ctrl-C in Citrix windows, then Command-C in my local Office apps....driving me crazy.

    I swapped the Ctrl and Command keys and used your key binding file...it's like being stranded in the desert and coming upon a cooler full of Sierra Nevada. Thanks!

    Now to figure out that Alt-Tab dilemma....

    ReplyDelete
  24. I couldn't even do it with as simple as "b" = ("insertText:", "a");
    logged out, restarted, nada.

    ReplyDelete
  25. I don't know all the possible problems, but you might check whether the whole thing is enclosed with curly brackets and whether the filename is in the exact correct location with the correct name: ~/Library/KeyBindings/DefaultKeyBinding.dict

    The ~ is the location of your home directory (e.g., /Users/myusername)

    I don't know off-hand whether you can remap unshifted keys like "b". You may need to at least add a @ or something. Maybe try:

    { "@b" = "insertText:"; }

    ReplyDelete
  26. Thanks for this article.. very helpful. Just wanted to chime in about text editors that respect these bindings. I was disappointed to find that editors like TextWrangler, TextMate, and gedit (for Mac) do not respect these custom key bindings for keyboard text navigation. They mostly just use the Mac defaults, giving some limited options for changing a couple actions. The Mac built-in TextEdit does respect the bindings, which is nice, but I wanted something with syntax highlighting etc. Fortunately I found a free editor -- Fraise -- that does respect the key bindings and also has syntax highlighting and other features. Has anyone else found good text editors / IDEs that respect these key bindings for text navigation?

    ReplyDelete
  27. Man I wish I had have seen this when I first bought my Mac 2 years ago. Better late than never!

    ReplyDelete

Note: Only a member of this blog may post a comment.