How to hook keyboard inputs globally in vb?

Posted on 2003-03-03
Medium Priority
Last Modified: 2010-04-07

I want hook the keyboard inputs made to all applications currently running on the systemby using visual basic. I have some examples but they hook only current thread's inputs. And also it is necessary to put these inputs into text box. Thus, I will be able to behave according to specified command typed by the user.
I know the mains of the this process but it is a little difficult for me to code it. If you help me in solving this problem I will be preciate.

Thanks in advance
Question by:monarch_ilhan
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 2
  • 2
  • +1

Accepted Solution

imessvb earned 450 total points
ID: 8062624
here's the code from my old program. i know it looks a little too messy... and i had extra stuff specified to my program that you might want to delete: (it detects keyboard input to other apps)

Option Explicit

Private Type POINTAPI
    x As Long
    y As Long
End Type
Public Type EVENTMSG
    message As Long
    paramL As Long
    paramH As Long
    time As Long
    hwnd As Long
End Type
Private Type MSG
    hwnd As Long
    message As Long
    wParam As Long
    lParam As Long
    time As Long
    pt As POINTAPI
End Type
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 Sub CopyMemory Lib "kernel32" _
    Alias "RtlMoveMemory" _
    (Destination As Any, _
    Source As Any, _
    ByVal Length As Long)

Private Declare Function GetAsyncKeyState _
    Lib "user32" _
    (ByVal vKey As Long) _
As Integer

Private Const WH_JOURNALRECORD = 0
Private Const WH_GETMESSAGE = 3
Private Const WH_KEYBOARD = 2
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Private Const WM_SYSKEYDOWN = &H104
Private Const WM_SYSKEYUP = &H105

Private hHook As Long

Public Sub StartHook()
    If hHook = 0 Then
        hHook = SetWindowsHookEx(WH_JOURNALRECORD, AddressOf HookProc, 0&, 0&)
    End If
End Sub

Public Sub EndHook()
    If hHook Then UnhookWindowsHookEx hHook
End Sub

Public Function HookProc(ByVal nCode As Long, ByVal wParam As Long, lParam As Long) As Long
    Dim iShift As Integer, iKey As Integer
    iShift = 0
    If GetAsyncKeyState(vbKeyControl) Then iShift = vbCtrlMask
    If GetAsyncKeyState(vbKeyMenu) Then iShift = iShift + vbAltMask
    If GetAsyncKeyState(vbKeyShift) Then iShift = iShift + vbShiftMask
    Dim winMsg As EVENTMSG
    CopyMemory winMsg, lParam, Len(winMsg)
    iKey = CInt(winMsg.paramL And &HFF)
    Select Case winMsg.message
            If iKey <> vbKeyControl And iKey <> vbKeyMenu And iKey <> vbKeyControl Then
                frmMain.KeyTyped iKey, iShift
            End If
    End Select
    HookProc = CallNextHookEx(hHook, nCode, wParam, lParam)
Debug.Print winMsg.message, iKey
End Function

Author Comment

ID: 8151170
Hello again,
Thank you very much for you suggestions but unfortunatately it didnt work. May be there is a small trick which I couldnt see.
Please could you check it again and inform me soon??

And for motivating you, I am increasing its point from 100 to 150.

Best Regards

Expert Comment

ID: 8154251
what part of it didn't work? did it give any error messages or it simply did not response? if you leave your email i can send my sample code to you.
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.


Expert Comment

ID: 8154277
oh, be sure you call StartHook() in Form_Load() event and EndHook() in Form_Unload() event, and your form should be named "frmMain" and has a public function whose signature is: KeyTyped(Byval KeyCode, Byval Shift)

(the code was originally written in win98, i'll check again to see if it works in win2k)

Author Comment

ID: 8157466
hHook = SetWindowsHookEx(WH_JOURNALRECORD, AddressOf HookProc, 0&, 0&)

The return code of above function becomes Zero (0). So, StartHook process does not start. I did your suggestions but, since the SetWindowsHookEx does not start, it is unable to hook keyboard inputs. I think we may change the above function's parameters.

When I change tha functions as
hHook = SetWindowsHookEx(WH_JOURNALRECORD, AddressOf HookProc, App.hInstance , 0&) it gives a return code and it only hooks in my application not globally.

my email address is monarch_ilhan@yahoo.com

I am looking forward to have your solution suggestions.


Expert Comment

ID: 8200546
A problem with the code, is it's not in a DLL locally nor is it registered that way, so if say, someone hits the Windows key on the keyboard, that program goes dormant and stays that way (the hook is invalidated because the system can't find it after the process change).  I've run into the same situation, only means to fix that is to DLL the testing code and make the DLL locally registered and make sure the threadid is in the SetWindowsHookEx.  That way, any new threads that open up will also include that hook themselves (since a journalrecord is system wide, each thread will hook in if they don't have it present).

To hook the keyboard and mouse directly, you'd really need to write device drivers for them.

>hHook = SetWindowsHookEx(WH_JOURNALRECORD, AddressOf HookProc, App.hInstance , 0&) it gives a return code and it only hooks in my application not globally.

This is what I meant by the threadid being present, if this was in a registered DLL, all future opened threads would also open this hook for their usage and unhook it when they leave.

Expert Comment

ID: 8207769
Sorry monarch_ilhan, the code works fine in win98se, even not in a dll, but not in win2k, not matter acsii or unicode version of the APIs is used...

FunkyMeister, I'll try to put the code in a dll and test in win2k again, thanks for the explanation. btw, since hooking is not recommended except for debugging, do you know of any other methods to hook keyboard/mouse using existing APIs?

Expert Comment

ID: 8216124
Actually, hooking them may not be "recommended", but any mouse driver out there (and Internet keyboard driver as well) does it.  Thought they all use DLL's because each thread must be able to get AT the hook, otherwise it's invalidated and the code stops working (the hook gets "canned").  I've seen it get canned on a 98 machine outside of a dll but not inside of one.  And using a program that shows tasks and module usage, I see my dll listed on every last task (which is what you want).  But the downside is, if you're "late" in the stream, you may be getting sloppy seconds from the system (and may be too late down the list of listeners) and be able to do very little but go, "Oh, thats nice."

What are you hooking the inputs for?  Might help me understand the need.
LVL 49

Expert Comment

ID: 9024014
Hi monarch_ilhan,
It appears that you have forgotten to close this question. I will ask Community Support to close it unless you finalize it within 7 days. I will ask a Community Support Moderator to:

    Split points between: imessvb and FunkyMeister

monarch_ilhan, if you think your question was not answered at all or if you need help, just post a new comment here; Community Support will help you.  DO NOT accept THIS comment as an answer.

EXPERTS: If you disagree with that recommendation, please post an explanatory comment.
DanRollins -- EE database cleanup volunteer

Featured Post


Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The debugging module of the VB 6 IDE can be accessed by way of the Debug menu item. That menu item can normally be found in the IDE's main menu line as shown in this picture.   There is also a companion Debug Toolbar that looks like the followin…
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

752 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question