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]

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).

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.

16 comments:

Anonymous said...

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

John said...

Perfect! Many thanks, that's very helpful!

jared said...

thank you so very very very much!

Aaron H said...

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?

Matthew V Ball said...

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!

Anonymous said...

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

Anonymous said...

moveWordBackwardAndModifySelection doesn't work too:( // Dmitry Kovba

Anonymous said...

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 */

Matthew V Ball said...

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

Anonymous said...

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

Anonymous said...

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

Anonymous said...

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?

Matthew V Ball said...

@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... :)

Noah said...

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?

Matthew V Ball said...

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... :)

Noah said...

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 :)

Post a Comment