Office Space: Tips and Tricks for Scripting Microsoft Office Applications

Office Space

Welcome to Office Space, the column that offers tips and tricks for scripting Microsoft® Office applications. We’ll post new tips every Tuesday and Thursday; to see an archive of previous tips, visit the Office Space Archive. And if you have particular questions about Microsoft Office scripting, feel free to send them to scripter@microsoft.com (in English, if possible). We can’t promise to answer all the questions we receive, but we’ll do our best.

Retrieving a List of Microsoft Word Keyboard Shortcuts

If you’re into video games then you know all about cheat codes. With cheat codes you type a secret message into the game console or press a specified sequence of buttons on the joystick and – voilà! – all of a sudden you have unlimited wealth, immortality, or god-like powers. As you might expect, immortality comes in very handy in games where the only way you can lose is to be killed. Which is probably why they call them cheat codes rather than, say, playing fair codes.

You might not be aware of this, but Microsoft Word comes with its own set of cheat codes. Granted they don’t give you unlimited wealth or god-like powers (at least not the cheat codes we know about), but they can make your word processing life much easier. For example, suppose you have a phrase that was typed using all lowercase letters and you’d really rather have that phrase typed using all uppercase letters. Hey, no problem: select the text and then press Ctrl+Shift+A. Voilà: all uppercase letters. Want to format another phrase as hidden text? Highlight the phrase and press Ctrl+Shift+H. The list goes on and on. And on.

That’s pretty cool, but there is a problem: most likely you haven’t memorized all the keyboard shortcuts found in Microsoft Word. (Considering the fact that there are hundreds of such shortcuts, that’s almost a given.) So how in the world can you ever get a list of Microsoft Word commands and their accompanying cheat codes?

OK, true, a lot of these shortcuts can be found in Word’s help file. And, yes, no doubt a lot of them can be found somewhere on the Internet as well. But that’s a boring way to get a list of Word’s keyboard shortcuts. Here’s a much cooler way to get that same information:

Set objWord = CreateObject("Word.Application")
objWord.Visible = True
objWord.ListCommands(True)

That’s right: it’s a script, and just a three-line script to boot. We begin by creating an instance of the Word.Application object and then setting the Visible property to True; that starts Word and makes it visible on screen. We then call the ListCommands method, passing the True parameter. The True parameter tells ListCommands to return all the Word commands, both built-in and customized. If we passed False to ListCommands then we’d get back a collection of only customized commands.

When we run our three-line script Word will automatically build us a document that looks like this:

Microsoft Word

Pretty cool, huh? In the first column (Command Name) you’ll see the Word command; in columns 2 (Modifiers) and 3 (Key) you’ll see the keyboard shortcut for that command, if one exists. If we look closely at the table we can see that the Address command doesn’t have a keyboard shortcut, but that the All Caps command does (Ctrl+Shift+A):

Address

 ‪

 

 

All Caps

Ctrl+Shift+

A

 

The list continues on from there, documenting well over a thousand commands found in Microsoft Word 2003. Not bad for a three-line script, eh?

Now, if we were lazy – OK, fine: if we were lazier we could just end the column right here and you’d still have a nifty little script to add to your toolkit. On the other hand, we can’t deny that about three-fourths of the Word commands have no keyboard shortcut; nevertheless, all those shortcut-less commands – such as Address – are intermingled in the table along with the commands that do have shortcuts. That’s OK, but if we’re interested only in our so-called cheat codes that’s a lot of extraneous information we need to weed through. And that got us to thinking: is there any way we could modify our script so that it would delete all the commands that don’t have a keyboard shortcut?

Well, you already know the answer: of course there’s a way to do that. As far as we know there’s no way to list only commands that have a shortcut. Therefore we did the next best thing: we listed all the commands, just like we did before, then went through the table row-by-row, checking to see if a command had a keyboard shortcut. If it did, we left it alone; if it didn’t we deleted that row. When we were all done our new list of commands looked like this:

Microsoft Word

Much cooler. Best of all the modified script – while a bit cryptic at first glance – didn’t require very many more lines of code:

Set objWord = CreateObject("Word.Application")
objWord.Visible = True
objWord.ListCommands(True)

Set objDoc = objWord.Documents(1)
Set objTable = objDoc.Tables(1)

For i = 1 to objTable.Rows.Count
    strText = objTable.Cell(i,2).Range.Text 
    strText = strText & objTable.Cell(i,3).Range.Text
    intLength = Len(strText)
    If intLength <= 4 Then
        objTable.Rows(i).Delete
        i = i - 1
    End If
Next

OK, maybe it’s a tad more than “a bit” cryptic. But let’s walk through the code and explain what it’s doing. The first three lines of this modified script are the same as our original script: we create an instance of Word and call the ListCommands method to auto-create a table of all the Microsoft Word commands. We then use the next two lines of code to create a pair of object references, one to the current document (objDoc) and one to the first table in that document (objTable):

Set objDoc = objWord.Documents(1)
Set objTable = objDoc.Tables(1)

Because our document has only a single table in it, objTable now points us to the table containing all the Word commands. So far so good.

From there we set up a For Next loop that runs from 1 to the number of rows in the table (for example, if our table has 4,362 rows in it the loop will run from 1 to 4,362). That’s what this line of code does:

For i = 1 to objTable.Rows.Count

So what do we do within that For Next loop? Well, we begin by setting the variable strText equal to the value of the Text property for cell i, 2 in the table; in other words, strText will now contain whatever happens to be typed in cell i, 2. In case you’re wondering, cells are referenced by the row number followed by the column number, and i is our loop variable. Thus the first time we run through the loop i, 2 refers to row 1, column 2; the second time through the loop i, 2 refers to row 2, column 2, etc.

Next we assign strText the current value of strText plus whatever happens to be in cell i, 3. Why do we look at column 3 as well as column 2? Well, most of the keyboard shortcuts consist of a modifier plus a key: for example, Ctrl+Shift plus A. A few shortcuts, however, consist of only a key (such as F1 for Help). That means we can’t just check column 2 and, if there’s no value, assume that there’s no shortcut key; that isn’t always the case. Instead we have to combine the value of column 2 with the value of column 3.

After piecing together our string we then use the Len function to count the number of characters in the string; this number gets stored in the variable intLength. This is the one tricky part in the script. If you look at the Address command you’ll see blank cells for both the modifier and key. Because of that you might assume that neither cell has any text and that the length (number of characters) would be 0. Interestingly enough, however, that’s not the case. Instead, a “blank” cell actually contains a carriage return and a linefeed (equivalent to pressing ENTER on the keyboard); thus two “empty” cells really contain a total of four characters (a carriage return and a linefeed in each cell). That’s why we use this line of code to determine if the length of our string has 4 or fewer characters:

If intLength <= 4 Then

If the string has four or fewer characters we assume that both the modifier and key columns are blank; otherwise the string would have to have at least five characters (the two carriage returns, the two linefeeds, plus at least one other character). If we have four or fewer characters we then execute these two lines of code:

objTable.Rows(i).Delete
i = i - 1

The first line deletes the current row in the table. The second line then resets the value of i to i – 1. Why? Well, suppose we’re on line 3 of the table. We delete the row. Does that mean that the next row in the table is line 4? No; it’s actually line 3. That’s because, when we deleted the previous line 3, all the rows in the table moved up one: what used to be line 4 now becomes line 3. We have to adjust the value of i to ensure that we don’t skip a row.

Yes it’s a little confusing, and we apologize for that; if you run the script a few times hopefully you’ll see how it all works. Incidentally, if you do run the script be forewarned that it might take 15 minutes or more to complete; that’s because reading a huge table like this is very slow. So, yes, the script takes awhile to complete, but in this case the old saying holds true: good things do come to those who wait.