Solved

Keyboard Events in VB ?

Posted on 2008-10-23
11
1,216 Views
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
0
Comment
Question by:lewisma2
  • 6
  • 5
11 Comments
 
LVL 85

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()

            UnhookWindowsHookEx(hhkLowLevelKeyboard)

            MyBase.Finalize()

        End Sub
 

    End Class
 

End Class

Open in new window

0
 

Author Comment

by:lewisma2
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 ?
0
 

Author Comment

by:lewisma2
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 ?
0
 
LVL 85

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:
http://www.vmware.com/products/thinapp/
0
 

Author Comment

by:lewisma2
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
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 125 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.  =(
0
 

Author Comment

by:lewisma2
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 !!
0
 
LVL 85

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().
0
 

Author Closing Comment

by:lewisma2
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
0
 

Author Comment

by:lewisma2
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 ??
cheers
0
 
LVL 85

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.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

If you have ever used Microsoft Word then you know that it has a good spell checker and it may have occurred to you that the ability to check spelling might be a nice piece of functionality to add to certain applications of yours. Well the code that…
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.
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…

862 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

Need Help in Real-Time?

Connect with top rated Experts

28 Experts available now in Live!

Get 1:1 Help Now