Fair enough. But I'll still post my proof of concept of an Application_KeyPreview (as opposed to Form_KeyPreview) idea. For the example you'll need two forms (one with at least a checkbox, textbox and command button; one or two extra controls that can get the focus would also be nice. The second form can have controls or not, as you please). And you'll need a module.
Drop the following code in Form1:
[tt]
Option Explicit
Private Sub chkHookIt_Click()
ApplicationKeyPreview (chkHookIt = vbChecked)
End Sub
Private Sub Command1_Click()
Form2.Show
End Sub
Private Sub Form_Unload(Cancel As Integer)
Application_KeyPreview False
End Sub
[/tt]
Then paste the following into the module:
[tt]
Option Explicit
Private Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Private Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long
Private Const WH_KEYBOARD = 2
Private Const HC_ACTION = 0
Private Const VK_SHIFT = &H10
Private Const VK_CAPITAL = &H14
Private prevLowLevelKybd As Long
Public Sub Application_KeyPreview(WantHook As Boolean)
If WantHook = True Then
prevLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD, AddressOf vbKeyboardProc, App.hInstance, 0)
ElseIf prevLowLevelKybd Then
UnhookWindowsHookEx prevLowLevelKybd
prevLowLevelKybd = 0
End If
End Sub
Private Function vbKeyboardProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim KeyPress As Long
' Is it a keyboard message, with a key going down?
If (nCode = HC_ACTION) And ((lParam And &HC0000000) <> 0) Then
' OK, start processing key
' Note we only have a short period of time to do this, so do as little as possible here...
KeyPress = MapVirtualKey(wParam, 2) ' Convert virtual key code
' Cheap (and flawed, but good enough for sake of example) method of dealing with SHIFT and CAPS LOCK
If ((GetKeyState(VK_CAPITAL) And &H1)) <> 0 Then KeyPress = KeyPress Xor &H20 ' CAPS LOCK ON
If ((GetKeyState(VK_SHIFT) And &H80)) = 0 Then KeyPress = KeyPress Xor &H20 ' SHIFT not pressed
' In this example we just pop the pressed key into a textbox
Form1.Text1.Text = Chr(KeyPress)
End If
' OK, pass everything on for default processing
vbKeyboardProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End Function