.NET 系统范围热键组件






4.33/5 (21投票s)
一个用于响应系统范围热键组合的组件。
引言
系统范围的热键是一种按键组合,无论哪个应用程序具有输入焦点,都会触发特定事件。 例如,如果您按下 WIN+E,则会启动一个新的资源管理器实例,或者如果您按下 CTRL+PRINTSCREEN,则当前活动的窗口会被屏幕截图到剪贴板。
Win32 API 有几个调用用于设置和响应热键 - 特别是 RegisterHotKey 和 UnregisterHotKey,您可以在 VB.NET 中这样声明
<DllImport("user32", EntryPoint:="RegisterHotKey", _
          SetLastError:=True, _
          ExactSpelling:=True, _
          CallingConvention:=CallingConvention.StdCall)> _
Public Function RegisterHotkey(ByVal hwnd As IntPtr, _
           ByVal Id As Int32, _
           <MarshalAs(UnmanagedType.U4)> ByVal fsModifiers As Int32, _
           <MarshalAs(UnmanagedType.U4)> ByVal vkey As Int32) As Boolean
End Function
<DllImport("user32", EntryPoint:="UnregisterHotKey", _
SetLastError:=True, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Public Function UnregisterHotkey(ByVal hwnd As Int32, _
                            ByVal Id As Int32) As Boolean
End Function
在热键通过 API 调用 RegisterHotkey 注册后,每当按下指定的按键组合时,就会将 WM_HOTKEY Windows 消息发送到 hwnd 参数中传递给它的窗口。
指定按键组合
触发事件的键由两个参数 fsModifiers 和 vKey 定义。
fsModifiers 是一个值,它告诉操作系统,热键组合中包含哪些修饰键 - 即 Alt、Ctrl、Shift 或 Win 键。 这个值由以下标志的组合组成
Public Enum HotkeyModifierFlags
    MOD_ALT = &H1
    MOD_CONTROL = &H2
    MOD_SHIFT = &H4
    MOD_WIN = &H8
End Enum
因此,例如,如果您想要一个热键是 CTRL+ALT+C,那么修饰符将是 MOD_ALT + MOD_CONTROL。
vKey 参数是与修饰符一起定义热键组合的键的虚拟键代码。
指定唯一的热键 ID
id 参数用于区分给定窗口可以接收的多个热键。 为了确保我们处理的是唯一的 ID,我使用 API 调用 GlobalAddAtom 来返回 id。 这是这样声明的
<DllImport("kernel32", EntryPoint:="GlobalAddAtom", _
SetLastError:=True, _
ExactSpelling:=False)> _
Public Function GlobalAddAtom(<MarshalAs(UnmanagedType.LPTStr)> _
                ByVal lpString As String) As Int32
End Function
创建一个窗口来监听 WM_HOTKEY 消息
最后一个参数是一个窗口句柄,用于监听 WM_HOTKEY 消息。 在这里有两个选择 - 要么传入现有窗口的句柄并子类化它的 WndProc 以查找该消息,要么创建一个新的不可见窗口专门用于监听该消息。
第二种选择是通过创建一个派生自 System.Windows.Forms.NativeWindow 的新类来实现的,如下所示
Public Class GlobalHotkeyListener
    Inherits NativeWindow
#Region "Private member variables"
    Private windowHandle As Integer
    Private mwh As ManualResetEvent
#End Region
    Public Sub New(ByVal Id As Int32, _
              ByVal fsModifiers As Int32, _
              ByVal vkey As Int32, _
              ByRef wh As ManualResetEvent)
        '\\ Get a local copy of the wait handle
        mwh = wh
        Dim cp As CreateParams = New CreateParams()
        ' Fill in the CreateParams details.
        cp.Caption = ""
        cp.ClassName = "STATIC"
        ' Set the position on the form
        cp.X = 0
        cp.Y = 0
        cp.Height = 0
        cp.Width = 0
        '\\ Set the style and extended style flags
        cp.Style = WindowStyleBits.WS_MINIMIZE
        cp.ExStyle = WindowStyleExtendedBits.WS_EX_NOACTIVATE
        ' Create the actual window
        Me.CreateHandle(cp)
        Try
            If Not RegisterHotkey(MyBase.Handle, _
                        Id, fsModifiers, vkey) Then
                Throw New Win32Exception()
            End If
        Catch e As Exception
            System.Diagnostics.Debug.WriteLine(e.ToString)
        End Try
    End Sub
对 WM_HOTKEY 的监听是这样完成的
<System.Security.Permissions._
                 PermissionSetAttribute(System.Security.Permissions_
                 .SecurityAction.Demand, Name:="FullTrust")> _
    Protected Overrides Sub WndProc(ByRef m As Message)
        ' Listen for messages that are sent to the 
        ' button window. Some messages are sent
        ' to the parent window instead of the button's window.
        Select Case (m.Msg)
            Case WM_HOTKEY
                ' Respond to the hotkey message (asynchronously??)
                If Not mwh Is Nothing Then
                    mwh.Set()
                End If
        End Select
        MyBase.WndProc(m)
    End Sub
未来改进
理想情况下,这个控件应该有一个 UIEditor 派生的类,以允许选择按键组合。


