ThreeWave Testing Key States

This page describes VBA code to test the state of the SHIFT, CTRL, and ALT keys.
ShortFadeBar

Introduction

You may wish to provide varying behavior of a procedure depending on the state of the SHIFT, ALT, or CTRL keys. For example, you could design a procedure to omit confirmation dialogs if the SHIFT key is down when the procedure is run. Excel itself does things similar to this. For example, the items on the EDIT menu are different if you have the SHIFT key down as you access the menu. Using some simple Windows API functions, you can do similar things.

VBA does not give you access to the keyboard state. Therefore, you must use the GetKeyState Windows API function. This function returns the state (pressed or not pressed) of a specified key. The code in this article provides three functions written in VBA that you can use in your own code:

  • IsShiftKeyDown Indicates whether the left, right, either, or both SHIFT keys are pressed.
  • IsControlKeyDown Indicates whether the left, right, either, or both CTRL keys are pressed.
  • IsAltKeyDown Indicates whether the left, right, either, or both ALT keys are pressed.
Each of these procedures returns True or False indicating the state of the key(s) -- True if the key is pressed or False if the key is not pressed.

The function declarations are as follows:

    Public Function IsShiftKeyDown(Optional LeftOrRightKey As Long = LeftKeyOrRightKey) As Boolean

    Public Function IsControlKeyDown(Optional LeftOrRightKey As Long = LeftKeyOrRightKey) As Boolean

    Public Function IsAltKeyDown(Optional LeftOrRightKey As Long = LeftKeyOrRightKey) As Boolean

Each of these procedures takes an optional parameters indicating whether the left, right, either or both keys are to be tested. If this parameter is omitted, the code tests for either right or left or both, make no distinction whether the key is the left or right key. The values allowed for this parameter are:
    Public Const BothLeftAndRightKeys = 0    ' BOTH left and right together
    Public Const LeftKey = 1                 ' LEFT key only
    Public Const RightKey = 2                ' RIGHT key only
    Public Const LeftKeyOrRightKey = 3       ' EITHER left or right or BOTH

While the code in this article test only the SHIFT, CTRL, and ALT keys, it can be adapted to test any key. To do this you would supply the appropriate key code to the GetKeyState API function. (See the MSDN article for GetKeyState for more information.)

There is nothing specific to Excel or indeed VBA in this code. You can use this code in any application that supports VBA or in VB6 code.

The complete code is shown below. The code is also available as a downloadable bas module file.

Option Explicit
Option Compare Text
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' modKeyState
' By Chip Pearson, www.cpearson.com, chip@cpearson.com
' This code is at www.cpearson.com/Excel/KeyTest.aspx
' This module contains functions for testing the state of the SHIFT, ALT, and CTRL
' keys.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''


''''''''''''''''''''''''''''''''''''''''''''''''''''
' Declaration of GetKeyState API function. This
' tests the state of a specified key.
''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Declare Function GetKeyState Lib "user32" ( _
    ByVal nVirtKey As Long) As Integer
    
''''''''''''''''''''''''''''''''''''''''''
' This constant is used in a bit-wise AND
' operation with the result of GetKeyState
' to determine if the specified key is
' down.
''''''''''''''''''''''''''''''''''''''''''
Private Const KEY_MASK As Integer = &HFF80 ' decimal -128

'''''''''''''''''''''''''''''''''''''''''
' KEY CONSTANTS. Values taken
' from VC++ 6.0 WinUser.h file.
'''''''''''''''''''''''''''''''''''''''''
Private Const VK_LSHIFT = &HA0
Private Const VK_RSHIFT = &HA1
Private Const VK_LCONTROL = &HA2
Private Const VK_RCONTROL = &HA3
Private Const VK_LMENU = &HA4
Private Const VK_RMENU = &HA5
'''''''''''''''''''''''''''''''''''''''''
' The following four constants simply
' provide other names, CTRL and ALT,
' for CONTROL and MENU. "CTRL" and
' "ALT" are more familiar than
' "CONTROL" and "MENU". These constants
' provide no additional functionality.
' They simply provide more familiar
' names.
'''''''''''''''''''''''''''''''''''''''''
Private Const VK_LALT = VK_LMENU
Private Const VK_RALT = VK_RMENU
Private Const VK_LCTRL = VK_LCONTROL
Private Const VK_RCTRL = VK_RCONTROL

''''''''''''''''''''''''''''''''''''''''''''
' The following constants are used to specify,
' when testing CTRL, ALT, or SHIFT, whether
' the Left key, the Right key, either the
' Left OR Right key, or BOTH the Left AND
' Right keys are down.
'
' By default, the key-test procedures make
' no distinction between the Left and Right
' keys and will return TRUE if either the
' Left or Right (or both) key is down.
''''''''''''''''''''''''''''''''''''''''''''
Public Const BothLeftAndRightKeys = 0   
Public Const LeftKey = 1
Public Const RightKey = 2
Public Const LeftKeyOrRightKey = 3      


Public Function IsShiftKeyDown(Optional LeftOrRightKey As Long = LeftKeyOrRightKey) As Boolean
''''''''''''''''''''''''''''''''''''''''''''''''
' IsShiftKeyDown
' Returns TRUE or FALSE indicating whether the
' SHIFT key is down.
'
' If LeftOrRightKey is omitted or LeftKeyOrRightKey,
' the function return TRUE if either the left or the
' right SHIFT key is down. If LeftKeyOrRightKey is
' LeftKey, then only the Left SHIFT key is tested.
' If LeftKeyOrRightKey is RightKey, only the Right
' SHIFT key is tested. If LeftOrRightKey is
' BothLeftAndRightKeys, the codes tests whether
' both the Left and Right keys are down. The default
' is to test for either Left or Right, making no
' distiction between Left and Right.
''''''''''''''''''''''''''''''''''''''''''''''''
    Dim Res As Long
    
    Select Case LeftOrRightKey
        Case LeftKey
            Res = GetKeyState(VK_LSHIFT) And KEY_MASK
        Case RightKey
            Res = GetKeyState(VK_RSHIFT) And KEY_MASK
        Case BothLeftAndRightKeys
            Res = (GetKeyState(VK_LSHIFT) And GetKeyState(VK_RSHIFT) And KEY_MASK)
        Case Else
            Res = GetKeyState(vbKeyShift) And KEY_MASK
    End Select
    
    IsShiftKeyDown = CBool(Res)
End Function

Public Function IsControlKeyDown(Optional LeftOrRightKey As Long = LeftKeyOrRightKey) As Boolean
''''''''''''''''''''''''''''''''''''''''''''''''
' IsControlKeyDown
' Returns TRUE or FALSE indicating whether the
' CTRL key is down.
'
' If LeftOrRightKey is omitted or LeftKeyOrRightKey,
' the function return TRUE if either the left or the
' right CTRL key is down. If LeftKeyOrRightKey is
' LeftKey, then only the Left CTRL key is tested.
' If LeftKeyOrRightKey is RightKey, only the Right
' CTRL key is tested. If LeftOrRightKey is
' BothLeftAndRightKeys, the codes tests whether
' both the Left and Right keys are down. The default
' is to test for either Left or Right, making no
' distiction between Left and Right.
''''''''''''''''''''''''''''''''''''''''''''''''
    Dim Res As Long
    
    Select Case LeftOrRightKey
        Case LeftKey
            Res = GetKeyState(VK_LCTRL) And KEY_MASK
        Case RightKey
            Res = GetKeyState(VK_RCTRL) And KEY_MASK
        Case BothLeftAndRightKeys
            Res = (GetKeyState(VK_LCTRL) And GetKeyState(VK_RCTRL) And KEY_MASK)
        Case Else
            Res = GetKeyState(vbKeyControl) And KEY_MASK
    End Select
    
    IsControlKeyDown = CBool(Res)

End Function

Public Function IsAltKeyDown(Optional LeftOrRightKey As Long = LeftKeyOrRightKey) As Boolean
''''''''''''''''''''''''''''''''''''''''''''''''
' IsAltKeyDown
' Returns TRUE or FALSE indicating whether the
' ALT key is down.
'
' If LeftOrRightKey is omitted or LeftKeyOrRightKey,
' the function return TRUE if either the left or the
' right ALT key is down. If LeftKeyOrRightKey is
' LeftKey, then only the Left ALT key is tested.
' If LeftKeyOrRightKey is RightKey, only the Right
' ALT key is tested. If LeftOrRightKey is
' BothLeftAndRightKeys, the codes tests whether
' both the Left and Right keys are down. The default
' is to test for either Left or Right, making no
' distiction between Left and Right.
''''''''''''''''''''''''''''''''''''''''''''''''
    Dim Res As Long
    
    Select Case LeftOrRightKey
        Case LeftKey
            Res = GetKeyState(VK_LALT) And KEY_MASK
        Case RightKey
            Res = GetKeyState(VK_RALT) And KEY_MASK
        Case BothLeftAndRightKeys
            Res = (GetKeyState(VK_LALT) And GetKeyState(VK_RALT) And KEY_MASK)
        Case Else
            Res = GetKeyState(vbKeyMenu) And KEY_MASK
    End Select
    
    IsAltKeyDown = CBool(Res)

End Function

The following are test procedures to illustrate the code. Run the procedure named Test and then press the keys that you want to test. Test calls ProcTest via OnTime to allow you to press the appropriate keys. The results are displayed in the Debug window of the VBA Editor.


Sub Test()
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Test
' This is a procedure to test and demonstrate the Key-State
' functions above. Since you can't run a macro in the VBA
' Editor if the SHIFT, ALT, or CTRL key is down, this procedure
' uses OnTime to execute the ProcTest test procedure. OnTime
' will call ProcTest two seconds after running this Test
' procedure. Immediately after executing Test, press the
' key(s) (Left/Right SHIFT, ALT, or CTRL) you want to test
' for. The procedure called by OnTime, ProcTest, displays the
' status of the Left/Right SHIFT, ALT, and CTRL keys.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Application.OnTime Now + TimeSerial(0, 0, 2), "ProcTest", , True
End Sub


Sub ProcTest()
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' ProcTest
' This procedure simply displays the status of the Left adn Right
' SHIFT, ALT, and CTRL keys.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Debug.Print "SHIFT KEY: ", "LEFT: " & CStr(IsShiftKeyDown(LeftKey)), _
                           "RIGHT: " & CStr(IsShiftKeyDown(RightKey)), _
              "EITHER: " & CStr(IsShiftKeyDown(LeftKeyOrRightKey)), _
                           "BOTH:   " & CStr(IsShiftKeyDown(BothLeftAndRightKeys))
                        
Debug.Print "ALT KEY:   ", "LEFT: " & CStr(IsAltKeyDown(LeftKey)), _
                           "RIGHT: " & CStr(IsAltKeyDown(RightKey)), _
                           "EITHER: " & CStr(IsAltKeyDown(LeftKeyOrRightKey)), _
                           "BOTH:   " & CStr(IsAltKeyDown(BothLeftAndRightKeys))
                        
Debug.Print "CTRL KEY:   ", "LEFT: " & CStr(IsControlKeyDown(LeftKey)), _
                            "RIGHT: " & CStr(IsControlKeyDown(RightKey)), _
                            "EITHER: " & CStr(IsControlKeyDown(LeftKeyOrRightKey)), _
                            "BOTH:   " & CStr(IsControlKeyDown(BothLeftAndRightKeys))

End Sub

SectionBreak

This page last updated: 5-October-2007

-->