As our list of editing macros in Microsoft Word grows, we’ll invariably want to automate the process of assigning the keyboard shortcuts in part because they are occasionally reset by Word.
Thanks for your interest
This content is part of a paid plan.
Automatically update custom keyboard shortcuts
Our productivity gets a boost when our most common editing macros are at our fingertips, so we can wring more work out of our most used macros when we assign them to keyboard shortcuts.
Most shortcuts use some combination of modifier keys along with one main key. While we can assign many keys individually, this is usually reserved to just the function keys.
Assigning our own custom keyboard shortcuts to macros or commands is called “keybinding.” Unfortunately, the keybinding command in Word VBA is a little awkward (see previous article), but we can simplify the process with our own macros and functions.
Only so many reasonable key combinations exist, so if you want more customization options, you can also assign macros to custom buttons on the ribbon or the Quick Launch bar. Also, two-key shortcuts can be set with a similar command as covered in this article, but we’re not covering them today. For those willing to invest in voice recognition software, Dragon Professional scripting also uses VBA, and it allows us to connect to Word and run our macros by voice command (see previous introductory article to get started).
This article is part of a series of mostly member articles to automatically assign our own keyboard shortcuts in VBA. Each article covers different aspects of the small project.
- Simpler approach to get a keycode for any key combination (lacks error checks)
- More concise but programmy version to get a keycode for any key combination (includes error checks)
- A function that validates whether isolated keys are allowed for a tentative keyboard shortcut
- Another macro assembles the pieces to automatically assign or reset keyboard shortcuts for macros or Word commands (this article)
Why do we need it?
While we can manually assign custom shortcuts in both Word for Mac and Windows, it quickly becomes tiresome beyond only a handful of macros, and your library of editing macros will grow faster than you think. Also, issues occasionally arise with custom shortcuts in Microsoft Word which require us to reset them.
Reassign shortcuts when reset by Word
If you rename a macro or even just copy and paste it somewhere else inside the VBA editor, Word detects the change and invalidates the assigned shortcut or resets it back to the default if one exists. You would need to reassign it manually … again. Worse, Word will sometimes automatically reset all keyboard shortcuts to defaults if the Normal.dot template becomes corrupted. Fortunately, the latter case is rare but troublesome when it happens. Either way, it’s handy to be able to reset all your shortcuts with a single button press or however you choose to invoke the reassignment macro.
Better shortcut organization
Organizing shortcut assignments also helps with remembering which ones you have at your disposal and in setting up useful shortcut patterns.
Macro skeleton
We’re creating a “special key” shortcut assignment macro that requires a keycode constant to assign the shortcut, but it is actually the more general case and the easier one to implement. The macro skeleton is:
This macro isn’t a function, so it returns no value.
Depending on our preferences, we need about four slight variations of this macro for the different cases. Some other programming languages make this easier with “overloaded” functions that use the same function name but different parameters, but we must use distinct names in VBA.
Parameters
The macro requires three arguments from the user with an optional fourth. The first two are identical by design to the GetKeyCode function in an earlier article.
I often precede plain text variables with an “s” or “S” to identify the variable type as a String, and a capital first letter implies the variable value will not change inside the macro. VBA does not care about nor enforce either “rule” as long as we don’t try to use one of its reserved words.
Modifier keys text string
The first parameter requires a plain text string telling the macro what modifier keys are used for the keyboard shortcut. We’ll call this variable sModifierKeys where we imagine input something like “Control+Shift”. For simplicity, we’re requiring the words to be spelled out in full, but it could be implemented with abbreviations as well.
We convert any alphabetic characters in sModifierKeys to lowercase inside the function, but any changes to String arguments in VBA can leak back outside the macro. The ByVal keyword tells VBA not to change the argument value given by the user.
The main key such as “A” or “9” should not be included in the sModifierKeys text, but any main key given as text will just be ignored by the previous GetKeyCode function. As far as this macro is concerned, modifier key texts “Control+Shift” and “Control+Shift+A” will result in the same keyboard shortcut provided the next MainKey constant is correct. An upcoming article will allow us to interpret a shortcut assignment in this more convenient pattern “Control+Shift+A”.
Main key
The second parameter requires a standard Word key constant. These are usually found in the WdKey enumeration table, but to keep it general, the MainKey variable value is stored as a Long number type (just a bigger Integer).
In VBA, enumerations are mostly just constant lists with names that are easier to read and remember. The WdKey table includes all text characters as well as most special keys like Home or Delete. Word automatically converts between WdKey values to a Long number type for the MainKey variable, so for example, we could specify an “A” key for the shortcut by passing the function a value of wdKeyA.
Arrow keys are omitted from the WdKey table for some reason, but they are defined in the VBA KeyCode constants table, and they are used in the same manner.
VBA automatically converts the key constants to Long numbers when necessary.
Macro name
We also need the plain text name of the macro or Word command to run which we’ll call SMacro. We cannot assign shortcuts to macros with any parameters, nor can we assign shortcuts to functions.
Optional key binding category
Unfortunately, the key binding command has a tiny variation between assigning shortcuts to our own macros or standard Word commands. While I don’t like making this macro seem more complicated, it’s annoying to have such a small difference force us to copy the same macro over with only one tiny change and another dozen or so identical steps.
Optional parameter review
We’ll make the parameter Optional since a macro is the most common use case by far.
We’ve covered the Optional keyword for parameters before, so let’s do a whirlwind review.
Optional tells VBA the variable does not need to be given when the function is called. If not, VBA uses a default value given with the parameter.
Key category type
We still need to specify a variable type which must be one of the “intrinsic” types such as numbers or a string. The type of our MyKeyCategory variable is WdKeyCategory.
Yep, it’s like they make up new enumerations for everything, but that’s better than all numbers being a Long number type, and we have to refer to tables to know what anything is. At least it’s descriptive but see the Gotchas below.
Default value
There are several key category types in the enumeration, but we mainly need the macro and standard Word command constants which are wdKeyCategoryMacro and wdKeyCategoryCommand, respectively.
The default value for our optional category parameter is literally assigned right after the parameter type with = SomeValue where SomeValue must match the data type used (e.g., a number for a Long parameter, True-False for a Boolean parameter, etc.). For us, assigning a shortcut to a macro is the most common case by far, so we’ll set wdKeyCategoryMacro as the default value.
Getting the keycode
The keycode identifies the unique key combination for a shortcut we’re attempting to assign. Getting the keycode requires several steps including a pair of supplementary key validation functions, so it was relegated to its own function.
Define keycode number variable
We start by defining a numeric variable myKeyCode which will store the unique key code.
It has a Long number type since the KeyCode option of the KeyBindings Add method later wants a Long number for the unique key combination.
Call key code function
The previous GetKeyCode function (or the improved version) requires two arguments which are identical to the first two parameters of the current function. The work to create the earlier function pays off since we simply call it using the same two arguments.
We store the numerical keycode result in the previous myKeyCode variable.
Some key combinations just don’t work in Word, but specifics depend on whether you’re in Word for Windows or Mac. The GetKeyCode function performs some validations on the potential key combination, but we still have some error checking to do later just in case.
Setup the keyboard shortcut (“keybinding”)
We’ve interpreted the modifier keys text and main key value and stored the result in the myKeyCode variable. We need to bind the key combination to the intended macro.
KeyBindings property
We introduced the KeyBindings object in a previous article which belongs to the Application object in VBA.
When not specified, VBA assumes the Application object, so we can just omit it.
In addition to some other data (properties) and actions (methods) defining what it can do, KeyBindings stores a collection of all active and inactive key bindings in Word.
Clear key binding
It’s good practice to clear an existing key binding. Probably nothing bad would happen if we ignore this step. It makes the macro more complicated, but it is safer and definitely clearer.
Get the Key
There are several ways to access the specific KeyBinding corresponding to the given keyboard shortcut. I prefer to use the Key method.
As shown, many examples in the Microsoft documentation use the BuildKeyCode function to refer to the proper shortcut, but we’ve already stored our keycode in the myKeyCode variable earlier.
This Key purportedly refers to a KeyBinding object which stores information about the key binding information corresponding to myKeyCode.
Clear the key binding
Now we can clear the key binding—
Hold on … better watch out for trouble.
Does the key binding even exist?
The problem is the upcoming Clear method will cause an error if the referenced Key does not exist. Meaning, this step could easily cause the macro to crash.
Hmmm.
We now need to ensure the referenced Key gives us a valid KeyBinding object before trying to clear it. Probably the cleanest way to proceed is to store the Key result, so we first declare a new KeyBinding variable.
Now we can Set the key binding to whatever result is returned by the Key method for our keycode.
We need to use Set because a KeyBinding is a VBA object with its own properties (data) and actions (methods) not just a value like a number. This assignment to a new variable isn’t strictly necessary, but it makes the following steps a little clearer.
Validate whether key binding exists
The Key method literally returns Nothing if the Key shortcut does not exist in Word, so we just check for it.
Since it’s a True or False (Boolean) value, we can directly use it in a conditional statement.
Since a KeyBinding is an object, we use “Is” rather than an equals = sign to compare it to Nothing. I wish VBA supported IsNot from Visual Basic, so the line reads better, but we’re stuck with this Yoda-esque form.
Finally clear the key binding
Now we can clear the key binding if it exists, but we’ll use the more compact notation with the If statement on one line.
Clearing an existing key binding isn’t strictly necessary. I know this in part because I’ve been just “adding” existing keyboard shortcuts for years in VBA, but I felt remiss to omit it from a public version, and it is a tidier approach.
Do not exit function
As a brief aside, we do not additionally exit the function if the key binding does not exist since we might be setting a new shortcut. Nothing wrong with that.
KeyBindings property
Now we return to binding macro to the shortcut. The KeyBindings object has a convenient (but messy) method to Add a new key binding.
Most common add key binding options
We have several options when referencing the KeyBindings.Add method:
- The KeyCategory constant is usually either set to macros or Word commands. We’ll focus on macros until the end of this article.
- The Command option is the literal name of the macro we want to run given in plain text within double quotes or with a string variable storing the name.
- The KeyCode option needs the numeric value corresponding to the unique key combination we want to use to trigger the macro.
Typical command
The options make the command a little cumbersome, but a typical new keybinding command looks like:
Each option is separated by a comma, and assigning option values in a VBA command requires a colon equals := not just an equals = sign. Unfortunately, the Add method requires a long line, so we add an underscore _ to stretch it across two lines and make it more readable. VBA does not care.
Shortcut category
Our MyKeyCategory parameter for the current macro assigned a default KeyCategory of wdKeyCategoryMacro.
Assigning a shortcut to a standard Word command rather than our own macros requires a different keybinding category wdKeyCategoryCommand. Everything else about the process is the same, and you won’t notice a difference when using them in Word.
Other interesting secondary categories in the table include wdKeyCategoryAutoText, wdKeyCategoryFont, wdKeyCategoryStyle, and wdKeyCategorySymbol; but we do not use them in this article. Word assigns several standard shortcuts related to these types, but I do not to use them.
Command name?
The current macro requires the macro name which is stored as SMacro.
Build keycode?
VBA provides a BuildKeyCode(…) function to make generating the key code easier, but we went through the work of creating our own slightly more general GetKeyCode function in a previous article. We provided the various modifier keys as text and the main key as a constant and stored the result in the myKeyCode variable.
Add method with our macro variables
Our version will look a little simpler than the above example since we directly use our parameter variables.
Two-keys option?
Another option exists KeyCode2 to specify a second key. Standard Word two-key shortcuts access menu commands and such. We could generalize and apply them to our own macros, but we’re not covering them in this article.
String parameter?
An awkward system exists to provide a single String as a CommandParameter when adding a key binding, but I wouldn’t use it unless it was forced on me. The only exception might be for simple parameters like a paragraph spacing value, but even then accessing it inside the macro makes me want to proverbially but forcefully defenestrate anyone responsible for this programming atrocity (a.k.a., yeet them out a window in modern parlance).
No macro arguments
Any keyboard shortcut assigned in Word cannot have an argument (such as the number of paragraphs to move) which is unfortunate. We can, however, cheat the system if we use voice commands in Dragon Professional. See this article to get started if you’re interested in this route, but it is a paid application.
Testing keyboard shortcuts
Assuming you’ve done everything else correctly, some key combinations just don’t work.
Yep. That’s right … even if you really want it to.
It’s a limitation of Word, the physical keyboard, and/or how the operating system interprets the keyboard input. We can’t do much about it except mope and work around the missing key combinations. We can, however, test whether a given key combination will work.
Windows
In Word for Windows, use: File → Options → Customize Ribbon and click the Customize … button (see older video for Windows). It’s not the friendliest user interface, but inside this dialog, click into the Press new shortcut key: edit box, and you can test various combinations. I’m not sure they could’ve hidden it much better, but at least it’s available.
Mac
Testing shortcuts is much easier in Word for Mac, use the Tools → Customize keyboard … menu option. Test any key combinations in the dialog (see early part of a previous article on another topic).
What if a key binding error occurs?
The previously used GetKeyCode function already does some validation on the keycode value, but what if something else goes wrong?
We really should add an error step to catch a VBA “runtime” error (literally an error that occurs while the macro is running). If we don’t catch the error, the macro will crash and pop up a nasty message that we don’t know what in the world we’re doing with macros or writing—well, it’ll just let us know there was a problem, but it feels personal.
We’ve covered this in other articles, but let’s review the concept as it’s used in VBA.
Track errors
Let VBA know we want to track possible errors using On Error.
KeyBindError is just a made-up line label we add somewhere, but it’s usually placed at the end of the macro. After it, we include any error-specific steps we want to run if an error occurs.
Exit the macro
But first … we need to tell VBA not to proceed into the error steps when a shortcut assignment is successful. We simple exit the subroutine.
Otherwise, VBA would just mosey on through the rest of the macro steps running everything.
Error steps line label
We label a line using the same name as above just ending it with a colon:
The VBA editor insists the line is not indented. A little annoying but whatever.
Line labels are just that. VBA doesn’t do anything else with them other than store the line position. We always use them in the context of marking a line to goto if an error occurs. Technically, we could utilize them in regular macros with a GoTo statement, but programmers kind of quit doing that about 40 years ago since it made programs hard to follow. The tongue-in-cheek term was “spaghetti code” but the cooked kind with a mass of sticky noodles in a bowl.
Error message
I like to include an error message that gives additional information about the problem. The standard Word function is MsgBox.
Here we used a dummy error message for brevity, but the macro below includes a real error message including the key information (pun intended).
MsgBox works in both Mac and Windows. Other spiffy options exist like giving the dialog a title or a fancy icon beside our message, but our examples just report a basic error message.
Clear the error
We need to tell VBA we took care of the error, so it doesn’t get passed up the line to the calling macro. The standard Word VBA error object is Err, and we just need to reference the Clear method.
Then we just let the macro end.
Gotchas
What might go wrong that we haven’t already solved?
My keyboard shortcut isn’t working!
Word may have disabled the shortcut for some reason, so try reassigning it. See comments at the top with a few reasons why this might happen.
Unfortunately, both Windows and Mac have idiosyncrasies with certain key combinations, but we just have to work around them. Available keyboard shortcuts differ between Word for Windows and Mac for multiple reasons. For example, I have issues using shortcuts involving punctuation keys on a Mac. Macs don’t seem to recognize them in combination with most modifier keys. This works better in Windows, but it’s not perfect there either.
Optional key category parameter
Since VBA doesn’t actually check values assigned to enumeration type variables, what if someone gives a general number to the MyKeyCategory parameter?
Rather than validate this value manually and further stretch out the function, I chose to let this fall under the umbrella of a generic error which would be caught by the On Error handling when the key binding is attempted.
Final general version with special keys
The special key version for assigning a shortcut to a macro or Word command is:
If you’re using Word for Mac, use the GetKeyCodeMac function instead.
The previous GetKeyCode function or its improved version did the heavy lifting for us, so most of the effort here is spent taking care of possible errors. It's a little messy, but it would almost certainly bite us somewhere down the road if we had not included it.
The underscores just make it easier to read in the VBA editor. VBA doesn’t care unless it’s over 26 lines which is rarely needed.
Final simple Word macro version with special keys
Adding a macro shortcut is the most common case, so it’s nice to have a direct macro to do this. The advantage of creating the more general version above is we can just call it for our more specific cases. Now we apply it to a macro shortcut.
We had to use a unique macro name since VBA doesn’t allow repeated names.
Since the MyKeyCategory is optional with a default value of wdKeyCategoryMacro, we could have left that argument out, but I chose to be explicit just for the extra clarity.
Why make the parameter optional then? Well, someone else may want to omit it, and I probably will sometime also.
One could argue we now have two macros rather than one, but this one is just for convenience and prettification (it’s a real word). Obviously, you could just leave this one out and use the more general version if you prefer.
Example uses
When we set up our keyboard shortcuts, we “call” the function once for each (re)assigned shortcut.
Let’s pretend we want to assign a macro named ApplySceneStyle to the keyboard shortcut Control+Shift+A. The appropriate modifier keys text is “Control+Shift” and the key constant from the WdKey table is wdKeyA. Inserting these into the function call, we have:
That’s not too bad.
We needed the initial keyword Call since the macro required arguments.
The ApplySceneStyle macro name was passed as plain text in double quotes. We specified wdKeyA from the standard key constants table.
Most relevant key constants are listed in the standard Word WdKey enumeration. It allows regular text characters as well as any special keys like Home or Delete, thus the “special key” part of the macro name.
Of course, we could’ve instead used the earlier general macro:
In this case, they are almost the same, but we’ll shorten this in an upcoming article.
What don’t I like?
The above function call is a little clunky for simple shortcut assignments like Control+Shift+A. Why can’t I just use that same shortcut text instead of the clumsy wdKeyA for the main key?
I’d prefer to just call a simpler function with something like:
That’s easier to use, but we'll have to wait for it since this usability improvement is the subject of the next version.
I like letting VBA interpret the “A” for me without needing to explicitly type wdKeyA. Admittedly, it’s splitting hairs when the above version works just fine, but I like my macros to be simple when possible and reasonable. Kind of like my VBA version of keeping the kitchen counter clean. It just … should be.
Word command version with special keys
Binding a shortcut to a standard Word command requires a slightly different key binding command, but we created the earlier assignment macro to allow an optional key category parameter. Now we use it to create a more specific macro to assign a Word command to a shortcut.
Change parameter name
I also made an aesthetic change in the third macro parameter from SMacro to SCommand just to be clearer if someone else ever reads it.
Final simple Word command version with special keys
In this macro, we tell the more general AddShortcutSpecialKey macro that we’re adding or modifying a standard Word command shortcut by providing the wdKeyCategoryCommand constant for the MyKeyCategory parameter.
Again, this is just for convenience, so we don’t need to explicitly give the wdKeyCategoryCommand category.
Example uses
One Word command I use regularly is OutlinePromote. I prefer to assign it to “Control+Shift+O”, so with this macro, the assignment looks like:
Or we could use the slightly longer, messier version with the more general assignment macro:
I like the tidier look of the former version, but we’ll make it even easier in an upcoming article.
Use cases
OutlinePromote and OutlineDemote are very useful, so I reassigned both commands. I also reassigned several other standard commands like Redo via EditRedoOrRepeat to Control+Shift+Z to mimic the more standard Redo shortcut on a Mac. I also remapped CopyFormat, PasteFormat, as well as PasteTextOnly since I wanted the standard shortcuts for my own macros.
Word commands
The names of standard Word commands can be found in the macro dialog under the View menu or in the same dialog used for manually assigning shortcuts. Unfortunately, the respective command actions aren’t documented well, but the most useful ones are probably already assigned to a standard Word shortcut.