KeyUp execute code.

omairhe

Well-known Member
Joined
Mar 26, 2009
Messages
2,040
Office Version
  1. 2019
Platform
  1. Windows
Hey excel gurus,

I would need your help on running a specific code when key state is up. I am already aware of a OnKey method but that is not what I require.

Another way of achieving this would be to use AutoHotKey. With a hotkey assigned to the excel macro that gets triggered on key up state that works only on excel.

will appreciate.
Thank you.
 
I'll be logging off shortly but i'll try writing some code for the arrow keys later ... Stay tuned.
 
Upvote 0

Excel Facts

Waterfall charts in Excel?
Office 365 customers have access to Waterfall charts since late 2016. They were added to Excel 2019.
I'll be logging off shortly but i'll try writing some code for the arrow keys later ... Stay tuned.

Just so you know, the arrow keys need to keep their functionality while the key up should keep its functionality at the same time.
 
Upvote 0
for instance if "a" were to held down. the cell should keep writing letter a but when released pop up message or run macro. same with the arrow keys.

Thanks.
 
Last edited:
Upvote 0
Try this :

1- In a Standard Module :
Code:
Option Explicit

[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If]#If[/URL]  VBA7 Then
    Private Declare PtrSafe Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
    Private Declare PtrSafe Function SetTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As LongPtr
    Private Declare PtrSafe Function KillTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else]#Else[/URL] 
    Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
    Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
    Private Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End]#End[/URL]  If


Public Sub HookArrowKeys()
    SetTimer Application.hwnd, 0, 0, AddressOf WatchKeyState    
End Sub


Public Sub UnHookArrowKeys()
   KillTimer Application.hwnd, 0   
End Sub



Private Sub WatchKeyState()

    Dim vKey As Variant, vKeysArray As Variant, vKeysNames As Variant, i As Integer
    
    vKeysArray = Array(vbKeyDown, vbKeyUp, vbKeyLeft, vbKeyRight, vbKeyLButton)
    vKeysNames = Array("Down", "Up", "Left", "Right", "MouseClick")
    
    For i = 0 To UBound(vKeysArray)
        If GetAsyncKeyState(vKeysArray(i)) Then vKey = vKeysArray(i): Exit For
    Next i
    
    If vKey = vbKeyLButton Then KillTimer Application.hwnd, 0: Exit Sub
    
    On Error Resume Next
    vKey = vKeysNames(i)
    i = GetAsyncKeyState(vbKeyLButton)
     
    If NavigationKeyStateUp Then
        KillTimer Application.hwnd, 0
        Call OnKeyUpPseudoEvent(Selection, CStr(vKey))
    End If
    
End Sub


Private Property Get NavigationKeyStateUp() As Boolean
    
    NavigationKeyStateUp = GetAsyncKeyState(vbKeyDown) + GetAsyncKeyState(vbKeyUp) _
    + GetAsyncKeyState(vbKeyLeft) + GetAsyncKeyState(vbKeyRight) = 0
    
End Property




[B][COLOR=#008000]'=================================================================================
'                                 PSEUDO-EVENT
'=================================================================================[/COLOR][/B]
Private Sub OnKeyUpPseudoEvent(ByVal Target As Range, ByVal vKey As String)
    MsgBox "You Relased the '" & vKey & "' Key" & vbNewLine & "At cell : '" & Target.Address & "'"
End Sub
[B][COLOR=#008000]'==================================================================================[/COLOR][/B]


2- In the Workbook Module :
Code:
Option Explicit

Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
    Call HookArrowKeys
End Sub

Now just navigate the worksheet(s) with the UP,DOWN,RIGHT,LEFT keys and the MsgBox located in then OnKeyUpPseudoEvent routine should pop up when releasing the keys.
 
Upvote 0
Oops! there was a bug in the previous code - Please, ignore it and use the following one


-In a Standard Module

Code:
Option Explicit

[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If"]#If[/URL]  VBA7 Then
    Private Declare PtrSafe Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
    Private Declare PtrSafe Function SetTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As LongPtr
    Private Declare PtrSafe Function KillTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else"]#Else[/URL] 
    Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
    Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
    Private Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End"]#End[/URL]  If


Public Sub HookArrowKeys()

    SetTimer Application.hwnd, 0, 0, AddressOf WatchKeyState
    
End Sub


Public Sub UnHookArrowKeys()

   KillTimer Application.hwnd, 0
   
End Sub


Private Sub WatchKeyState()

    Static vKey As Variant
    Dim vKeysArray As Variant, vKeysNames As Variant, i As Integer
    
    vKeysArray = Array(vbKeyDown, vbKeyUp, vbKeyLeft, vbKeyRight, vbKeyLButton)
    vKeysNames = Array("Down", "Up", "Left", "Right", "MouseClick")
    
    For i = 0 To UBound(vKeysArray)
        If GetAsyncKeyState(vKeysArray(i)) Then vKey = vKeysArray(i): Exit For
    Next i
    
    If vKey = vbKeyLButton Then KillTimer Application.hwnd, 0: Exit Sub
    
    On Error Resume Next
    vKey = vKeysNames(i)
    i = GetAsyncKeyState(vbKeyLButton)
     
    If NavigationKeyStateUp Then
        KillTimer Application.hwnd, 0
        Call OnKeyUpPseudoEvent(Selection, CStr(vKey))
    End If
    
End Sub


Private Property Get NavigationKeyStateUp() As Boolean
    
    NavigationKeyStateUp = GetAsyncKeyState(vbKeyDown) + GetAsyncKeyState(vbKeyUp) _
    + GetAsyncKeyState(vbKeyLeft) + GetAsyncKeyState(vbKeyRight) = 0
    
End Property



[B][COLOR=#008000]'=================================================================================
'                                 PSEUDO-EVENT
'=================================================================================
[/COLOR][/B]
Private Sub OnKeyUpPseudoEvent(ByVal Target As Range, ByVal vKey As String)
    
    MsgBox "You Relased the '" & vKey & "' Key" & vbNewLine & "At cell : '" & Target.Address & "'"
    
End Sub

[B][COLOR=#008000]'==================================================================================[/COLOR][/B]
 
Last edited:
Upvote 0
I have revised the code properly at home and have found a couple of bugs that went unnoticed ... I have fixed them and have updated the code as follows:

Here is a workbook example


Code update:

1- In a Standard Module:
Code:
Option Explicit

[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If]#If[/URL]  VBA7 Then
    Private Declare PtrSafe Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
    Private Declare PtrSafe Function SetTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As LongPtr
    Private Declare PtrSafe Function KillTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else]#Else[/URL] 
    Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
    Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
    Private Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End]#End[/URL]  If


Public Sub HookArrowKeys()

    SetTimer Application.hwnd, 0, 0, AddressOf WatchKeyState

End Sub


Private Sub WatchKeyState()
    
    Static vKey As Variant
    Static bArrowKeyWasPressed As Boolean
    Dim bArrowKeyPressed As Boolean
    Dim vKeysArray As Variant, vKeysNames As Variant, i As Integer
     
    vKeysArray = Array(vbKeyDown, vbKeyUp, vbKeyLeft, vbKeyRight, vbKeyLButton)
    vKeysNames = Array("Down", "Up", "Left", "Right", "MouseClick")
    
    For i = 0 To UBound(vKeysArray)
        If GetAsyncKeyState(vKeysArray(i)) Then vKey = vKeysArray(i): bArrowKeyPressed = True: Exit For
    Next i

    If vKey = vbKeyLButton Then KillTimer Application.hwnd, 0: Exit Sub

    On Error Resume Next
    vKey = vKeysNames(i)
    i = GetAsyncKeyState(vbKeyLButton)
    
    If NavigationKeyStateUp Then
        If bArrowKeyWasPressed Then
            KillTimer Application.hwnd, 0
            Call ThisWorkbook.OnArrowKeyUpPseudoEvent(Selection, CStr(vKey))
        End If
    End If
  
    bArrowKeyWasPressed = bArrowKeyPressed
    If bArrowKeyPressed = False Then KillTimer Application.hwnd, 0
    
End Sub


Private Property Get NavigationKeyStateUp() As Boolean
    
    NavigationKeyStateUp = GetAsyncKeyState(vbKeyDown) + GetAsyncKeyState(vbKeyUp) _
    + GetAsyncKeyState(vbKeyLeft) + GetAsyncKeyState(vbKeyRight) = 0
    
End Property



2- In the ThisWorkbook Module:
Code:
Option Explicit


Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)

    Call HookArrowKeys

End Sub


[COLOR=#008000][B]'=================================================================================
'                           PSEUDO-EVENT
'=================================================================================[/B][/COLOR]
Public Sub OnArrowKeyUpPseudoEvent(ByVal Target As Range, ByVal vKey As String)
    
    MsgBox "{" & vKey & "} arrow Key released" & " [MENTION=167149]cell[/MENTION] : ''" & _
    Target.Parent.Name & "!" & Target.Address & "''", vbInformation
    
    [B][COLOR=#008000]'OTHER EXISTING CODE GOES HERE ....[/COLOR][/B]
    
End Sub
[B][COLOR=#008000]'==================================================================================[/COLOR][/B]

Despite using a windows timer + callback , the code should be stable... Also, the timer doesn't have a real impact on performance as the timer is only activated for a very short time while navigating the worksheet(s) until the Arrow keys are released and stops immediately thereafter.
 
Upvote 0
Thank you so much,

This brought a smile on my face. Kudos.
 
Upvote 0
Happy to to have helped.

I am assuming you have used the code in post#16 - Right ?


Yes my intital response was for the previous code as that worked aswell but then I updated to post#16 and it is all good now.

I was in search for something like this for a long time. Highlighting the row while selection is on the move can be distracting because I wanted to highlight the selected row only when seletion was at rest meannig on keyup state, so that the fonts in the first cells of the selected row and column shall be colored into green . we have conditional formatting and vba codes and even Kutools for that but the code you presented is quite sleek and right on the money.
 
Last edited:
Upvote 0
omairhe

Excellent ! I too have learnt in the process as this was quite a challenging question and is not a common request with excel

Thanks for the feedback.
 
Last edited:
Upvote 0

Forum statistics

Threads
1,214,585
Messages
6,120,394
Members
448,957
Latest member
Hat4Life

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top