A stable custom KeyPres event for worksheet cells

Jaafar Tribak

Well-known Member
Joined
Dec 5, 2002
Messages
9,807
Office Version
  1. 2016
Platform
  1. Windows
http://www.box.net/shared/ukx1l761taWorkbook demo

Hi all.

Ever wanted to have a keyPress event for worksheet cells just like those provided by ActiveX textbox controls so you can detect the keys as they are being typed in and act accordingly ?

Workarounds i've used so far involved using a keyboard hook, timers or continuos loops all of which tie up and slow down the application and can potentially crash the application if the project is reset while the code is running.

I've written this small dll whose bytes are stored within the workbook in a hidden worksheet. There is no need to register the dll (its all done on the fly) and more importantly the application seems to remain stable and no crashing is feared even if the code errors out or the VBE is reset !

The only requirement is that the Event procedure(OnKeyPress) MUST be located in the workbook module and MUST be Public to be seen by the dll code.

Code in the workbook module :

Code:
Option Explicit
 
Private Const DCOM_DLL_PATH_NAME As String _
= "C:\WINDOWS\system32\DirectCOM.dll"
 
Private Const JAAFAR_DLL_PATH_NAME As String _
= "C:\KeyPressWatcher.dll"

'CreateObject-Replacement (FileBased)
Private Declare Function GETINSTANCE Lib "DirectCom" _
(FName As String, ClassName As String) As Object

Private Declare Function UNLOADCOMDLL Lib "DirectCom" _
(FName As String, ClassName As String) As Long

Private oKeyPressInstance As Object


'=================================================================
'KeyPress custom event.
'Event Procedure Must be PUBLIC !!! and located in the workbook module.
'Use the ByRef Cancel argument to prevent the drop operation.

'Allow only Alpha characters in cell A1 of Sheets("test")
Public Sub OnKeyPress _
(ByVal Target As Range, ByVal KeyCode As Long, ByRef Cancel As Boolean)
    
    If ActiveSheet Is Sheets("test") Then
        If Target.Address = Range("a1").Address Then
            If IsNumeric(Chr(KeyCode)) Then
                MsgBox "No numeric characters are allowed in the range : " & _
                vbNewLine & Target.Address
                Cancel = True
            End If
        End If
    End If
    
End Sub
'=====================================================================


Private Sub Workbook_Open()

        'Create the DirectCom & KeyPressWatcher dlls.
        Call CreateDlls

        'load an instance of the 'KeyPressWatcher.dll' Class.
        Set oKeyPressInstance = _
        GETINSTANCE(JAAFAR_DLL_PATH_NAME, "KeyPressClass")

        If Not oKeyPressInstance Is Nothing Then
            'start watching user key strokes.
            Call oKeyPressInstance.Start(ThisWorkbook)
        Else
            MsgBox "Unable to load the " & _
            "'KeyPressWatcher' dll.", vbInformation
        End If

End Sub

Private Sub Workbook_BeforeClose(Cancel As Boolean)

    
    If Not oKeyPressInstance Is Nothing Then
        oKeyPressInstance.Finish
        Set oKeyPressInstance = Nothing
    End If

    UNLOADCOMDLL JAAFAR_DLL_PATH_NAME, "KeyPressClass"

    On Error Resume Next
    
    If Len(Dir(JAAFAR_DLL_PATH_NAME)) <> 0 Then
        Kill JAAFAR_DLL_PATH_NAME
    End If

End Sub



'Create the 'DirectCom' & 'KeyPressWatcher' dll from the
'Bytes stored in the '"DllBytes" hidden worksheet.
Private Sub CreateDlls()
 
    Dim Bytes() As Byte
    Dim lFileNum As Integer
    Dim aVar
    Dim x As Long
 
    On Error Resume Next
    
    If Len(Dir(JAAFAR_DLL_PATH_NAME)) = 0 Then
    
       With Worksheets("DllBytes")
           aVar = .Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp)).Value
       End With
     
       ReDim Bytes(LBound(aVar) To UBound(aVar))
       For x = LBound(aVar) To UBound(aVar)
           Bytes(x) = CByte(aVar(x, 1))
       Next
    
       lFileNum = FreeFile
       Open JAAFAR_DLL_PATH_NAME For Binary As #lFileNum
           Put #lFileNum, 1, Bytes
       Close lFileNum
    
    End If
    

    If Len(Dir(DCOM_DLL_PATH_NAME)) = 0 Then
    
        Erase Bytes
        
        With Worksheets("dllBytes")
            aVar = .Range(.Cells(1, 2), .Cells(.Rows.Count, 2).End(xlUp)).Value
        End With
        
        ReDim Bytes(LBound(aVar) To UBound(aVar))
        For x = LBound(aVar) To UBound(aVar)
            Bytes(x) = CByte(aVar(x, 1))
        Next
        lFileNum = FreeFile
        Open DCOM_DLL_PATH_NAME For Binary As #lFileNum
            Put #lFileNum, 1, Bytes
        Close lFileNum
        
    End If
    

End Sub
Tested on Excel 2007 Win 7 only. Any feedback is much appreciated.
 
Last edited:
Jaafar,

I use Excel x64. I understand how WH_KEYBOARD_LL works globally, to listen for input events from the physical keyboard. The listening event is not only Excel specific. I have tried to initialize another Excel session with WH_KEYBOARD_LL to catch the event at the main thread, but no good result. Maybe, I should try again.
This may be of interest to you :
This method should work in x64bit excel unlike the legacy WH_KEYBOARD and WH_KEYBOARD_LL hooks.
 
Upvote 0

Excel Facts

Who is Mr Spreadsheet?
Author John Walkenbach was Mr Spreadsheet until his retirement in June 2019.

Forum statistics

Threads
1,224,823
Messages
6,181,185
Members
453,020
Latest member
Mohamed Magdi Tawfiq Emam

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