当我的表单没有焦点时如何引发事件(vb .net)

时间:2016-07-07 14:39:38

标签: vb.net winforms keyboard-events

我使用vb.net开发了一个应用程序,它指示我系统的大写锁定状态。主窗体中有一个复选框,每当按下大写锁定键打开大写锁定时,复选框都会被选中,当关闭时,复选框将被取消选中。以下是代码:

Public Class Form1

Dim keyStCL As Boolean = False

Private WithEvents KeyHook As New KeyboardHook

Private Const VK_CAPSLOCK As Integer = &H14
Private Const VK_SCROLLLOCK As Integer = &H91
Private Const VK_NUMLOCK As Integer = &H90

Private Const KEYEVENTF_EXTENDEDKEY As Integer = &H1
Private Const KEYEVENTF_KEYUP As Integer = &H2

 Private Sub SimulateKeyPressCaps(ByVal bVKCode As Byte, ByVal bScanCode As Byte)
    Call keybd_event(VK_CAPSLOCK, &H45, KEYEVENTF_EXTENDEDKEY Or 0, 0)
    Call keybd_event(VK_CAPSLOCK, &H45, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)
End Sub

Private Sub checkbutton_caps_CheckedChanged(sender As Object, e As EventArgs) Handles checkbutton_caps.Click

    If keyStCL = True Then
        SimulateKeyPressCaps(VK_CAPSLOCK, &H45)
        checkbutton_caps.Image = Image.FromFile("resources\btn_ico_caps_off.png")
        checkbutton_caps.Checked = False

    ElseIf keyStCL = False Then
        SimulateKeyPressCaps(VK_CAPSLOCK, &H45)
        checkbutton_caps.Image = Image.FromFile("resources\btn_ico_caps_on.png")
        checkbutton_caps.Checked = True

    End If
End Sub

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Activated

    Me.KeyPreview = True

    If My.Computer.Keyboard.CapsLock = True Then
        keyStCL = True
        My.Computer.Audio.PlaySystemSound(Media.SystemSounds.Beep)
        checkbutton_caps.Checked = True
        checkbutton_caps.Image = Image.FromFile("resources\btn_ico_caps_on.png")
    ElseIf My.Computer.Keyboard.CapsLock = False Then
        keyStCL = False
        checkbutton_caps.Checked = False
        checkbutton_caps.Image = Image.FromFile("resources\btn_ico_caps_off.png")
    End If

Private Sub Form1_KeyPressCaps(ByVal sender As Object, e As KeyEventArgs) Handles Me.KeyDown

    If e.KeyCode = Keys.CapsLock Then
        If keyStCL = True Then
            checkbutton_caps.Checked = False
            checkbutton_caps.Image = Image.FromFile("resources\btn_ico_caps_off.png")
            keyStCL = False

        ElseIf keyStCL = False Then
            checkbutton_caps.Checked = True
            checkbutton_caps.Image = Image.FromFile("resources\btn_ico_caps_on.png")
            keyStCL = True

        End If
    End If
End Sub

现在问题是上面代码中提到的所有事件只有在主窗体具有焦点时才会被引发,而不是在它失去焦点时。我打算在后台运行这个程序,这样每当我点击大写锁定键时,我都会得到通知,但这是不可能的,因为当程序失去焦点时键盘事件不会被提升。即使没有焦点,我怎样才能使我的程序引发事件?

以下是我使用过的Keyboard Hook类。 (我没有更改Keyboard Hook类中的任何内容,因为它在https://sim0n.wordpress.com/2009/03/28/vbnet-keyboard-hook-class/上使用它 使用此类后,我现在收到错误:无法设置键盘挂钩。此错误消息是由Keyboard Hook类本身创建的。

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

1 个答案:

答案 0 :(得分:-2)

因此,您遇到的问题是您希望在事件发生时收到通知,但只有在具有复选框的表单具有焦点时才会通知您。现在我不是专家程序员,但我刚刚完成了一本关于visual basic的书。我认为你的问题在于事件处理程序行。现在你有:

Private Sub Form1_KeyPressCaps(ByVal sender As Object, e As KeyEventArgs) Handles Me.KeyDown

该行启动子例程,以便在Me表格上按下任何键时,该表格是当前选定的表格。我现在无法使用VB进行实验,因为我的许可证用完了,我很快就会收到另一个。但您可以尝试在Me的位置指定所有表单。或者指定何时最小化表单。我真的希望我现在有智能感知,但你可以尝试的东西可能是

Private Sub Form1_KeyPressCaps(ByVal sender As Object, e As KeyEventArgs) Handles AllForms.KeyDown

Private Sub Form1_KeyPressCaps(ByVal sender As Object, e As KeyEventArgs) Handles Me.Minimized.KeyDown

我意识到这些都可能是错误的语法,但逻辑仍然是正确的,或者我相信。我不知道全球关键钩是什么,但如果我的回答不适合您,可能值得研究一下。这是我的第一个答案,所以我希望它有所帮助