Keyboard Control for Mac OS X Windows

Awhile back I blogged about this handy applescript for maximizing windows vertically in Mac OS X. A few weeks ago I installed Linux on my old G3 iBook (a subject worthy of several posts all its own), and one of the things I really like about Linux is the ability to customize keyboard shortcuts and, in particular, to assign keyboard shortcuts to window manager tasks like moving and resizing windows. I installed Xubuntu on the iBook, though I have been using the fluxbox window manager, which is both lightweight and highly customizable, especially with respect to keyboard commands: you just edit a single text file that contains a list of all of the keyboard combinations and actions associated with them. It’s great. And since I’ve spent a good deal of time using these keyboard commands the last few weeks, I really miss them when I’m in OS X and have to manually drag all my windows around where I want them. So after googling around for some way of doing this in OS X and coming up mostly empty, I went back to that original maximize vertically script and, lo and behold, it gave me all the applescript knowledge I needed to throw together a set of applescripts (controlled by Quicksilver triggers) to have a great deal of control of windows via keyboard shortcuts in Mac OS X. Here’s what I have now:

Center window on screen: Cmd-Ctrl-c

Maximize Windows:

Maximize Window Vertically: Cmd-Ctrl-m

Maximize Window, Full Screen: Cmd-Shift-m

Move window to screen edges:\*

Move to left edge: Cmd-Ctrl-h

Move to right edge: Cmd-Ctrl-l

Move to top edge: Cmd-Ctrl-k

Move to bottom edge: Cmd-Ctrl-j

Move window, 15 pixels at a time:

Move left: Cmd-Opt-h

Move right: Cmd-Opt-l

Move up: Cmd-Opt-k

Move down: Cmd-Opt-j

Resize Windows:

Expand right by 15 px: Cmd-Opt-Ctrl-l

Shrink left by 15 px: Cmd-Opt-Ctrl-h

Expand down by 15 px: Cmd-Opt-Ctrl-j

Shrink up by 15 px: Cmd-Opt-Ctrl-k

You’ve got to be pretty careful to avoid shortcut conflicts obviously, so I avoided the singular Cmd-x combos or even the Cmd-Shift-x combos, and anything with Control by itself is likely taken as well (especially if you take advantage of the emacs-style keybindings in Cocoa apps). The only conflict I know of for sure in this set is Cmd-Opt-H, which is usually “Hide Others” in all apps. I fixed this in System Preferences by making Hide Others into Cmd-Opt-Shift-h, but I’m sure I’ll discover more as I go.

I used h,j,k,l as the direction keys — an obvious choice to any vi-user that is no doubt mysterious and confusing to anyone else (of course “l” stands for right and “h” stands for left…how else would it be?). However, this lets you keep your hands on the home row and, amazingly, these keys seem to be relatively under-used in other OS shortcuts (Compared to their home row neighbors a,s,d,f, for example).

This also doesn’t work in every application — most unfortunately, it doesn’t work in Firefox, though it does work in Camino and Safari.

So how to do it? Here is a zip file with all the applescripts you need. In my case, I put them in ~/Library/Scripts/window_control/ (it doesn’t really matter, but if you put them here they’ll show up in your AppleScript Menu).

I set up the triggers in Quicksilver (which if you’re not using Quicksilver or something like it…you should be). If you are using Quicksilver and you aren’t currently using any Triggers, you can just put the Triggers.plist file I included in the zip archive in ~/Library/Application Support/Quicksilver/. (Then open it up in a text editor and simply do a find-and-replace replacing “jon” with your username.)

You may need to tweak things to fit your system. I’ve got a Macbook with a 1280 x 800 screen and I keep my Dock on the right side, so in your scripts (which unfortunately require setting a screen size manually — there may be a way around this), you’ll need to adjust the display_y_size and display_x_size variables at the top of the script to reflect your own display size (minus the menu bar and dock). You can use Script Editor.app, located in your /Applications/AppleScript/ folder. Other things to easily tweak: the number of pixels in each resize and move (I picked 15, but if you’ve got a bigger monitor, you may want to jump more at a time, for example). It’s also handy to set a low repeat value in Quicksilver for the move and resize actions so you can just hold the keys down for bigger movements.

*Update, July 6: I realized that pushing windows to the edges was helpful for big windows (say, browser windows), but for smaller windows (Terminal and Finder windows, for example), it would be more helpful to “tile” them: i.e. move them up/down/left/right by the amount of their width. So I added some intelligence to the “edge” scripts: if there’s room, it will move the window one “tile” size, but if there’s not room, it will just move it to the edge. I updated the scripts in the zip archive. I must say, for not being a very big fan of applescript, this is pretty damn cool. (Of course, a single text file in your home directory, for example, is still much more elegant…)

Update #3: If you’ve run the command in Update #2 on a multi-user Mac, you may have found that after making this change, Preview won’t open for any other user on the machine. This is because this command changes the permissions on the Info.plist file, making it read/write only for you. The easy way to fix this:

chmod +r /Applications/Preview.app/Contents/Info.plist

Yet another update, 01/15/2009: I’m now using Spark for the shortcuts, which works much better than Quicksilver’s Triggers. (I still love and use Quicksilver for other things, but Spark works better for this.) Plus, if you like the idea of having this functionality but dislike the limitations or setup headaches, and you don’t mind paying for software that will give you this ability, check out MercuryMover.

Two Fixes, 09/20/2009: I just uploaded an updated collection of scripts that works around a stupid bug in 10.5/10.6’s Terminal.app (figured if 10.6 didn’t fix this, it may never be fixed…) and also includes a handy trick to get the display size automatically, though it doesn’t work with multiple monitors. Depending on your configuration (i.e. if you’re running Tiger still, don’t use Terminal, or if you use multiple monitors…) you may still want the old files.