Hi, I have been trying to build an application for which I need to set low-level keyboard hooks. I thing I am trying to accomplish is that when I press the key "a" I want windows to think I have pressed the key "b". But the problem I am facing is that when I press key "a" it produces "ab". I am providing my code below. Any help will be highly appreciated. Also I would like to know how to detect double and triple key presses (e.g. shift + a and ctrl + alt + b).
Option Strict On
Imports System.Runtime.InteropServices
Public Class Form1
Private Const KEYEVENTF_EXTENDEDKEY As Long = &H1
Private Const KEYEVENTF_KEYUP As Long = &H2
Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, _
ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Private Const WH_KEYBOARD_LL As Integer = 13
Private Const WM_KEYUP As Integer = &H101
Private Shared _proc As LowLevelKeyboardProc = AddressOf HookCallback
Private Shared _hookID As IntPtr = IntPtr.Zero
Public Declare Auto Function SetWindowsHookEx Lib "user32.dll" ( _
ByVal idHook As Integer, ByVal lpfn As LowLevelKeyboardProc, _
ByVal hMod As IntPtr, ByVal dwThreadId As UInteger) As IntPtr
Public Declare Auto Function UnhookWindowsHookEx _
Lib "user32.dll" (ByVal hhk As IntPtr) As IntPtr
Public Declare Auto Function CallNextHookEx _
Lib "user32.dll" (ByVal hhk As IntPtr, ByVal nCode As Integer, _
ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
Public Declare Auto Function GetModuleHandle Lib "kernel32.dll" ( _
ByVal lpModuleName As String) As IntPtr
Private Shared Function SetHook( _
ByVal proc As LowLevelKeyboardProc) As IntPtr
Dim curProcess As Process = Process.GetCurrentProcess()
Dim curModule As ProcessModule = curProcess.MainModule
Return SetWindowsHookEx(WH_KEYBOARD_LL, proc, _
GetModuleHandle(curModule.ModuleName), 0)
End Function
Public Delegate Function LowLevelKeyboardProc( _
ByVal nCode As Integer, ByVal wParam As IntPtr, _
ByVal lParam As IntPtr) As IntPtr
Public Shared Function HookCallback( _
ByVal nCode As Integer, _
ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
If nCode >= 0 And wParam = CType(WM_KEYUP, IntPtr) Then
Dim vkCode As Keys = CType(Marshal.ReadInt32(lParam), Keys)
If vkCode = Keys.A Or vkCode = Keys.A Then
keybd_event(CByte(Keys.B), 0, KEYEVENTF_EXTENDEDKEY, 0)
End If
End If
Return CallNextHookEx(_hookID, nCode, wParam, lParam)
End Function
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
_hookID = SetHook(_proc)
End Sub
Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
UnhookWindowsHookEx(_hookID)
End Sub
End Class
Option Strict On
Imports System.Runtime.InteropServices
Public Class Form1
Private Const KEYEVENTF_EXTENDEDKEY As Long = &H1
Private Const KEYEVENTF_KEYUP As Long = &H2
Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, _
ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Private Const WH_KEYBOARD_LL As Integer = 13
Private Const WM_KEYUP As Integer = &H101
Private Shared _proc As LowLevelKeyboardProc = AddressOf HookCallback
Private Shared _hookID As IntPtr = IntPtr.Zero
Public Declare Auto Function SetWindowsHookEx Lib "user32.dll" ( _
ByVal idHook As Integer, ByVal lpfn As LowLevelKeyboardProc, _
ByVal hMod As IntPtr, ByVal dwThreadId As UInteger) As IntPtr
Public Declare Auto Function UnhookWindowsHookEx _
Lib "user32.dll" (ByVal hhk As IntPtr) As IntPtr
Public Declare Auto Function CallNextHookEx _
Lib "user32.dll" (ByVal hhk As IntPtr, ByVal nCode As Integer, _
ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
Public Declare Auto Function GetModuleHandle Lib "kernel32.dll" ( _
ByVal lpModuleName As String) As IntPtr
Private Shared Function SetHook( _
ByVal proc As LowLevelKeyboardProc) As IntPtr
Dim curProcess As Process = Process.GetCurrentProcess()
Dim curModule As ProcessModule = curProcess.MainModule
Return SetWindowsHookEx(WH_KEYBOARD_LL, proc, _
GetModuleHandle(curModule.ModuleName), 0)
End Function
Public Delegate Function LowLevelKeyboardProc( _
ByVal nCode As Integer, ByVal wParam As IntPtr, _
ByVal lParam As IntPtr) As IntPtr
Public Shared Function HookCallback( _
ByVal nCode As Integer, _
ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
If nCode >= 0 And wParam = CType(WM_KEYUP, IntPtr) Then
Dim vkCode As Keys = CType(Marshal.ReadInt32(lParam), Keys)
If vkCode = Keys.A Or vkCode = Keys.A Then
keybd_event(CByte(Keys.B), 0, KEYEVENTF_EXTENDEDKEY, 0)
End If
End If
Return CallNextHookEx(_hookID, nCode, wParam, lParam)
End Function
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
_hookID = SetHook(_proc)
End Sub
Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
UnhookWindowsHookEx(_hookID)
End Sub
End Class