【问题标题】:How to set global keyboard hook on separate thread?如何在单独的线程上设置全局键盘挂钩?
【发布时间】:2012-04-29 19:11:47
【问题描述】:

经过多次搜索,我最终使用这个类进行全局键盘挂钩。链接: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 每隔一段时间上传小文件),在此期间钩子喜欢键盘。这我当然不想要

我现在无法跳转到 Async FtpWebRequest,因为它需要进行很多更改,所以我认为解决方案是让钩子在另一个线程中运行。

我该怎么做?

编辑:一个建议是将我的耗时操作(上传)移动到另一个线程。这样做后我面临其他问题。因为耗时的任务(上传)在一个计时器中,所以我将不得不重写大部分以便将文件->保存与文件->上传同步,而且我不介意应用程序锁定 3-4 秒。我介意的是松开 kayboard 3-4 秒...

【问题讨论】:

  • 这听起来有点像键盘记录器。
  • @SLaks:不!我的爱好是飞行模拟,我正在开发一个实用程序来捕获和上传 MS FSX/FS9 并将其发送到我们的社区 ftp 服务器。请参见此处:[我的站点...] (flightsimdreams.com/j/…)
  • 我想为 PrintScreen 键挂钩...
  • 这是一个在不同线程上运行的挂钩库。 gist.github.com/Ciantic/471698 你可以尝试修改它来做你想要的文件。很确定问题是您正在使用系统挂钩,因此如果您拦截消息并且在处理时不发送它,您将锁定键盘。您不需要为钩子使用线程,只需在不同的线程上进行处理即可。

标签: .net vb.net multithreading keyboard-hook


【解决方案1】:

不要让钩子在不同的线程上运行(我不认为你可以,它基于消息循环);相反,只需在另一个线程中运行您的任务。这可能是最简单的方法:

Call New Thread(Sub()
                    ' Do stuff here
                End Sub) With {.IsBackground = True}.Start()

【讨论】:

  • 我的计时器每隔 10 秒运行一次。在勾选时它将屏幕保存到图像文件并触发上传。如果上传时间超过 10 秒,我最终会锁定文件吗?所以我必须通过创建文件队列或其他方式来实现这种同步?
  • @e4rthdog:文件队列是理想的。
【解决方案2】:

您需要在后台线程上运行耗时的任务。
使用ThreadPoolTask

【讨论】:

  • 我希望你能详细说明,但这样做我面临其他问题。因为耗时的任务(上传)在一个计时器中,所以我将不得不重写大部分以便将文件->保存与文件->上传同步,而且我不介意应用程序锁定 3-4 秒。我介意的是松开 kayboard 3-4 秒...
  • 不管怎样做。没有人说编程会很容易。什么意思?
  • 多年过去了,我意识到:)..请参阅我上面的评论以了解我的意思(关于计时器和文件队列集合)。我不在乎轻松,我想成为正确的方式主要......
  • @e4rthdog 这和钩子有什么关系?
  • 这个想法是将计时器和上传功能保持在 SEQUENCE 中。我需要它,因为我不希望图像“滞后”(我将它们呈现为像直播一样)。所以方法是在同一个线程上保持计时器和耗时,但是在同一个线程中的钩子在上传过程中会锁定键盘......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多