当app执行其他任务时,Keyboard Hook会冻结键盘

时间:2012-04-29 13:58:16

标签: .net keyboard

我正在使用以下类找到here在我的应用程序中全局挂钩键盘组合。

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

即使应用程序有焦点但它有问题,它仍然很好用。我的申请正在使用

 My.Computer.Network.UploadFile

在上传过程中,kayboard笔划停止响应。鼠标还可以。

如何在应用程序内的其他操作期间保持键盘处于活动状态?

1 个答案:

答案 0 :(得分:0)

是的,那是在惹麻烦。 Windows只能在程序泵送消息循环时调用钩子回调方法。 Windows没有其他机制可以在主线程上进行调用而不会导致严重的重入问题。

当主线程执行其他操作(例如上传文件)时,它会停止运行。这是GUI应用程序的一般要求,占用主UI线程与其他任务使得用户界面紧张。它停止响应输入并停止绘画。几秒钟后,Windows窗口管理器将介入并用“ghost窗口”替换主窗口,标题栏中显示“Not Responding”。你让你的鼻子更难擦,因为这现在也阻止任何键盘输入被处理,Window无法调用钩子回调。

您需要在另一个线程上执行长时间运行的任务,以便UI线程可以保持响应。或者在您谈论的特定情况下,请改用UploadFileAsync()。