I've developed an application using vb.net that indicates the caps lock status of my system. There's a checkbox in the main form, whenever the caps lock is switched on by pressing the caps lock key, the checkbox gets checked and when turned off the checkbox gets unchecked. Below are the codes:
Public Class Form1
Dim keyStCL As Boolean = False
Private WithEvents KeyHook As New KeyboardHook
Private Const VK_CAPSLOCK As Integer = &H14
Private Const VK_SCROLLLOCK As Integer = &H91
Private Const VK_NUMLOCK As Integer = &H90
Private Const KEYEVENTF_EXTENDEDKEY As Integer = &H1
Private Const KEYEVENTF_KEYUP As Integer = &H2
Private Sub SimulateKeyPressCaps(ByVal bVKCode As Byte, ByVal bScanCode As Byte)
Call keybd_event(VK_CAPSLOCK, &H45, KEYEVENTF_EXTENDEDKEY Or 0, 0)
Call keybd_event(VK_CAPSLOCK, &H45, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)
End Sub
Private Sub checkbutton_caps_CheckedChanged(sender As Object, e As EventArgs) Handles checkbutton_caps.Click
If keyStCL = True Then
SimulateKeyPressCaps(VK_CAPSLOCK, &H45)
checkbutton_caps.Image = Image.FromFile("resources\btn_ico_caps_off.png")
checkbutton_caps.Checked = False
ElseIf keyStCL = False Then
SimulateKeyPressCaps(VK_CAPSLOCK, &H45)
checkbutton_caps.Image = Image.FromFile("resources\btn_ico_caps_on.png")
checkbutton_caps.Checked = True
End If
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Activated
Me.KeyPreview = True
If My.Computer.Keyboard.CapsLock = True Then
keyStCL = True
My.Computer.Audio.PlaySystemSound(Media.SystemSounds.Beep)
checkbutton_caps.Checked = True
checkbutton_caps.Image = Image.FromFile("resources\btn_ico_caps_on.png")
ElseIf My.Computer.Keyboard.CapsLock = False Then
keyStCL = False
checkbutton_caps.Checked = False
checkbutton_caps.Image = Image.FromFile("resources\btn_ico_caps_off.png")
End If
Private Sub Form1_KeyPressCaps(ByVal sender As Object, e As KeyEventArgs) Handles Me.KeyDown
If e.KeyCode = Keys.CapsLock Then
If keyStCL = True Then
checkbutton_caps.Checked = False
checkbutton_caps.Image = Image.FromFile("resources\btn_ico_caps_off.png")
keyStCL = False
ElseIf keyStCL = False Then
checkbutton_caps.Checked = True
checkbutton_caps.Image = Image.FromFile("resources\btn_ico_caps_on.png")
keyStCL = True
End If
End If
End Sub
Now the problem is all the events mentioned in the above codes get raised only when the main form has focus and not when it has lost focus. I am planning to run this program in background so that whenever I hit the caps lock key, I get notified, but this is not possible since the keyboard events do not get raised when the program has lost focus. How can I make my program raise events even when it does not have focus?
And below is the Keyboard Hook class I've used. (I haven't changed anything in the Keyboard Hook class i used it as it is on https://sim0n.wordpress.com/2009/03/28/vbnet-keyboard-hook-class/) After using this class I am now getting an error: Could not set Keyboard Hook. This error message was created by the Keyboard Hook class itself.
Imports System.Runtime.InteropServices
Public Class KeyboardHook
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
Private Overloads Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal HookProc As KBDLLHookProc, ByVal hInstance As IntPtr, ByVal wParam As Integer) As Integer
End Function
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
Private Overloads Shared Function CallNextHookEx(ByVal idHook As Integer, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
End Function
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
Private Overloads Shared Function UnhookWindowsHookEx(ByVal idHook As Integer) As Boolean
End Function
<StructLayout(LayoutKind.Sequential)> _
Private Structure KBDLLHOOKSTRUCT
Public vkCode As UInt32
Public scanCode As UInt32
Public flags As KBDLLHOOKSTRUCTFlags
Public time As UInt32
Public dwExtraInfo As UIntPtr
End Structure
<Flags()> _
Private Enum KBDLLHOOKSTRUCTFlags As UInt32
LLKHF_EXTENDED = &H1
LLKHF_INJECTED = &H10
LLKHF_ALTDOWN = &H20
LLKHF_UP = &H80
End Enum
Public Shared Event KeyDown(ByVal Key As Keys)
Public Shared Event KeyUp(ByVal Key As Keys)
Private Const WH_KEYBOARD_LL As Integer = 13
Private Const HC_ACTION As Integer = 0
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Private Const WM_SYSKEYDOWN = &H104
Private Const WM_SYSKEYUP = &H105
Private Delegate Function KBDLLHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
Private KBDLLHookProcDelegate As KBDLLHookProc = New KBDLLHookProc(AddressOf KeyboardProc)
Private HHookID As IntPtr = IntPtr.Zero
Private Function KeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
If (nCode = HC_ACTION) Then
Dim struct As KBDLLHOOKSTRUCT
Select Case wParam
Case WM_KEYDOWN, WM_SYSKEYDOWN
RaiseEvent KeyDown(CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys))
Case WM_KEYUP, WM_SYSKEYUP
RaiseEvent KeyUp(CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys))
End Select
End If
Return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam)
End Function
Public Sub New()
HHookID = SetWindowsHookEx(WH_KEYBOARD_LL, KBDLLHookProcDelegate, System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly.GetModules()(0)).ToInt32, 0)
If HHookID = IntPtr.Zero Then
Throw New Exception("Could not set keyboard hook")
End If
End Sub
Protected Overrides Sub Finalize()
If Not HHookID = IntPtr.Zero Then
UnhookWindowsHookEx(HHookID)
End If
MyBase.Finalize()
End Sub
End Class