Heading

This is some text inside of a div block.
This is some text inside of a div block.
This is some text inside of a div block.
min read

Get main function key from shortcut text

Word • Macros • Functions • Organization
Peter Ronhovde
18
min read

We can simplify some keyboard shortcut assignments by allowing the shortcut to be designated as text. This function translates a typical text function key abbreviation such as “F1” to a standard Word WdKey value to facilitate creating some shortcut assignments in VBA.

Thanks for your interest

This content is part of a paid plan.

Get main key value from function key text

Function keys are common for keyboard shortcuts with about 100 possible key combinations when used alone or combined with modifier keys. More combinations exist on a Mac since it has four modifier keys instead of the three accessible ones in Windows. Most have default commands assigned, but we can override them. That's a lot of shortcuts waiting for our own custom macros just a tap away.

When assigning keyboard shortcuts to function keys in Word VBA, it is convenient to allow text shortcut formats like “Control+Shift+F1”. The Word WdKey enumeration table contains constants for function keys from F1 to F16, so we just need to interpret the last two or three characters of the shortcut to get the main key constant consistent with the shortcut text. This value can then be used with an upcoming Word VBA key binding macro to override the key combinations for our own editing macros.

A previous function parsed letters and numbers, and now this one interprets function key text, so we account for the majority of reasonable keyboard shortcuts. The previous special key shortcut assignment macro covers the rest, such as punctuation or numpad keys, as long as the key combination is valid in Word.

This article is part of a series of mostly member articles helping organize and quickly reassign our macro shortcuts:

Function key skeleton

The previous GetAlphanumericKey function accounted for alphanumeric keyboard shortcut combinations like “Control+Alt+A”, but now we further allow something like “Control+Alt+F9”?

The function skeleton to interpret function key text as a WdKey constant is:

Function GetFunctionKey(SKey As String) As WdKey
' Return WdKey value corresponding to the function key from the last
' two or three characters of SKey
' Returns wdNoKey if no matching function key was found

End Function

Parameter

The function takes the key as plain text (a String) named SKey where the last two or three characters of the argument are assumed to be the intended function key abbreviation. The beginning of the SKey text can include the modifier keys, but they are ignored for this function.

The initial capital “S” of SKey is just a naming preference indicating a String parameter that does not change anywhere inside the function. VBA doesn’t care about the parameter name (as long as it isn’t one of VBAs own reserved words), but it does require a plain text value because it was declared “As String”.

Return value

We return a corresponding WdKey constant from the WdKey enumeration for the identified function key. If no corresponding function key text is found, it returns wdNoKey which technically has a value of 255. Remember, an enumeration is mostly just a list of standard constants with names that are easier to remember and read.

Using a Long number type might be more convenient in some ways, but a WdKey number type is consistent with a previous related function. It also makes this function's returned result clearer because the WdKey table only includes physical keys as opposed to any characters possibly accessed using the Shift key.

Unfortunately, VBA doesn’t restrict the values assigned to an enumeration variable. VBA converts between these number types automatically anyhow, so we don't lose anything by being more specific.

Quick empty string check?

If SKey contains no text, the two function key searches below will already fail to find anything valid, so the function would automatically exit with an invalid value. Adding a separate empty string “” check at the top is a little clearer, but it seems superfluous for this function.

If you prefer to include it, we basically just check whether SKey is equal to an empty string “”. If so, we set an invalid return value of wdNoKey using the function name before exiting the function (see the same error check in the previous related function if you want a more granular explanation).

' Check for non-empty shortcut text (not necessary and not used below)
If SKey = "" Then
' Invalid empty shortcut text, so exit function
GetAlphanumericKey = wdNoKey
Exit Function
End If

Empty strings would be uncommon, so the function below omits this redundant check.

Converting text to a key constant

Unlike the previous function which converted a single character, we must now interpret two or three characters which could range from “F1” to “F16”. After some setup steps, a Select-Case statement with 17 cases would work, but that would be long and boring. Instead, it’s shorter and a little more elegant to search and validate any found function key abbreviations.

Identifying a number with Like

We covered the Like search operator earlier in this article, and it seems tailor made to handle identifying a function key abbreviation in the keyboard shortcut text.

Convert keys to lowercase?

We could convert the SKey text to lowercase like we did in the GetKeyCode function.

' Convert shortcut text to lowercase
SKey = LCase(SKey) ' Not needed for this search

This would usually save us some logical issues with accounting for upper and lowercase text in our searches, but we can actually handle this simple case difference easily with a revised Like search pattern at the slight cost of making the pattern harder to read. It’s a nice learning experience though.

Search pattern

Like makes it easy to check alphabetic cases without using an extra function to explicitly convert the text.

Brief Like search review

Recall that a text search with Like looks like:

SomeText Like SearchPattern

SomeText and SearchPattern are plain text strings. Both can be literal text “in double quotes” or text stored in a String variable.

Character classes in the search pattern

In computer world, upper and lowercase text are different unless the program has been specifically designed to allow either case. That’s what we’re about to do with this function key search.

Allowing for either “F” or “f” uses brackets “[Ff]” around the characters in the search pattern. They tell Like to allow either character in that match position but not both. The square brackets specify a “character class” for the search pattern, but we don’t care about the fancy name. It just allows us to match either character.

As we move forward, we'll only refer to the uppercase "F" for brevity.

Number matching with a hashtag

Now we need “F” followed by a single number at the end of the string.

Numeric digits as text are matched using the hashtag “#”. It literally requires a single-digit number in its location in the search pattern.

Since the number follows our “F” to create a function key text abbreviation “F1”, our search pattern is “[Ff]#”. Nothing precedes the “F” character, so this search implicitly requires “F” to begin the search text … which is a problem.

On the positive side, since nothing follows the hashtag #, this implicitly requires the number to end the searched text which is what we want for this search since our shortcut text is something like “Control+Shift+F1” where the “F1” indeed ends the example text.

Allowing for other text using an asterisk

We need to allow for any characters before the “F1” text. This is done with an asterisk “*”, and fortunately, it also allows for no characters in its pattern position. Our revised search pattern is “*[Ff]#”.

We don’t include an asterisk at the end because we expect the function key number to be the last character of the searched text.

The pattern starts looking more like hieroglyphics than a text search, but it is allowing us to do more. Regular expressions (see this introductory article to get started if you’re interested), take this up several levels with much more detailed searches. We don’t need that sledgehammer yet though.

Revised search

Our searched text is stored in the argument SKey. Putting this together with the search pattern, our revised search is:

SKey Like "*[Ff]#"

Conditional statement

Like returns a True or False (Boolean) value indicating whether a match was found, so we can put this search directly into a conditional statement:

If SKey Like "*[Ff]#" Then
' Do these steps if a single-digit function key is matched ...
End If

Hmmm.

Like doesn’t give us any additional information about the match. We must parse any function key abbreviation manually to get the number.

Matching two-digit function keys

It seems odd to only match F1 through F9, so let’s add a two-digit option. The initial part of the search pattern is the same “*[Ff]#”, but if we need to match two digits after the “F”, we simply include another hashtag. Our second search pattern is “*[Ff]##”.

Function keys

This pattern looks for an “F” or “f” followed strictly by two number digits. It will not match “F1” to “F9”. The asterisk behavior is the same as before. This pattern will technically match shortcut text that ends with “F10” through “F99”.

Uhhh …

We’ll have to do something about that since the function keys in the WdKey enumeration stop at “F16”.

Revised conditional statement

We can chain this second condition with the previous one using an If-ElseIf statement.

If SKey Like "*[Ff]##" Then
' Do these steps if a two-digit function key is matched ...
ElseIf SKey Like "*[Ff]#" Then
' Do these steps if a single-digit function key is matched ...
Else
' No matching function key number
' Set an invalid value and exit subroutine ...
End If

Remember the ElseIf is only checked if the first condition does not find a match. See this previous introductory article for VBA conditional statements if you’d like a quick review.

We do the two searches separately mostly because Like is a little dumb. We need to know whether the last character or the last two characters are numbers, so we can properly interpret the which function key was given. The order doesn’t matter because the potential matches don’t overlap with one or two number digits.

Getting the number

We need the Right(…) function again to get the last character or two of the SKey text string.

Right(SomeText, NumberOfCharacters)

As a quick review, Right(…) gets the last NumberOfCharacters from SomeText. We temporarily store the characters in a string variable named sNumber.

Dim sNumber As String

Now why do this?

Get the function key text number

The number at the end of SKey is just text which is why I reminded myself of this fact by preceding the name with an “s”. The naming convention isn’t necessary or required, but it’s a good reminder.

Even though technically everything is a number in some form to a computer, VBA doesn’t know the numerical value of the text as a human would read it. It definitely doesn’t know it in the context of our intended function key constant from the WdKey table.

If we want the one-digit number, we pick the last digit of the SKey text and store it in sNumber. We don't need the "F" since we've already identified it as a function key abbreviation.

sNumber = Right(SKey, 1)

Similarly, a two-digit number requires us to pick the last two digits of the SKey text, so we instead specify a two for the second argument.

sNumber = Right(SKey, 2)

These are used below for the respective parts of the If-ElseIf statement.

Else part

If no matches of either single or double-digit function keys are found, the conditional statement will default to the Else part. This is a logical error as far as this function is concerned, so we need some error steps to let the user know what happened.

Error message

Personally, I would not include an error message in this function, but if you prefer, a possible error message could be:

' Function key number is not valid
MsgBox "Invalid function key for " + SKey ' Optional

Remember, the more details we give, the more generally useful the error message will be when catching a problem, and catching it earlier is usually best. Since this it just a utility function, I’d prefer to let the calling macro use the invalid return value to detect the mistake and report something is wrong there.

Return an invalid value for the function on an error

The function expects to return a value even when a logical error occurs, so we specify that explicitly.

GetFunctionKey = wdNoKey

The wdNoKey is a specific WdKey enumeration value, and it seems like a logical choice for an invalid value.

Exit the subroutine

If we encounter a logical error at this point in the function, we need to exit now because other steps follow that we do not want to run.

Exit Function

Revised conditional statement

Assembling our current conditional statement steps, we have:

' Parse function key number based on pattern match
Dim sNumber As String
If SKey Like "*[Ff]##" Then
sNumber = Right(SKey, 2) ' Get two-digit function key text
ElseIf SKey Like "*[Ff]#" Then
sNumber = Right(SKey, 1) ' Get one-digit function key text
Else
' Function key is not valid
MsgBox "Invalid function key for " + SKey ' Optional

GetFunctionKey = wdNoKey
Exit Sub
End If

We're not converting the function key number inside the If statement since this happens with either a single- or double-digit number match. In that case, it makes more sense to convert a valid number after conditional statement, so we only have to include the step once.

Convert the function key number

Word VBA has several functions to convert text to numbers depending on what type of number you need. Like matched a known number with one or two digits, so we already know it is a numeric value. More specifically, it is a counting number. In VBA terms there are several ways to represent them with varying maximum values and memory usage (neither is important for this function). We’ve been using a Long number type for these kinds of numbers, so we’ll stay with it. We’ll store the number in a new variable myKey.

Dim myKey As Long

We’ll get the numeric value using the CLng(…) function.

myKey = CLng(sNumber)

CLng(…) is a standard Word VBA function that converts a known text number to an actual numerical value as a Long number. We actually don’t need a Long here since an Integer is plenty big, but we’re assigning it to a Long value later, so we might as well be consistent.

We convert the number to a function key value if either match is found, one or two digits, so the conversion can be placed after the conditional statement.

Consistency checks on possible function keys

We should always think about and usually check for problems.

Is the number valid?

In general, this CLng(...) function could cause an error if the text number sNumber is not actually a number. Like already matched a number at the end of the text using hashtags, so we should be safe. If this were a general text number, I would first use the IsNumeric(…) function to validate whether it is indeed numeric text before trying to convert it.

What about the function key range?

We need additional checks to make sure our function key number is between 1 and 16 since that’s as high as VBA goes with the function key constants in the WdKey table. We’ve tested numeric ranges before, but let’s have a quick review. We have the function key number stored in the myKey variable, so we can check whether it is greater than or equal to 1.

myKey >= 1

Similarly, myKey needs to be less than or equal to 16.

myKey <= 16

Both conditions need to be True for myKey to be within the range, so we use an And operator to check whether the myKey value is between 1 and 16.

myKey >= 1 And myKey <= 16

Function key conditional statement

Putting this compound condition into a If statement, we finally have:

If myKey >= 1 And myKey <= 16 Then
' Matched function key is okay ...
Else
' Matched function key number is out of range
' Give an invalid result ...
End If
Invalid result

That is, if the purported function key number is zero or less or over sixteen, it cannot be a valid keyboard shortcut assignment. Similar to the logical error segment above, we return the wdNoKey number to indicate an invalid function key result.

GetFunctionKey = wdNoKey

If needed, we could use add an error message, but I prefer the shortcut assignment macro to handle that problem.

No exit necessary this time

At this point, there is no need to exit the function, since it is already ending just after this conditional statement.

Return valid function key value

In the standard WdKey table, F1 begins with a constant value of 112 for wdKeyF1 and increments up by 1 to F16 at a value of 127 for wdKeyF16 (see how the enumeration makes the constants easier to read). After the above validation, we know our function key number stored in the myKey variable has a value somewhere between 1 and 16, inclusive, so we only need to convert it to the appropriate function key constant.

A quick-draw approach would be to add myKey to the wdKeyF1 constant to increment to the appropriate function key, but there is a problem.

wdKeyF1 + myKey ' Does not quite work ...

For example, if myKey is 1 for the function key abbreviation “F1”. To VBA, this addition would be like to wdKeyF1 + 1, but this results in the wrong WdKey constant since 112 + 1 = 113 which is wdKeyF2 in the WdKey table.

wdKeyF1 + 1 ' Example for "F1" gives F2 WdKey constant?

Ooops.

The starting value is wdKeyF1, but our number also starts at 1 for the F1 key, so we need to subtract 1 to get the correct function key value. Since we’re almost done, we’ll store the numeric result in the function name as the return value.

GetFunctionKey = wdKeyF1 + myKey - 1

This works for every function key since the WdKey function key constants also increment by 1. This is a little more programmy than some of the stuff we’ve covered, but it’s the cleanest way to do it. As an alternative, we could simplify the expression a little and just add 111 to myKey.

GetFunctionKey = myKey + 111 ' Alternative not used

But I like keeping things general by using the F1 key starting value wdKeyF1. It’ll probably never change, but I feel better about it.

Gotchas

Where could this go wrong?

We’re relatively safe in the function since the Like searches and the function key value validations both already have error defaults in the Else parts of the respective If statements. Converting sNumber using CLng(…) could crash, in principle, without an actual number, but one of the successful Like searches already identified a candidate text number by this step of the macro, so this should be safe as well.

Final get function key function

The final function to extract a function key value from a keyboard shortcut text is:

Function GetFunctionKey(SKey As String) As WdKey
' Return WdKey value corresponding to the function key from the last
' two or three characters of SKey
' Returns wdNoKey if no matching function key was found

' Parse function key number based on pattern match
' Also catches empty SKey argument
Dim sNumber As String
If SKey Like "*[Ff]##" Then
' Get two-digit function key text
sNumber = Right(SKey, 2)
ElseIf SKey Like "*[Ff]#" Then
' Get one-digit function key text
sNumber = Right(SKey, 1)
Else
' Function key number is missing or invalid
GetFunctionKey = wdNoKey
Exit Function
End If

' Convert the text number
' sNumber is already a valid number based on Like searches
Dim myKey As Long
myKey = CLng(sNumber)

' Validate function key number
If myKey >= 1 And myKey <= 16 Then
' Convert valid function key number to WdKey constant
GetFunctionKey = wdKeyF1 + myKey - 1
Else
' Function key number is outside of valid 1 to 16 range
GetFunctionKey = wdNoKey
End If
End Function

I chose to omit any specific error messages with the two invalid results, but the function assigns an invalid return value of wdNoKey. The calling function can use that value to handle any logical errors based on the invalid result.

Affiliate Links

If you're interested in using Word or another tool related to the article, check out these affiliate links. I may make a small commission if you purchase when using them, but there is no increase in cost for you, and it helps to support this site and associated content.

I've been using Microsoft for Business for commercial use (that's us writers) on one of the lower pricing tiers for years. I get to use my macros, have online storage, and don't have to worry about software updates.