Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How do I "get" keystrokes? 7

Status
Not open for further replies.

Guest_imported

New member
Jan 1, 1970
0
I know how to use SendKeys, but i'd like to capture keystrokes (outside of my program), how can I do this?
Thanks,
Tom
 
I don't believe you can capture keystrokes from outside your program in VB, but I do know it's possible in VC++ by eavsdropping on windows messages. Exactly what that sytax would be, you'd have to go to a VC++ forum, and someone there should know. But hey, I've been wrong before, and it might be possible in VB.

Kevin
 
Yes, it can be done in VB. But the method is somewhat inefficient. Try:
[tt]
Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer

Function GetKey$()
For Cnt = 32 To 128
If GetAsyncKeyState(Cnt) <> 0 Then
GetKey$ = Chr$(Cnt)
Exit For
End If
Next Cnt
End Function
[/tt]
Then place the following in a timer...
[tt]
Static OldKey$
Ret$ = GetKey$
If Ret$ <> OldKey$ Then
OldKey = Ret$
WasTyped$ = WasTyped$ + OldKey$
End If
[/tt]
WasTyped$ will contain a bit of garbage followed by (almost) everything that was typed. Note that GetAsyncKeyState ignores the shift-state of the keypress. Also note that the use of a timer has more than one disadvantage.

System-wide hooks in VB? I will leave the discussion to others.
VCA.gif

Alt255@Vorpalcom.Intranets.com​
 
To do a system wide hook in VB, you will have to do what Alt255 suggested. There is a better approach that involves monitoring the OS message queue, but the callback for that has to be in a C++ DLL . . . sorry pure VB won't work for this method. There have been several long threads on this subject and the answer is always the same . . . the callback for the Window Hook has to be in C++. - Jeff Marler B-)
 
It IS possible in VB - as long as you are running under NT4/W2000...
 
StrongM,
How would you do this (under NT/2K) using ONLY Visual Basic? I can do it almost entriely in VB, but I need a small C++ DLL to accept the call back. Remember that it has to monitor keypresses in ALL prcoesses not just the current one. - Jeff Marler B-)
 
StrongM,
One more comment . . . if you are only monitoring the current process, then the callback can be in a VB Module . . . If you are moniroting for all processes, the callback has to be in a DLL since DLLs are only loaded once in physical memory and their code is mapped to each virtual process space that uses it. That allows them to receive calls from each process. The problem here is that VB (unless you trick the compiler) will not export public APIs (not COM methods) that you can use as a CallBack Address. - Jeff Marler B-)
 
Sure. I'm aware of all that, which is why the approach has to be slightly different.

All the following in a module: [tt]

Option Explicit

Public Declare Sub CopyMemory Lib &quot;kernel32&quot; Alias &quot;RtlMoveMemory&quot; (Destination As Any, Source As Any, ByVal Length As Long)

Public Declare Function GetKeyState Lib &quot;user32&quot; (ByVal nVirtKey As Long) As Integer

Public Declare Function SetWindowsHookEx Lib &quot;user32&quot; Alias &quot;SetWindowsHookExA&quot; (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long

Public Declare Function CallNextHookEx Lib &quot;user32&quot; (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long

Public Declare Function UnhookWindowsHookEx Lib &quot;user32&quot; (ByVal hHook As Long) As Long

Public Const HC_ACTION = 0
Public Const WM_KEYDOWN = &H100
Public Const VK_SHIFT = &H10
Public Const VK_CAPITAL = &H14

Public prevLowLevelKybd As Long

Public Type KBDLLHOOKSTRUCT
vkCode As Long ' virtual keycode
scanCode As Long ' hardware scancode
flags As Long
time As Long
dwExtraInfo As Long
End Type

Public Const WH_KEYBOARD_LL = 13

Public Function LowLevelKeyboardProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Dim HookStruct As KBDLLHOOKSTRUCT
Dim IsShifted As Boolean

If (nCode = HC_ACTION) Then

If wParam = WM_KEYDOWN Then
CopyMemory HookStruct, ByVal lParam, Len(HookStruct)
IsShifted = (GetKeyState(VK_SHIFT) And &H8000) Or (GetKeyState(VK_CAPITAL) And &H1) ' Check if character is shifted or not. Don't really need to bother with this if only interested in virtual key codes
' At this point we have correct info in HookStruct, and shifted status in IsShifted.
' So do whatever it it that you want to do...
End If

End If

LowLevelKeyboardProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)

End Function

Public Sub ToggleHook(WantHook As Boolean)
If WantHook = True Then
prevLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf LowLevelKeyboardProc, App.hInstance, 0)
Else
UnhookWindowsHookEx prevLowLevelKybd
prevLowLevelKybd = 0
End If
End Sub

[/tt]

And, for this example, I have a small form with a checkbox on it call chkHookIt and the following code: [tt]

Option Explicit

Private Sub chkHookIt_Click()
ToggleHook (chkHookIt = vbChecked)
End Sub


Private Sub Form_Unload(Cancel As Integer)
If prevLowLevelKybd <> 0 Then UnhookWindowsHookEx prevLowLevelKybd
End Sub
[/tt]
 
strongm,
I like it! It seems to work great on my 2K box . . . I need to look at it a bit closer later on, but for the moment could you tell me why this will not work under Win9x? - Jeff Marler B-)
 
<grin> Glad you like it. The reason it only works in NT4/W2000 is that W9x doesn't support the WH_KEYBOARD_LL in SetWindowsHookEx (it didn't exist in NT4 either, until SP3)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top