【问题标题】:Allowing Global Hotkeys允许全局热键
【发布时间】:2018-05-01 18:52:24
【问题描述】:

首先,我不是一个真正的程序员,但我对我目前所做的工作感到满意。

我在下面编写了与机器人技术有关的代码。当您单击表单时,下面的代码允许我使用键盘快捷键。但是,无论应用程序是否处于焦点或什至最小化,我都需要热键来工作。

我已经在网上看了,但不是很清楚。

Public Class MainForm

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

        If (e.KeyCode And Not Keys.Modifiers) = Keys.T AndAlso e.Modifiers = Keys.Control Then
            DF1Com1.Write("O:1/0", "1")  ' (O:9/0) (R)  
        End If

        'If e.KeyCode = Keys.R Then
        'DF1Com1.Write("O:1/0", "1")  ' (O:9/0) (R)   
        'End If

    End Sub

    Private Sub MainForm_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp

        If (e.KeyCode And Not Keys.Modifiers) = Keys.T AndAlso e.Modifiers = Keys.Control Then
            DF1Com1.Write("O:1/0", "0")  ' (O:9/0) (R) 
        End If

        'If e.KeyCode = Keys.R Then
        'DF1Com1.Write("O:1/0", "0") ' (O:9/0) (R) 
        'End If

    End Sub

Public Class MainForm


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

        If (e.KeyCode And Not Keys.Modifiers) = Keys.T AndAlso e.Modifiers = Keys.Control Then
            DF1Com1.Write("O:1/0", "1")  ' (O:9/0) (R) 
        End If

        'If e.KeyCode = Keys.R Then
        'DF1Com1.Write("O:1/0", "1")  ' (O:9/0) (R)
        'End If

    End Sub

    Private Sub MainForm_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp

        If (e.KeyCode And Not Keys.Modifiers) = Keys.T AndAlso e.Modifiers = Keys.Control Then
            DF1Com1.Write("O:1/0", "0")  ' (O:9/0) (R)  
        End If

        'If e.KeyCode = Keys.R Then
        'DF1Com1.Write("O:1/0", "0") ' (O:9/0) (R) 
        'End If

    End Sub

End Class

更新:

没错。我现在添加了一个允许注册 GlobalKey 的类。

在我的主要表单中,我现在有这个键:

   Public Class MainForm
    Dim hkr As New HotKeyRegistryClass(Me.Handle)

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        hkr.Register(HotKeyRegistryClass.Modifiers.MOD_CTRL, Keys.A).ToString()
        hkr.Register(HotKeyRegistryClass.Modifiers.MOD_CTRL, Keys.S).ToString()
        hkr.Register(HotKeyRegistryClass.Modifiers.MOD_CTRL, Keys.D).ToString()
        hkr.Register(HotKeyRegistryClass.Modifiers.MOD_CTRL, Keys.F).ToString()
        hkr.Register(HotKeyRegistryClass.Modifiers.MOD_CTRL, Keys.G).ToString()
        hkr.Register(HotKeyRegistryClass.Modifiers.MOD_SHIFT Or HotKeyRegistryClass.Modifiers.MOD_CTRL, Keys.H).ToString()
    End Sub

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        If m.Msg = HotKeyRegistryClass.Messages.WM_HOTKEY Then 'NOT THE ACTUAL WINDOWS NAMESPACE
            Dim ID As String = m.WParam.ToString()
            Select Case ID
                Case 0 : If DF1Com1.Write("O:1/0", "1") Then DF1Com1.Write("O:1/0", "0")
                Case 1 : MessageBox.Show("S")
                Case 2 : MessageBox.Show("D")
                Case 3 : MessageBox.Show("F")
                Case 4 : MessageBox.Show("G")
                Case 5 : MessageBox.Show("H")
            End Select
        End If
        MyBase.WndProc(m)
    End Sub

如果您查看 案例 0。它可以工作,但是它不会将密钥备份。它一直压着它。当键按下时我需要它'DF1Com1.Write("O:1/0", "0")'

类代码

Public NotInheritable Class HotKeyRegistryClass
    Private Declare Function RegisterHotKey Lib "user32.dll" (ByVal handle As IntPtr, ByVal id As Int32, ByVal fsModifier As Int32, ByVal vk As Int32) As Int32
    Private Declare Function UnregisterHotKey Lib "user32.dll" (ByVal handle As IntPtr, ByVal id As Int32) As Int32
    Private Handle As IntPtr = IntPtr.Zero
    Private Registry As New System.Collections.Generic.List(Of Int32)
    Public Enum Messages
        [WM_HOTKEY] = &H312
    End Enum
    Public Enum Modifiers
        [MOD_ALT] = &H1
        [MOD_CTRL] = &H2
        [MOD_SHIFT] = &H4
    End Enum
    Sub New(ByVal Handle As IntPtr)
        Me.Handle = Handle
    End Sub
    Public Function Register(ByVal Modifier As Int32, ByVal Key As System.Windows.Forms.Keys) As Int32
        Dim ret As Int32
        ret = NextAvailableIndex()
        Call RegisterHotKey(Me.Handle, ret, Modifier, Key)
        Registry.Insert(ret, ret)
        Return ret
    End Function
    Public Sub Unregister(ByVal ID As Int32)
        Call UnregisterHotKey(Me.Handle, ID)
        Registry.Remove(ID)
    End Sub
    Private Function NextAvailableIndex() As Int32
        Dim ret As Int32 = 0
        Dim n As Int32 = 0
        For i As Int32 = 0 To Registry.Count - 1
            If Registry(i) = n Then
                n = n + 1
            ElseIf n < Registry(i) Then
                Return n
            End If
        Next
        If n = Registry.Count Then
            Return Registry.Count
        End If
        Return ret
    End Function
End Class

【问题讨论】:

  • 查看Windows.Input.Keyboard.GetKeyStates,而不是捕获表单上的关键事件,而是在计时器或后台线程中轮询关键状态。
  • A -1 问这个问题。有点不公平。正如我所说。我不是铁杆程序员。
  • 我现在已经更新了代码,我几乎是他们的了。仍在继续,但我坚持最后一部分。
  • 一定有更多您没有发布的代码。这里没有任何东西可以让按键保持按下状态。使用键盘挂钩可以更好地聆听热键,因为您可以使用任何组合键甚至单个键。您必须自己完成所有操作,但要跟踪按下了哪些修饰符,并确保在您自己处理时不会将键发送到挂钩链中。
  • RegisterHotKey 无法做到这一点。您的按键向上和向下事件仅在您的应用程序中起作用,RegisterHotkey 仅报告组合键已激活。如果你想要上下全局键,那么你需要一个低级键盘钩子。在这里查看我的答案...stackoverflow.com/questions/43268643/…

标签: vb.net hotkeys


【解决方案1】:

很遗憾,RegisterHotkey 只会告诉您组合键何时被激活。此外,正如您已经意识到的那样,您拥有的 KeyDownKeyUp 事件只有在您的应用获得焦点时才会起作用。

获得真正全局的KeyDownKeyUp 的唯一方法是使用低级键盘挂钩。由于我不想复制我的整个答案,我将简单地链接到它。该链接将为您提供一些设置键盘挂钩的指导。

How to disable/override Windows 10 Hotkeys with C#

另一种可能性是像这样在热键激活时执行这两个命令...

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        If m.Msg = HotKeyRegistryClass.Messages.WM_HOTKEY Then 'NOT THE ACTUAL WINDOWS NAMESPACE
            Dim ID As String = m.WParam.ToString()
            Select Case ID
                Case 0 : 
                    DF1Com1.Write("O:1/0", "1")
                    System.Threading.Thread.Sleep(2000)
                    DF1Com1.Write("O:1/0", "0")
                Case 1 : MessageBox.Show("S")
                Case 2 : MessageBox.Show("D")
                Case 3 : MessageBox.Show("F")
                Case 4 : MessageBox.Show("G")
                Case 5 : MessageBox.Show("H")
            End Select
        End If
        MyBase.WndProc(m)
    End Sub

【讨论】:

  • 只是一个简单的问题。我知道你在 C# 中有你的解决方案。是否有 VB.NET 解决方案,因为我的机器人系统使用 VB.NET。和以前一样,我不介意我不能进入最低级别,我只需要在我释放密钥后停用DF1Com1.Write("O:1/0", "0") 的方法。谢谢
  • 您应该能够从 CodeProject 获取项目并将 c# 编译成 DLL 库。然后您可以引用该库并在 VB.net 中编写您的处理程序。
  • 也许....通过RegisterHotkey 激活的每个热键都应该执行第一个代码DF1Com1.Write("O:1/0", "1"),然后休眠一秒钟,然后执行最后一个代码DF1Com1.Write("O:1/0", "0")。基本上这意味着即使您按住按键,每次按键也只会移动机器人一定的量。如果这不起作用,那么我只能想到一个键盘挂钩。
  • 我将此添加到我的答案中。
  • 有什么方法可以读取DF1Com1.Read中所写的内容
【解决方案2】:

实现此目的的另一个选择是使用布尔值来跟踪。这样做意味着,按热键开始,然后再次按停止。

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Static toggle As Boolean
        If m.Msg = HotKeyRegistryClass.Messages.WM_HOTKEY Then 'NOT THE ACTUAL WINDOWS NAMESPACE
            Dim ID As String = m.WParam.ToString()
            Select Case ID
                Case 0 :
            If toggle Then
             DF1Com1.Write("O:1/0", "0")
            Else
                        DF1Com1.Write("O:1/0", "1")
            End If
            toggle = Not toggle
                Case 1 : MessageBox.Show("S")
                Case 2 : MessageBox.Show("D")
                Case 3 : MessageBox.Show("F")
                Case 4 : MessageBox.Show("G")
                Case 5 : MessageBox.Show("H")
            End Select
        End If
        MyBase.WndProc(m)
    End Sub

【讨论】:

  • 你好,好主意。然而,不幸的是,这样做是不可行的。我只能想象会犯错误的用户数量。由于这个系统不是我自己用的,
  • 您好,前几天提出的建议解决方案的任何更新。谢谢
  • 我取得了一些进展,但假期耽误了我。今天我会努力完成的。
  • 非常感谢,我真的很感激。想请你喝啤酒!
  • 我这周不在城里。我希望能完成它,但我所有的时间都花在了将 zVirtualDesktop 设置为商业应用程序上。一旦我出差回来,我就会兑现这个……承诺。
猜你喜欢
  • 2014-09-22
  • 1970-01-01
  • 2016-02-28
  • 2010-12-12
  • 2019-12-07
  • 2016-02-22
  • 2011-03-15
  • 1970-01-01
  • 2021-01-27
相关资源
最近更新 更多