Keys and case

Setting up a new computer from scratch is the perfect opportunity to rethink the way you’ve been working. Because it takes some time to find and import your old scripts and settings, the small amount of extra time it takes to tweak them doesn’t seem like much of a burden. I’ve used the setting up of my M1 MacBook Air to fiddle with my longstanding capitalization keybinding.

As I’ve explained before, I have a problem typing capitalized words. Usually, my pinkies lift off the Shift key a little too soon, and the word ends up all lower case. Sometimes, as I try to correct for that tendency, my pinkies linger too long on the Shift key, and I end up with words that have their first two letters CApitalized. For as long as I’ve used scriptable text editors, I’ve written macros to correct for this tendency. Emacs, NEdit,1 TextMate, BBEdit—they’ve all been given a way for me to correct my miscapitalizations. The macros have all worked the same way:

  1. I realize that I’ve typed part of a word—or maybe the entire word—and didn’t capitalize it.
  2. I type some key combination. For a long time, this has been ⌃⌘C.
  3. The editor goes back to the beginning of the word, capitalizes it, and then resets the cursor to where it was before I typed ⌃⌘C.

On the Mac, I can extend this correction to (some) other apps through the Cocoa text system and keybindings. If you know about keybindings, it’s probably through Brett Terpstra. His huge set of keybindings is unquestionably the best set of examples you can find on the topic, but I still think Jacob Rus’s old web pages (here and here) are the best tutorials.

So anyway, after a couple of days of using my new MacBook Air, I realized that my typing of capitalized words hadn’t improved, and I needed to install both my BBEdit capitalization macro and my keybindings file. As I was doing so, I thought about extending them. For example, I’ve run into situations when I needed ALL CAPS, but I didn’t press the Caps Lock key long enough for it to activate, and I’d type path in a shell script instead of PATH. And if I were going to add an uppercase keybinding, I might as well add a lowercase one while I was at it.

Writing the commands was simple enough (I’ll show them later)—what was tricky was deciding where to bind them. I took inspiration from the X, C, and V keys used for Cut, Copy, and Paste. They work because they’re all in a row, they’re in the same order as we usually list the functions, and two of the keys have a nominal relationship to their function. I chose three keys at the other end of the lower row: <, >, and ?.

Case keys

The relationship between the names of these keys and their function is tenuous, but the < key can be related to the idea of “making what’s to the left smaller” and the > key to “make what’s to the left larger.” More important is that the order of the keys from left to right is the order I associate with case changing: Lowercase, Uppercase, Capitalize.

Of course, I can’t just combine the Command key with these to run my macros. ⌘-Period has been used to cancel commands for as long as the Mac has been around.2 And ⌘-Comma is the standard shortcut for opening an app’s preferences window. So, to hold onto some connection with my older use of ⌃⌘C, I chose to combine Control and Command to the three keys.

The Cocoa text system keybindings are saved in ~/Library/KeyBindings/DefaultKeyBinding.dict. This is a plain text file that’s formatted in a way that’s reminiscent of JSON.

{
    "^@," = (setMark:, moveWordLeft:, moveRight:, lowercaseWord:, swapWithMark:);
    "^@." = (setMark:, moveWordLeft:, moveRight:, uppercaseWord:, swapWithMark:);
    "^@/" = (setMark:, moveWordLeft:, moveRight:, capitalizeWord:, swapWithMark:);
}

The keybindings come before the equals sign, and the caret and at symbol are ASCII substitutes for Control and Command. After that come the series of Cocoa text selectors that do the work of moving the cursor around and changing case.

These keybindings work in apps that use the Cocoa text system and honor the keybindings. Luckily for me, that includes many of the apps I write in, especially Mail. It doesn’t include the app I do most of my writing in, BBEdit, but that’s OK because BBEdit has a very capable AppleScript dictionary, which can do everything the keybindings can do and more. Here are the scripts for Lowercase,

applescript:
 1:  tell application "BBEdit"
 2:    tell window 1
 3:      if length of selection is 0 then
 4:        set cursorPoint to characterOffset of selection
 5:        find "\\b\\w" options {search mode:grep, backwards:true} with selecting match
 6:        find "\\w+\\b" options {search mode:grep, extend selection:true} with selecting match
 7:        change case selection making lower case with replacing target
 8:        select insertion point before character cursorPoint
 9:      else
10:        change case selection making lower case with replacing target
11:      end if
12:    end tell
13:  end tell

Uppercase,

applescript:
 1:  tell application "BBEdit"
 2:    tell window 1
 3:      if length of selection is 0 then
 4:        set cursorPoint to characterOffset of selection
 5:        find "\\b\\w" options {search mode:grep, backwards:true} with selecting match
 6:        find "\\w+\\b" options {search mode:grep, extend selection:true} with selecting match
 7:        change case selection making raise case with replacing target
 8:        select insertion point before character cursorPoint
 9:      else
10:        change case selection making raise case with replacing target
11:      end if
12:    end tell
13:  end tell

and Capitalize

applescript:
 1:  tell application "BBEdit"
 2:    tell window 1
 3:      if length of selection is 0 then
 4:        set cursorPoint to characterOffset of selection
 5:        find "\\b\\w" options {search mode:grep, backwards:true} with selecting match
 6:        find "\\w+\\b" options {search mode:grep, extend selection:true} with selecting match
 7:        change case selection making capitalize words with replacing target
 8:        select insertion point before character cursorPoint
 9:      else
10:        change case selection making capitalize words with replacing target
11:      end if
12:    end tell
13:  end tell

You’ll note that these scripts behave differently under different conditions. If there’s no selection, they work just like the keybindings: jump back to the beginning of the word, change the case, and return the cursor to where it was. But if text is selected, they do something simpler: change the case of whatever is selected. This makes it easy to change the case of a whole set of words at once.

Have I occasionally typed ⌃⌘C instead of ⌃⌘/ over the past few weeks? Of course I have—you don’t break a 15-year habit overnight. But I’ve been pleasantly surprised at how few times I’ve done it. The logic of the new keybindings is winning.


  1. No, that one’s supposed to have the first two letters capitalized. 

  2. I suspect most of us use the Escape key now, but early Macs didn’t have an Escape key.