如何在单独的线程上设置全局键盘钩子? [英] How to set global keyboard hook on separate thread?

查看:22
本文介绍了如何在单独的线程上设置全局键盘钩子?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

经过多次搜索,我最终使用此类进行全局键盘挂钩.链接:全球钩帖

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆