Keyboard Events in VB ?

Posted on 2008-10-23
Medium Priority
Last Modified: 2013-11-27
I am trying to create a very simple keyboard test app for non-standard keyboard and just can't get going...
I would like to change the colour of a form panel when a corresponding key is pressed.
e.g. create PanelA and change the backcolour to red while key "A" is pressed and green when released.
I have managed to do this with a button using the button text "&A" on the button but this will cause problems as half the keys on the non-standard keyboard are combinations, ie ALT+A, ALT+B etc.
i have some code, but as it may be completely wrong/misleading i have not posted it here.
If anyone could help me start off with just one or two keys i'm sure i can take it from there and it will be apreciated, thanks
Question by:lewisma2
  • 6
  • 5
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 22787497
Use a low level keyboard hook via WH_KEYBOARD_LL.

Below is a simple example to get you started.

*** NOTE *** The hook does NOT work while running in the IDE!  Build the solution and run the executable located in your ..\bin\release folder.
Imports System.Runtime.InteropServices
Public Class Form1
    Private WithEvents llkb As LowLevelKeyBoardhook
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        llkb = New LowLevelKeyBoardhook
    End Sub
    Private Sub llkb_KeyDown(ByVal vkCode As Integer) Handles llkb.KeyDown
        Label1.BackColor = Color.Red
        Label1.Text = "KeyDown: " & vkCode
        Select Case vkCode
            Case Keys.A
                lblA.BackColor = Color.Red
        End Select
    End Sub
    Private Sub llkb_KeyUp(ByVal vkCode As Integer) Handles llkb.KeyUp
        Label1.BackColor = Control.DefaultBackColor
        Label1.Text = "KeyUp: " & vkCode
        Select Case vkCode
            Case Keys.A
                lblA.BackColor = Control.DefaultBackColor
        End Select
    End Sub
    Public Class LowLevelKeyBoardhook
        Private Const HC_ACTION As Integer = 0
        Private Const WH_KEYBOARD_LL As Integer = 13
        Private Const WM_KEYDOWN As Integer = &H100
        Private Const WM_SYSKEYDOWN As Integer = &H104
        Private Const WM_KEYUP As Integer = &H101
        Private Const WM_SYSKEYUP As Integer = &H105
        Public Structure KBDLLHOOKSTRUCT
            Public vkCode As Integer
            Public scancode As Integer
            Public flags As Integer
            Public time As Integer
            Public dwExtraInfo As Integer
        End Structure
        Private Declare Function SetWindowsHookEx Lib "user32" _
            Alias "SetWindowsHookExA" ( _
            ByVal idHook As Integer, _
            ByVal lpfn As LowLevelKeyboardProcDelegate, _
            ByVal hmod As Integer, _
            ByVal dwThreadId As Integer) As Integer
        Private Declare Function CallNextHookEx Lib "user32" ( _
            ByVal hHook As Integer, _
            ByVal nCode As Integer, _
            ByVal wParam As Integer, _
            ByVal lParam As KBDLLHOOKSTRUCT) As Integer
        Private Declare Function UnhookWindowsHookEx Lib "user32" ( _
            ByVal hHook As Integer) As Integer
        Private Delegate Function LowLevelKeyboardProcDelegate( _
            ByVal nCode As Integer, _
            ByVal wParam As Integer, _
            ByRef lParam As KBDLLHOOKSTRUCT) As Integer
        Private Declare Function GetAsyncKeyState Lib "user32" _
            (ByVal vKey As Integer) As Integer
        Public Event KeyDown(ByVal vkCode As Integer)
        Public Event KeyUp(ByVal vkCode As Integer)
        Private hhkLowLevelKeyboard As Integer
        Private keyboardDelegate As LowLevelKeyboardProcDelegate
        Public Sub New()
            keyboardDelegate = New LowLevelKeyboardProcDelegate(AddressOf Me.LowLevelKeyboardProc)
            hhkLowLevelKeyboard = SetWindowsHookEx(WH_KEYBOARD_LL, keyboardDelegate, _
                Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly.GetModules()(0)).ToInt32, 0)
        End Sub
        Private Function LowLevelKeyboardProc( _
            ByVal nCode As Integer, _
            ByVal wParam As Integer, _
            ByRef lParam As KBDLLHOOKSTRUCT) As Integer
            If (nCode = HC_ACTION) Then
                Select Case wParam
                    Case WM_KEYDOWN, WM_SYSKEYDOWN
                        RaiseEvent KeyDown(lParam.vkCode)
                    Case WM_KEYUP, WM_SYSKEYUP
                        RaiseEvent KeyUp(lParam.vkCode)
                End Select
            End If
            Return CallNextHookEx(hhkLowLevelKeyboard, nCode, wParam, lParam)
        End Function
        Protected Overrides Sub Finalize()
        End Sub
    End Class
End Class

Open in new window


Author Comment

ID: 22794109
That's brilliant mate....
i had been reading about Keyboard Hooks but would not have got that far, i don't think.......
The only bit that troubles me now is all the "special" keys used on my custom keyboard.
They are all ALT + A, ALT + B etc..... From what i read, do these have to be handled by a  must be KeyPress event, as apposed to KeyDown/KeyUp ???
If so, is it as easy to use the colours to indicate keydown and keyup ?
or do i need to use IF...THEN.. statements and variables ?

Author Comment

ID: 22794718
I have just "knocked up" a basic GUI without all keys to test on these machines and get an error message that .NET Framework needs to be installed.
I would like to create a stand alone application as the machines the app is for are "stripped down" XP machines and will not have all updates etc on them.
Is this possible in VB Express ?

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

LVL 86

Expert Comment

by:Mike Tomlinson
ID: 22796851
Is it possible?

Yes...and No.

Using only the standard VB.Net tools, you can NOT build an executable that runs WITHOUT the .Net Framework installed on the target machine.

But...if you want to shell out some $$$ then you can purchase various third-party applications that will make your VB.Net app a "stand-alone" application by encapsulating all of the necessary components from the framework into your EXE.

ThinApp (formerly ThinStall) is one such tool:

Author Comment

ID: 22865266
I am still struggling to use all the "Combination" keys, i.e. ALT +A, ALT + B etc....
My custom keyboard uses 28 of these and so I need to work something out for it, i have tried online help and IF...THEN statements but can't get it sorted...
any ideas ??
Thank You
LVL 86

Accepted Solution

Mike Tomlinson earned 500 total points
ID: 22869073
Unfortunately I don't have a custom keyboard so I can't test this stuff out...  =\

Can you check the Alt key when you get a WM_KEYDOWN msg like this?

        If My.Computer.Keyboard.AltKeyDown Then

        End If

For instance, if you were looking for Alt-A, then look for the "A" part in the WM_KEYDOWN message, then use the above test to see if the Alt key is down.

Again, not sure how the custom keyboard works and I can't test it out here.  =(

Author Comment

ID: 22874622
Hi again !!! cool !!
I have added the IF... THEN... ELSE statement and it works !!
            Case Keys.A
                If My.Computer.Keyboard.AltKeyDown Then
                    LabelALTA.BackColor = Color.Red
                Else : LabelA.BackColor = Color.Red
                End If
the only thing i get now is an error "beep" when these keys are pressed as i think the system (Windows) recognises the system key.
Do you know how i can make my App "capture" all keyboard events so that they are not also passed on to the OS ? or disable "System Keys" while my app is running ??
Many Thanks again for any help !!
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 22877120
You can "suppress" a keystroke in LowLevelKeyboardProc()...

Instead of:

    Return CallNextHookEx(hhkLowLevelKeyboard, nCode, wParam, lParam)

You would do:

    Return True

Since we are suppressing the keystrokes, you would have to raise a new event to indicate Ctrl-A, because we can't check for it out at the Form level if we suppressed it!

    Public Event CtrlA()

So the My.Computer.Keyboard.AltKeyDown check needs to be done inside LowLevelKeyboardProc().

Author Closing Comment

ID: 31509116
Thanks VERY much for your help...
I will have a go at the last bit soon, need to find some time to get my head around it first ! Cheers !! :-D

Author Comment

ID: 22902888
OK, the "Return True" DOES remove the error "beep" i was getting when using all the ALT+" " (custom) keys, but as you said, it does not "see" the ALT key down now...
I'm think i'm OK with performing the check with an IF...THEN...ELSE.... statement,
            If My.Computer.Keyboard.AltKeyDown And Keys.A Then
                RaiseEvent ALTA()
but can i use the SELECT.... CASE.... method with this or do i need to check individually for ALT+A, ALT+B, ALT+C etc. (my keyboard uses all letters and 2 numbers)
In addition, when i RaiseEvent for these, i obviously need to "Handle" these new events... is that simply by a Private Sub ??
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 22905999
You can check for the keys using a Select Case or a series of If Then statements.

As far as events go, you can either:

(1) Create an Enum with all your Key "codes" and then raise ONE event that passes the keypress "code".
(2) Create separate Events for each Key.

The sub that handles the events can be either public or private.  The parameter "signature" has to match though.  You can have the IDE do that for you though by selecting the variable in the left dropdown at the top of the editor (llkb in the original solution I posted).  Then in the right dropdown you will see the available events for that object.

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
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…

571 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