求一个VB.net可用的线程键盘钩子,用API的,不要利用窗体响应事件获取的

求一个VB.net可用的线程键盘钩子,用API的,不要全局钩子,不要利用窗体响应事件


Imports System.Reflection, System.Threading, System.ComponentModel, System.Runtime.InteropServices

/**/''' 本类可以在.NET 环境下使用系统键盘与鼠标钩子
Public Class SystemHookClass SystemHook

定义结构#Region " 定义结构"

Private Structure MouseHookStructStructure MouseHookStruct
Dim PT As POINT
Dim Hwnd As Integer
Dim WHitTestCode As Integer
Dim DwExtraInfo As Integer
End Structure

Private Structure MouseLLHookStructStructure MouseLLHookStruct
Dim PT As POINT
Dim MouseData As Integer
Dim Flags As Integer
Dim Time As Integer
Dim DwExtraInfo As Integer
End Structure

Private Structure KeyboardHookStructStructure KeyboardHookStruct
Dim vkCode As Integer
Dim ScanCode As Integer
Dim Flags As Integer
Dim Time As Integer
Dim DwExtraInfo As Integer
End Structure

#End Region

API 声明导入#Region "API 声明导入"

Private Declare Function SetWindowsHookEx()Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Integer, ByVal lpfn As HookProc, ByVal hMod As IntPtr, ByVal dwThreadId As Integer) As Integer
Private Declare Function UnhookWindowsHookEx()Function UnhookWindowsHookEx Lib "user32" (ByVal idHook As Integer) As Integer
Private Declare Function CallNextHookEx()Function CallNextHookEx Lib "user32" (ByVal idHook As Integer, ByVal nCode As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As Integer
Private Declare Function ToAscii()Function ToAscii Lib "user32" (ByVal uVirtKey As Integer, ByVal uScancode As Integer, ByVal lpdKeyState As Byte(), ByVal lpwTransKey As Byte(), ByVal fuState As Integer) As Integer
Private Declare Function GetKeyboardState()Function GetKeyboardState Lib "user32" (ByVal pbKeyState As Byte()) As Integer
Private Declare Function GetKeyState()Function GetKeyState Lib "user32" (ByVal vKey As Integer) As Short

Private Delegate Function HookProc()Function HookProc(ByVal nCode As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As Integer

#End Region

常量声明#Region " 常量声明"

Private Const WH_MOUSE_LL = 14
Private Const WH_KEYBOARD_LL = 13
Private Const WH_MOUSE = 7
Private Const WH_KEYBOARD = 2
Private Const WM_MOUSEMOVE = &H200
Private Const WM_LBUTTONDOWN = &H201
Private Const WM_RBUTTONDOWN = &H204
Private Const WM_MBUTTONDOWN = &H207
Private Const WM_LBUTTONUP = &H202
Private Const WM_RBUTTONUP = &H205
Private Const WM_MBUTTONUP = &H208
Private Const WM_LBUTTONDBLCLK = &H203
Private Const WM_RBUTTONDBLCLK = &H206
Private Const WM_MBUTTONDBLCLK = &H209
Private Const WM_MOUSEWHEEL = &H20A
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Private Const WM_SYSKEYDOWN = &H104
Private Const WM_SYSKEYUP = &H105

Private Const VK_SHIFT As Byte = &H10
Private Const VK_CAPITAL As Byte = &H14
Private Const VK_NUMLOCK As Byte = &H90

#End Region

事件委托处理#Region " 事件委托处理"

Private events As New System.ComponentModel.EventHandlerList

/**/''' 鼠标激活事件
Public Custom Event MouseActivity As MouseEventHandler
AddHandler(ByVal value As MouseEventHandler)
events.AddHandler("MouseActivity", value)
End AddHandler
RemoveHandler(ByVal value As MouseEventHandler)
events.RemoveHandler("MouseActivity", value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
Dim eh As MouseEventHandler = TryCast(events("MouseActivity"), MouseEventHandler)
If eh IsNot Nothing Then eh.Invoke(sender, e)
End RaiseEvent
End Event
/**/''' 键盘按下事件
Public Custom Event KeyDown As KeyEventHandler
AddHandler(ByVal value As KeyEventHandler)
events.AddHandler("KeyDown", value)
End AddHandler
RemoveHandler(ByVal value As KeyEventHandler)
events.RemoveHandler("KeyDown", value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs)
Dim eh As KeyEventHandler = TryCast(events("KeyDown"), KeyEventHandler)
If eh IsNot Nothing Then eh.Invoke(sender, e)
End RaiseEvent
End Event
/**/''' 键盘输入事件
Public Custom Event KeyPress As KeyPressEventHandler
AddHandler(ByVal value As KeyPressEventHandler)
events.AddHandler("KeyPress", value)
End AddHandler
RemoveHandler(ByVal value As KeyPressEventHandler)
events.RemoveHandler("KeyPress", value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs)
Dim eh As KeyPressEventHandler = TryCast(events("KeyPress"), KeyPressEventHandler)
If eh IsNot Nothing Then eh.Invoke(sender, e)
End RaiseEvent
End Event
/**/''' 键盘松开事件
Public Custom Event KeyUp As KeyEventHandler
AddHandler(ByVal value As KeyEventHandler)
events.AddHandler("KeyUp", value)
End AddHandler
RemoveHandler(ByVal value As KeyEventHandler)
events.RemoveHandler("KeyUp", value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs)
Dim eh As KeyEventHandler = TryCast(events("KeyUp"), KeyEventHandler)
If eh IsNot Nothing Then eh.Invoke(sender, e)
End RaiseEvent
End Event

#End Region

Private hMouseHook As Integer
Private hKeyboardHook As Integer

Private Shared MouseHookProcedure As HookProc
Private Shared KeyboardHookProcedure As HookProc

创建与析构类型#Region " 创建与析构类型"

/**/''' 创建一个全局鼠标键盘钩子 ( 请使用Start 方法开始监视)
Sub New()Sub New()
' 留空即可
End Sub
/**/''' 创建一个全局鼠标键盘钩子,决定是否安装钩子
''' 是否立刻挂钩系统消息
Sub New()Sub New(ByVal InstallAll As Boolean)
If InstallAll Then StartHook(True, True)
End Sub
/**/''' 创建一个全局鼠标键盘钩子,并决定安装钩子的类型
''' 挂钩键盘消息
''' 挂钩鼠标消息
Sub New()Sub New(ByVal InstallKeyboard As Boolean, ByVal InstallMouse As Boolean)
StartHook(InstallKeyboard, InstallMouse)
End Sub
/**/''' 析构函数
Protected Overrides Sub Finalize()Sub Finalize()
UnHook() ' 卸载对象时反注册系统钩子
MyBase.Finalize()
End Sub

#End Region

/**/''' 开始安装系统钩子
''' 挂钩键盘消息
''' 挂钩鼠标消息
Public Sub StartHook()Sub StartHook(Optional ByVal InstallKeyboardHook As Boolean = True, Optional ByVal InstallMouseHook As Boolean = False)
' 注册键盘钩子
If InstallKeyboardHook AndAlso hKeyboardHook = 0 Then
KeyboardHookProcedure = New HookProc(AddressOf KeyboardHookProc)
hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly.GetModules()(0)), 0)
If hKeyboardHook = 0 Then ' 检测是否注册完成
UnHook(True, False) ' 在这里反注册
Throw New Win32Exception(Marshal.GetLastWin32Error) ' 报告错误
End If
End If
' 注册鼠标钩子
If InstallMouseHook AndAlso hMouseHook = 0 Then
MouseHookProcedure = New HookProc(AddressOf MouseHookProc)
hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly.GetModules()(0)), 0)
If hMouseHook = 0 Then
UnHook(False, True)
Throw New Win32Exception(Marshal.GetLastWin32Error)
End If
End If
End Sub
/**/''' 立刻卸载系统钩子
''' 卸载键盘钩子
''' 卸载鼠标钩子
''' 是否报告错误
Public Sub UnHook()Sub UnHook(Optional ByVal UninstallKeyboardHook As Boolean = True, Optional ByVal UninstallMouseHook As Boolean = True, Optional ByVal ThrowExceptions As Boolean = False)
' 卸载键盘钩子
If hKeyboardHook <> 0 AndAlso UninstallKeyboardHook Then
Dim retKeyboard As Integer = UnhookWindowsHookEx(hKeyboardHook)
hKeyboardHook = 0
If ThrowExceptions AndAlso retKeyboard = 0 Then ' 如果出现错误,是否报告错误
Throw New Win32Exception(Marshal.GetLastWin32Error) ' 报告错误
End If
End If
' 卸载鼠标钩子
If hMouseHook <> 0 AndAlso UninstallMouseHook Then
Dim retMouse As Integer = UnhookWindowsHookEx(hMouseHook)
hMouseHook = 0
If ThrowExceptions AndAlso retMouse = 0 Then
Throw New Win32Exception(Marshal.GetLastWin32Error)
End If
End If
End Sub

' 键盘消息的委托处理代码
Private Function KeyboardHookProc()Function KeyboardHookProc(ByVal nCode As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As Integer
Static handled As Boolean : handled = False
If nCode >= 0 AndAlso (events("KeyDown") IsNot Nothing OrElse events("KeyPress") IsNot Nothing OrElse events("KeyUp") IsNot Nothing) Then
Static MyKeyboardHookStruct As KeyboardHookStruct
MyKeyboardHookStruct = DirectCast(Marshal.PtrToStructure(lParam, GetType(KeyboardHookStruct)), KeyboardHookStruct)
' 激活KeyDown
If wParam = WM_KEYDOWN OrElse wParam = WM_SYSKEYDOWN Then ' 如果消息为按下普通键或系统键
Dim e As New KeyEventArgs(MyKeyboardHookStruct.vkCode)
RaiseEvent KeyDown(Me, e) ' 激活事件
handled = handled Or e.Handled ' 是否取消下一个钩子
End If
' 激活KeyUp
If wParam = WM_KEYUP OrElse wParam = WM_SYSKEYUP Then
Dim e As New KeyEventArgs(MyKeyboardHookStruct.vkCode)
RaiseEvent KeyUp(Me, e)
handled = handled Or e.Handled
End If
' 激活KeyPress (TODO: 此段代码还有BUG !)
If wParam = WM_KEYDOWN Then
Dim isDownShift As Boolean = (GetKeyState(VK_SHIFT) & &H80 = &H80)
Dim isDownCapslock As Boolean = (GetKeyState(VK_CAPITAL) <> 0)
Dim keyState(256) As Byte
GetKeyboardState(keyState)
Dim inBuffer(2) As Byte
If ToAscii(MyKeyboardHookStruct.vkCode, MyKeyboardHookStruct.ScanCode, keyState, inBuffer, MyKeyboardHookStruct.Flags) = 1 Then
Static key As Char : key = Chr(inBuffer(0))
' BUG 所在
'If isDownCapslock Xor isDownShift And Char.IsLetter(key) Then
'     key = Char.ToUpper(key)
'End If
Dim e As New KeyPressEventArgs(key)
RaiseEvent KeyPress(Me, e)
handled = handled Or e.Handled
End If
End If
' 取消或者激活下一个钩子
If handled Then Return 1 Else Return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam)
End If
End Function
' 鼠标消息的委托处理代码
Private Function MouseHookProc()Function MouseHookProc(ByVal nCode As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As Integer
If nCode >= 0 AndAlso events("MouseActivity") IsNot Nothing Then
Static mouseHookStruct As MouseLLHookStruct
mouseHookStruct = DirectCast(Marshal.PtrToStructure(lParam, GetType(MouseLLHookStruct)), MouseLLHookStruct)
Static moubut As MouseButtons : moubut = MouseButtons.None ' 鼠标按键
Static mouseDelta As Integer : mouseDelta = 0 ' 滚轮值
Select Case wParam
Case WM_LBUTTONDOWN
moubut = MouseButtons.Left
Case WM_RBUTTONDOWN
moubut = MouseButtons.Right
Case WM_MBUTTONDOWN
moubut = MouseButtons.Middle
Case WM_MOUSEWHEEL
Static int As Integer : int = (mouseHookStruct.MouseData >> 16) And &HFFFF
' 本段代码CLE 添加,模仿C# 的Short 从Int 弃位转换
If int > Short.MaxValue Then mouseDelta = int - 65536 Else mouseDelta = int
End Select
Static clickCount As Integer : clickCount = 0 ' 单击次数
If moubut <> MouseButtons.None Then
If wParam = WM_LBUTTONDBLCLK OrElse wParam = WM_RBUTTONDBLCLK OrElse wParam = WM_MBUTTONDBLCLK Then
clickCount = 2
Else
clickCount = 1
End If
End If
Dim e As New MouseEventArgs(moubut, clickCount, mouseHookStruct.PT.X, mouseHookStruct.PT.Y, mouseDelta)
RaiseEvent MouseActivity(Me, e)
End If
Return CallNextHookEx(hMouseHook, nCode, wParam, lParam) ' 激活下一个钩子
End Function

/**/''' 键盘钩子是否有效
Public Property KeyHookEnabled()Property KeyHookEnabled() As Boolean
Get
Return hKeyboardHook <> 0
End Get
Set(ByVal value As Boolean)
If value Then StartHook(True, False) Else UnHook(True, False)
End Set
End Property
/**/''' 鼠标钩子是否有效
Public Property MouseHookEnabled()Property MouseHookEnabled() As Boolean
Get
Return hMouseHook <> 0
End Get
Set(ByVal value As Boolean)
If value Then StartHook(False, True) Else UnHook(False, True)
End Set
End Property

End Class

直接用钩子函数抓取就可以了,我之前用c#开发的 ,调用win32接口。

可以看看这个:https://docs.microsoft.com/en-us/dotnet/desktop/winforms/input-keyboard/how-to-simulate-events?view=netdesktop-6.0

下面这个不知道是不是你的要求


Public Declare Function SetWindowsHookEx Lib "user32" _
    Alias "SetWindowsHookExA" (ByVal idHook As Integer, _
    ByVal lpfn As KeyboardHookDelegate, ByVal hmod As Integer, _
    ByVal dwThreadId As Integer) As Integer

Public Delegate Function KeyboardHookDelegate( _
  ByVal Code As Integer, _
  ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) _
               As Integer

<MarshalAs(UnmanagedType.FunctionPtr)> _
Private callback As KeyboardHookDelegate

Public Sub HookKeyboard()
  callback = New KeyboardHookDelegate(AddressOf KeyboardCallback)

  KeyboardHandle = SetWindowsHookEx( _
    WH_KEYBOARD_LL, callback, _
    Marshal.GetHINSTANCE( _
    [Assembly].GetExecutingAssembly.GetModules()(0)).ToInt32, 0)

   Call CheckHooked()
  End Sub

Imports System.Runtime.InteropServices

Imports System.Reflection

Imports System.Drawing

Imports System.Threading
Module Keyboard

  Public Declare Function UnhookWindowsHookEx Lib “user32” _

    (ByVal hHook As Integer) As Integer


  Public Declare Function SetWindowsHookEx Lib “user32” _

    Alias “SetWindowsHookExA” (ByVal idHook As Integer, _

    ByVal lpfn As KeyboardHookDelegate, ByVal hmod As Integer, _

    ByVal dwThreadId As Integer) As Integer


  Private Declare Function GetAsyncKeyState Lib “user32” _

    (ByVal vKey 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


  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 Const HC_ACTION As Integer      = 0

  Private Const LLKHF_EXTENDED As Integer = &H1

  Private Const LLKHF_INJECTED As Integer = &H10

  Private Const LLKHF_ALTDOWN As Integer  = &H20

  Private Const LLKHF_UP As Integer       = &H80




  Public Const VK_TAB     = &H9

  Public Const VK_CONTROL = &H11

  Public Const VK_ESCAPE  = &H1B

  Public Const VK_DELETE  = &H2E


  Private Const WH_KEYBOARD_LL As Integer = 13&

  Public KeyboardHandle As Integer


  ‘尽可能多地阻止组合键


  Public Function IsHooked( _

    ByRef Hookstruct As KBDLLHOOKSTRUCT) As Boolean


    Debug.WriteLine(“Hookstruct.vkCode: ” & Hookstruct.vkCode)

    Debug.WriteLine(Hookstruct.vkCode = VK_ESCAPE)

    Debug.WriteLine(Hookstruct.vkCode = VK_TAB)


    If (Hookstruct.vkCode = VK_ESCAPE) And _

      CBool(GetAsyncKeyState(VK_CONTROL) _

      And &H8000) Then


      Call HookedState(“Ctrl + Esc blocked”)

      Return True

    End If


    If (Hookstruct.vkCode = VK_TAB) And _

      CBool(Hookstruct.flags And _

      LLKHF_ALTDOWN) Then


      Call HookedState(“Alt + Tab blockd”)

      Return True

    End If


    If (Hookstruct.vkCode = VK_ESCAPE) And _

      CBool(Hookstruct.flags And _

        LLKHF_ALTDOWN) Then


      Call HookedState(“Alt + Escape blocked”)

      Return True

    End If


    Return False

  End Function


  Private Sub HookedState(ByVal Text As String)

    Debug.WriteLine(Text)

  End Sub


  Public Function KeyboardCallback(ByVal Code As Integer, _

    ByVal wParam As Integer, _

    ByRef lParam As KBDLLHOOKSTRUCT) As Integer


    If (Code = HC_ACTION) Then

      Debug.WriteLine(“Calling IsHooked”)


      If (IsHooked(lParam)) Then

        Return 1

      End If


    End If


    Return CallNextHookEx(KeyboardHandle, _

      Code, wParam, lParam)


  End Function


  Public Delegate Function KeyboardHookDelegate( _

    ByVal Code As Integer, _

    ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) _

                 As Integer


  <MarshalAs(UnmanagedType.FunctionPtr)> _

  Private callback As KeyboardHookDelegate


  Public Sub HookKeyboard()

    callback = New KeyboardHookDelegate(AddressOf KeyboardCallback)


    KeyboardHandle = SetWindowsHookEx( _

      WH_KEYBOARD_LL, callback, _

      Marshal.GetHINSTANCE( _

      [Assembly].GetExecutingAssembly.GetModules()(0)).ToInt32, 0)


    Call CheckHooked()

  End Sub


  Public Sub CheckHooked()

    If (Hooked()) Then

      Debug.WriteLine(“Keyboard hooked”)

    Else

      Debug.WriteLine(“Keyboard hook failed: ” & Err.LastDllError)

    End If

  End Sub


  Private Function Hooked()

    Hooked = KeyboardHandle <> 0

  End Function


  Public Sub UnhookKeyboard()

    If (Hooked()) Then

      Call UnhookWindowsHookEx(KeyboardHandle)

    End If

  End Sub


End Module

可以通过鼠标或者键盘事件来实现,下面贴了代码可以参考一下
//''' 鼠标激活事件
Public Custom Event MouseActivity As MouseEventHandler
AddHandler(ByVal value As MouseEventHandler)
events.AddHandler("MouseActivity", value)
End AddHandler
RemoveHandler(ByVal value As MouseEventHandler)
events.RemoveHandler("MouseActivity", value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
Dim eh As MouseEventHandler = TryCast(events("MouseActivity"), MouseEventHandler)
If eh IsNot Nothing Then eh.Invoke(sender, e)
End RaiseEvent
End Event
/
/''' 键盘按下事件
Public Custom Event KeyDown As KeyEventHandler
AddHandler(ByVal value As KeyEventHandler)
events.AddHandler("KeyDown", value)
End AddHandler
RemoveHandler(ByVal value As KeyEventHandler)
events.RemoveHandler("KeyDown", value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs)
Dim eh As KeyEventHandler = TryCast(events("KeyDown"), KeyEventHandler)
If eh IsNot Nothing Then eh.Invoke(sender, e)
End RaiseEvent
End Event
//''' 键盘输入事件
Public Custom Event KeyPress As KeyPressEventHandler
AddHandler(ByVal value As KeyPressEventHandler)
events.AddHandler("KeyPress", value)
End AddHandler
RemoveHandler(ByVal value As KeyPressEventHandler)
events.RemoveHandler("KeyPress", value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs)
Dim eh As KeyPressEventHandler = TryCast(events("KeyPress"), KeyPressEventHandler)
If eh IsNot Nothing Then eh.Invoke(sender, e)
End RaiseEvent
End Event
/
/''' 键盘松开事件
Public Custom Event KeyUp As KeyEventHandler
AddHandler(ByVal value As KeyEventHandler)
events.AddHandler("KeyUp", value)
End AddHandler
RemoveHandler(ByVal value As KeyEventHandler)
events.RemoveHandler("KeyUp", value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs)
Dim eh As KeyEventHandler = TryCast(events("KeyUp"), KeyEventHandler)
If eh IsNot Nothing Then eh.Invoke(sender, e)
End RaiseEvent
End Event

看看这个是不是满足你的需求:
https://download.csdn.net/download/fxsee3/3646832?utm_source=iteye_new

https://ask.csdn.net/questions/235246?spm=1005.2026.3001.5635&utm_medium=distribute.pc_relevant_ask_down.none-task-ask-2~default~OPENSEARCH~Rate-15.pc_feed_download_top3ask&depth_1-utm_source=distribute.pc_relevant_ask_down.none-task-ask-2~default~OPENSEARCH~Rate-15.pc_feed_download_top3ask

可以参考下这篇文章:
https://blog.csdn.net/weixin_43676892/article/details/117227116?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164826114516782092934777%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=164826114516782092934777&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-117227116.nonecase&utm_term=%E9%92%A9%E5%AD%90&spm=1018.2226.3001.4450

Managing Low-Level Keyboard Hooks with the Windows API for VB .NET https://www.codeguru.com/visual-basic/managing-low-level-keyboard-hooks-with-the-windows-api-for-vb-net/

那只能用消息循环了。