|
|
![]() |
|
||
|
|
|||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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. |
![]() |