|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic Hook Routines SetWindowsHookEx: Detect Caps/Numlock/Scrollock via System-wide Keyboard Hook |
|
Posted: | Friday March 28, 2003 |
Updated: | Monday December 26, 2011 |
Applies to: | VB5, VB6 |
Developed with: | VB6, Windows XP |
OS restrictions: | Windows NT 4.0 SP3 and later |
Author: | VBnet, Randy Birch |
Related: |
SetWindowsHookEx: 'Self-Closing' Message Box using a VB Timer SetWindowsHookEx: 'Self-Closing' Message Box using SetTimer SetWindowsHookEx: Detect Caps/Numlock/Scrollock via System-wide Keyboard Hook SetWindowsHookEx: Customize the API Message Box SetWindowsHookEx: Trapping Special Key Events using Low Level Hooks MessageBoxEx: Displaying an API-created Message Box |
Prerequisites |
Windows NT 4.0 SP3 and later. LowLevelKeyboardProc is unsupported under
9x and ME.
VB5 or VB6 for use of the AddressOf operator. |
|
This
routine is pretty straightforward. Three labels represent the caps, num and scroll keys. On application start-up, GetKeyboardState is called in order to determine the initial state of those keys. If the bdState.kbByte(VK_XXX) = 1, the bit is set and, for the caps, num and scoll keys, indicates those keys are on. Once the initial state has been processed, a low-level keyboard hook is installed that monitors all keystrokes made. When the HC_ACTION msg is received, the value from lParam is copied into a KBDLLHOOKSTRUCT type. From that, the kbdllhs.flags member is checked and if the value is LLKHF_UP, the structure's kbdllhs.vkcode is examined. kbdllhs.vkcode indicates the virtual key code for the key pressed, in this case we're interested in VK_NUMLOCK, VK_CAPITAL and VB_SCROLL. Once the virtual key has been determined, GetKeyState is called for that key, and the value returned is compared to &HFF81 (-127). If the value is -127, the key was pressed on; if -128, the press turned it off. The corresponding label is made visible by converting the value to a boolean through the comparison of the result of GetKeyState and &HFF81. Simple, right? <g> As an exe this code will accurately display the active state of the caps, num and scroll keys, regardless of the application that currently has focus. |
BAS Module Code |
Hooks require a bas module for the hook code, so add the following to a bas module: |
|
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public m_hDllKbdHook As Long 'public variable holding 'the handle to the hook procedure Public Const WH_KEYBOARD_LL As Long = 13 'enables monitoring of keyboard 'input events about to be posted 'in a thread input queue Private Const HC_ACTION As Long = 0 'wParam and lParam parameters 'contain information about a 'keyboard message Public Const VK_CAPITAL As Long = &H14 Public Const VK_NUMLOCK As Long = &H90 Public Const VK_SCROLL As Long = &H91 Private Const LLKHF_UP As Long = &H80& 'test the transition-state flag Public Type KeyboardBytes kbByte(0 To 255) As Byte End Type Private Type KBDLLHOOKSTRUCT vkCode As Long 'a virtual-key code in the range 1 to 254 scanCode As Long 'hardware scan code for the key flags As Long 'specifies the extended-key flag, 'event-injected flag, context code, 'and transition-state flag time As Long 'time stamp for this message dwExtraInfo As Long 'extra info associated with the message End Type Public 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 Public Declare Function UnhookWindowsHookEx Lib "user32" _ (ByVal hHook As Long) As Long Public Declare Function CallNextHookEx Lib "user32" _ (ByVal hHook As Long, _ ByVal nCode As Long, _ ByVal wParam As Long, _ ByVal lParam As Long) As Long Public Declare Sub CopyMemory Lib "kernel32" _ Alias "RtlMoveMemory" _ (pDest As Any, _ pSource As Any, _ ByVal cb As Long) Public Declare Function GetKeyboardState Lib "user32" _ (kbArray As KeyboardBytes) As Long Public Declare Function GetKeyState Lib "user32" _ (ByVal nVirtKey As Long) As Integer Public Function LowLevelKeyboardProc(ByVal nCode As Long, _ ByVal wParam As Long, _ ByVal lParam As Long) As Long Dim kbdllhs As KBDLLHOOKSTRUCT 'Application-defined callback function 'used with the SetWindowsHookEx function. 'The system calls this function every 'time a new keyboard input event is about 'to be posted into a thread input queue. 'The keyboard input can come from the local 'keyboard driver or from calls to the 'keybd_event function. If the input comes 'from a call to keybd_event, the input 'was "injected". ' 'If nCode is less than zero, the hook 'procedure must return the value returned 'by CallNextHookEx. ' 'If nCode is greater than or equal to zero, 'and the hook procedure did not process the 'message, it is highly recommended that you 'call CallNextHookEx and return the value it 'returns; otherwise, other applications that 'have installed WH_KEYBOARD_LL hooks will not 'receive hook notifications and may behave 'incorrectly as a result. ' 'If the hook procedure processed the message, 'it may return a nonzero value to prevent the 'system from passing the message to the rest 'of the hook chain or the target window procedure. 'nCode specifies a code the hook 'procedure uses to determine how 'to process the message. HC_ACTION 'is the only valid code. 'On receipt of the HC_ACTION code, 'wParam and lParam contain information 'about a keyboard message, and lParam 'holds the pointer to a KBDLLHOOKSTRUCT 'structure. If nCode = HC_ACTION Then Call CopyMemory(kbdllhs, ByVal lParam, Len(kbdllhs)) If (kbdllhs.flags And LLKHF_UP) Then Select Case kbdllhs.vkCode Case VK_NUMLOCK Form1.Label1.Visible = (GetKeyState(VK_NUMLOCK) = &HFF81) Case VK_CAPITAL Form1.Label2.Visible = (GetKeyState(VK_CAPITAL) = &HFF81) Case VK_SCROLL Form1.Label3.Visible = (GetKeyState(VK_SCROLL) = &HFF81) Case Else End Select End If End If 'nCode = HC_ACTION LowLevelKeyboardProc = CallNextHookEx(m_hDllKbdHook, _ nCode, _ wParam, _ lParam) End Function |
Form Code |
Add three labels (Label1, Label2, Label3) to a form, along with the following code:. |
|
Option Explicit Private Sub Form_Load() Dim kbdState As KeyboardBytes Call GetKeyboardState(kbdState) With Label1 .Caption = "Numlock is ON" .Alignment = vbRightJustify End With With Label2 .Caption = "Caps lock is ON" .Alignment = vbRightJustify End With With Label3 .Caption = "Scroll lock is ON" .Alignment = vbRightJustify End With Label1.Visible = kbdState.kbByte(VK_NUMLOCK) = 1 Label2.Visible = kbdState.kbByte(VK_CAPITAL) = 1 Label3.Visible = kbdState.kbByte(VK_SCROLL) = 1 'set and obtain the handle to the keyboard hook m_hDllKbdHook = SetWindowsHookEx(WH_KEYBOARD_LL, _ AddressOf LowLevelKeyboardProc, _ App.hInstance, _ 0&) If m_hDllKbdHook = 0 Then MsgBox "Failed to install low-level keyboard hook." End If End Sub Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer) If m_hDllKbdHook <> 0 Then Call UnhookWindowsHookEx(m_hDllKbdHook) End If End Sub |
Comments |
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |