如何在单独的线程上设置全局键盘钩子? [英] How to set global keyboard hook on separate thread?
问题描述
经过多次搜索,我最终使用此类进行全局键盘挂钩.链接:全球钩帖
After many searches i end up using this class for global keyboard hooking. Link: Global Hook post
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
效果很好.
我的应用程序正在执行需要几秒钟才能完成的操作(ftp 每隔一段时间上传小文件),在此期间钩子会敲击键盘.这个我当然不想要
My app is performing operations that take some seconds to complete (ftp upload small files on interval), and during this time the hook lovks the keyboard. This i dont want of course
我现在无法跳转到 Async FtpWebRequest,因为它需要很多更改,所以我认为解决方案是让钩子存在于另一个线程中.
I cant jump to Async FtpWebRequest right now because it needs many changes, so i thought that the solution would be to make the hoook live in another thread.
我该怎么做?
一个建议是将我的耗时操作(上传)转移到另一个线程.在这样做时,我面临其他问题.因为耗时的任务(上传)是在一个计时器中,我必须重写很大一部分以便同步文件-> 保存与文件-> 上传,我不介意应用程序锁定 3-4 秒.我所介意的是松开 kayboard 3-4 秒...
A proposal is to move my time - consuming operations (upload) to another thread.Upon doing this i am facing other problems. Because the time consuming task (upload) is in a timer i would have to rewrite a big portion in order to synchronize the file->save with the file->upload and i dont mind the app locking for 3-4 secs. what i do mind is to loose the kayboard for 3-4 secs...
推荐答案
不要让钩子在不同的线程上运行(我认为你不能,它基于消息循环);相反,只需在另一个线程中运行您的任务.这可能是最简单的方法:
Don't make the hook run on a different thread (I don't think you can, it's based on the message loop); instead, just run your task in another thread. Here's probably the easiest way to do that:
Call New Thread(Sub()
' Do stuff here
End Sub) With {.IsBackground = True}.Start()
这篇关于如何在单独的线程上设置全局键盘钩子?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!