KeyCode and Shift Arguments
In yesterday's article, I wrote about how to add an event handler to the KeyDown event of a text box control. As a reminder, our goal was to override the default behavior of the up and down arrow keys on a continuous Access form.
By default, the up and down arrow keys move to the previous or next form control. On a continuous form laid out in a grid format, the more intuitive behavior would be for the up and down arrow keys to move between records.
The Starting Point
At the end of yesterday's article, we had gotten to the point where Access had auto-generated the following code:
Private Sub tbDiscount_KeyDown(KeyCode As Integer, Shift As Integer)
End Sub
The tbDiscount_KeyDown
routine is the event handler for the tbDiscount text box's Key Down event. Whenever the user presses any key on the keyboard while the tbDiscount text box has the focus, this routine will execute.
KeyDown event arguments
Let's start by discussing the event arguments, KeyCode and Shift.
KeyCode
The KeyCode argument corresponds to the key on the keyboard that the user pressed. The argument is an integer, but to make your code more readable you'll want to use the vbKeyCode constants, such as vbKeyA
, vbKeyReturn
, or vbKeyNumpad3
.
Perhaps the most important thing to note about the KeyCode argument is that it is passed by reference. This means that we can assign a different value to the KeyCode variable within the routine and it will be as if we pressed that other key instead.
For example, if we really wanted to mess with someone, we could do something like this:
Private Sub tbKeySwitcher_KeyDown(KeyCode As Integer, Shift As Integer)
Select Case KeyCode
Case vbKeyW: KeyCode = vbKeyQ
Case vbKeyQ: KeyCode = vbKeyW
End Select
End Sub
While this can be a fun prank, it's not particularly useful. The main reason you would assign a value to the KeyCode argument is if you wanted to block the default behavior of the key. To do this, you would set KeyCode to zero. I often use the following technique to disable the default behavior of a key press, add special handling for certain keys, then restore the default behavior for all other keys.
Private Sub tbSample_KeyDown(KeyCode As Integer, Shift As Integer)
Dim SaveKeyCode As Integer
SaveKeyCode = KeyCode
KeyCode = 0
Select Case SaveKeyCode
Case vbKeyUp
'Do something
Case vbKeyDown
'Do something else
Case vbKeyLeft
'Do another thing
Case vbKeyRight
'Do yet some other thing
Case Else
'Restore default behavior to all other keys
KeyCode = SaveKeyCode
End Select
End Sub
Shift Argument
The Shift argument contains information about the so-called modifier keys, namely [Shift], [Ctrl], and [Alt]. The argument is a bit mask. These are the values that comprise the mask:
- 1: [Shift] acShiftMask
- 2: [Ctrl] acCtrlMask
- 4: [Alt] acAltMask
Since the bit mask represents three boolean values, there are eight possible values for the Shift argument:
- 0: {no modifier keys in use}
- 1: [Shift]
- 2: [Ctrl]
- 3: [Shift] + [Ctrl]
- 4: [Alt]
- 5: [Shift] + [Alt]
- 6: [Ctrl] + [Alt]
- 7: [Shift] + [Ctrl] + [Alt]
The best way to check if any particular modifier key is in use is by performing a bitwise AND operation. For example:
Sub TestShiftBitMask()
Dim Shift As Integer
For Shift = 0 To 7
Debug.Print vbNewLine; "Shift code:"; Shift;
If Shift And acShiftMask Then Debug.Print " [Shift] ";
If Shift And acCtrlMask Then Debug.Print " [Ctrl] ";
If Shift And acAltMask Then Debug.Print " [Alt] ";
Next Shift
End Sub
Generated Events
Each pressed key generates a separate event. For example, if I were to press [Ctrl] + [Alt] + [Shift] + [P], that would generate four separate events:
Private Sub tbMyText_KeyDown(KeyCode As Integer, Shift As Integer)
Debug.Print "KeyCode: "; KeyCode, "Shift: "; Shift
End Sub
Updated [2021-05-01]: Add paragraph about setting KeyCode argument to zero along with accompanying sample routine, tbSample_KeyDown.