Share via

Detecting whether CTRL key is down

Anonymous
2011-05-05T23:56:49+00:00

(I apologize if this is a duplicate posting.  I could not find my own post)

I would like to detect whether the CTRL key is down during a mouse click.  I do some processing using the Worksheet_Selection_Change sub.  If the CTRL key is down during the selection, I would like to alter the process.

Any suggestions?

Microsoft 365 and Office | Excel | For home | Windows

Locked Question. This question was migrated from the Microsoft Support Community. You can vote on whether it's helpful, but you can't add comments or replies or follow the question.

0 comments No comments

Answer accepted by question author

Anonymous
2011-05-06T01:30:08+00:00

Lon wrote:

Thanks for the comment about the key being released before the macro is called.  However, this program will be meant only for my own use, and I will know to keep the key down long enough.

Okay ;-).  See this article.  However, my experiments suggest that the article might not be accurate, at least for WinXP, my platform.

Try the following test event macro, pressing and releasing control in a number of contexts.  In addition to 0 ("not set") and &h80 ("set -128"), sometimes I get &h01 ("set 1") and &h81 ("set -127").

EDIT....  Well, if we limit ourselves to iResult And &h80 for VK_CONTROL, as this article states, it reliably tells us if the key is up or down.  It is my nature to question documentation to ferret out undocumented nuances, especially for kernel features.  So I'm curious what these other states might tell us, if anything.  But the other bits might simply be "garbage".  TBD.

Caveat:  try this with a new worksheet.  It destroys column A.

Private Declare Function GetKeyState Lib "user32" _

    (ByVal vKey As Long) As Integer

Private Const VK_SHIFT As Long = &H10

Private Const VK_CONTROL As Long = &H11

Private Const VK_MENU As Long = &H12

Private Const VK_CAPITAL = &H14

Private Const VK_NUMLOCK = &H90

Private Const VK_SCROLL = &H91

'initialize by resetting VBA; click Run > Reset

Private n As Long

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

Dim iResult As Integer

If n = 0 Then Range("a:a").Clear: n = 1

iResult = GetKeyState(VK_CONTROL) And &H80  'EDITed

'note: iResult < 0 means bit 15 is set

If iResult <> 0 Then Cells(n, 1) = "set " & iResult _

Else Cells(n, 1) = "not set"

n = n + 1

End Sub

Was this answer helpful?

0 comments No comments

4 additional answers

Sort by: Most helpful
  1. Anonymous
    2011-05-07T20:06:28+00:00

    The article referred to led me to another article by Chip Pearson, which contained highly valuable information on testing the status of SHIFT, ALT, and CTRL keys.  Simplifying the coding presented solved my more focused issue of detecting whether the CTRL key is down.  Here is the code I ended up with:

    Option Explicit

    Option Compare Text

    Private Declare Function GetKeyState Lib "user32" ( _

        ByVal nVirtKey As Long) As Integer

    Private Const KEY_MASK As Integer = &HFF80 ' decimal -128

    Public Const BothLeftAndRightKeys = 0   ' Note: Bit-wise AND of LeftKey and RightKey

    Public Const LeftKey = 1

    Public Const RightKey = 2

    Public Const LeftKeyOrRightKey = 3      ' Note: Bit-wise OR of LeftKey and RightKey

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

        Dim Res As Long

         Res = GetKeyState(vbKeyControl) And KEY_MASK

        IsControlKeyDown = CBool(Res)

    End Function

    Thanks for the help.

    Was this answer helpful?

    0 comments No comments
  2. Anonymous
    2011-05-06T07:18:18+00:00

    The following event macro is more fun.  It measures reaction time:  how quickly you can release Ctrl after releasing the left "mouse" button (left button on my touchpad).

    I can do it before we enter the first GetKeyState call.  But when I try to delay the release the least, I have gotten it to be as little as about 20 milliseconds :-).  However, 115 to 190 milliseconds is more natural.


    Private Const VK_SHIFT As Long = &H10

    Private Const VK_CONTROL As Long = &H11

    Private Const VK_MENU As Long = &H12

    Private Const VK_CAPITAL = &H14

    Private Const VK_NUMLOCK = &H90

    Private Const VK_SCROLL = &H91

    'initialize by reseting VBA; click Run > Reset

    Private n As Long

    Private Declare Function GetKeyState Lib "user32" _

        (ByVal vKey As Long) As Integer

    Private Declare Function QueryPerformanceFrequency Lib "kernel32" _

       (ByRef freq As Currency) As Long

    Private Declare Function QueryPerformanceCounter Lib "kernel32" _

       (ByRef cnt As Currency) As Long

    Private Sub Worksheet_SelectionChange(ByVal Target As Range)

    Dim iResult As Integer, iResult2 As Integer, x As Long

    Dim sc As Currency, ec As Currency, dt As Double

    'measure time for user to release CTRL, if set

    sc = myTimer

    iResult0 = GetKeyState(VK_CONTROL)

    If (iResult0 And &H80) = 0 Then

       ec = myTimer

       dt = myElapsedTime(ec - sc)

       iResult2 = iResult0

    Else

       Do

          x = DoEvents()

          iResult2 = GetKeyState(VK_CONTROL)

          ec = myTimer

          dt = myElapsedTime(ec - sc)

       Loop Until (iResult2 And &H80) = 0 Or dt >= 1

    End If

    'note: iResult < 0 means bit 15 is set

    If n = 0 Then Range("a:c").Clear: n = 1

    Cells(n, 1) = iResult0

    Cells(n, 2) = iResult2

    Cells(n, 3) = dt

    n = n + 1

    End Sub

    Private Function myTimer() As Currency

    QueryPerformanceCounter myTimer

    End Function

    Private Function myElapsedTime(dc As Currency) As Double

    Static freq As Currency, df As Double

    If freq = 0 Then QueryPerformanceFrequency freq: df = freq

    myElapsedTime = dc / df

    End Function

    Was this answer helpful?

    0 comments No comments
  3. Anonymous
    2011-05-06T00:07:52+00:00

    Thanks for the comment about the key being released before the macro is called.  However, this program will be meant only for my own use, and I will know to keep the key down long enough.

    Was this answer helpful?

    0 comments No comments
  4. Anonymous
    2011-05-05T23:59:48+00:00

    Lon wrote:

    I would like to detect whether the CTRL key is down during a mouse click.  I do some processing using the Worksheet_Selection_Change sub.  If the CTRL key is down during the selection, I would like to alter the process.

    The CTRL key will usually have been released by the time the Worksheet_SelectionChange event macro is called.  It depends on how lazy the user is ;-).

    Was this answer helpful?

    0 comments No comments