Tác giả: Kỳ Nam
Mô tả: Dùng KeyboardHook sẽ 0 sợ hotkey đã được dùng bởi chương trình khác
Code: Select all
- Imports System.Runtime.InteropServices
-
- Public NotInheritable Class User32
-
- Public Declare Auto Function SetWindowsHookEx Lib "user32.dll" (ByVal idHook As WH, ByVal lpfn As HookProc, ByVal hmod As IntPtr, ByVal dwThreadId As Int32) As IntPtr
- Public Declare Function UnhookWindowsHookEx Lib "user32.dll" (ByVal hHook As IntPtr) As Boolean
- Public Declare Function CallNextHookEx Lib "user32.dll" (ByVal hHook As IntPtr, ByVal ncode As Int32, ByVal wParam As Int32, ByVal lParam As IntPtr) As Int32
- Delegate Function HookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
-
- Public Declare Auto Function MapVirtualKey Lib "user32.dll" (ByVal Code As Windows.Forms.Keys, ByVal MapType As MVK) As Short
-
- End Class
-
- <Flags()> Public Enum [MOD]
- None = 0
- Alt = 1
- Control = 2
- Shift = 4
- Win = 8
- End Enum
-
- Public Enum MVK
- VirtualKeyToScan
- ScanToVirtualKey
- VirtualKeyToCharacter
- ScanToVirtualKeyEx
- End Enum
-
- Public Enum WH
- CALLWNDPROC = 4
- CALLWNDPROCRET = 12
- CBT = 5
- DEBUG = 9
- FOREGROUNDIDLE = 11
- GETMESSAGE = 3
- HARDWARE = 8
- JOURNALPLAYBACK = 1
- JOURNALRECORD = 0
- KEYBOARD = 2
- KEYBOARD_LL = 13
- MAX = 11
- MAXHOOK = MAX
- MIN = -1
- MINHOOK = MIN
- MOUSE = 7
- MOUSE_LL = 14
- MSGFILTER = -1
- SHELL = 10
- SYSMSGFILTER = 6
- End Enum
-
- Public Enum WM
- KEYDOWN = &H100
- KEYUP = &H101
- SYSKEYDOWN = &H104
- SYSKEYUP = &H105
- End Enum
-
- Public MustInherit Class BaseHook
- Implements IDisposable
-
- Private HookHandle As IntPtr
- Private HookProc As User32.HookProc
-
- Protected MustOverride ReadOnly Property HookType() As WH
-
- ''' <summary>
- ''' Cần có sẵn standard application message loop trên thread hiện tại , nếu chưa có thì dùng Application.Run()
- ''' </summary>
- Public Sub InstallHook()
- If HookHandle <> IntPtr.Zero Then Return
- HookProc = AddressOf Hook
- HookHandle = User32.SetWindowsHookEx(HookType, HookProc, Marshal.GetHINSTANCE([GetType]().[Module]), 0)
- If HookHandle = IntPtr.Zero Then
- Throw New System.ComponentModel.Win32Exception()
- End If
- End Sub
-
- Private Function Hook(ByVal Code As Integer, ByVal WParam As IntPtr, ByVal LParam As IntPtr) As IntPtr
- Dim Result As IntPtr = User32.CallNextHookEx(HookHandle, Code, WParam, LParam)
- Return IIf(Code < 0, Result, IIf(InternalHookProcessing(WParam, LParam), New IntPtr(1), Result))
- End Function
-
- Protected MustOverride Function InternalHookProcessing(ByVal WParam As IntPtr, ByVal LParam As IntPtr) As Boolean
-
- Public Sub UninstallHook()
- If HookHandle = IntPtr.Zero Then Return
- User32.UnhookWindowsHookEx(HookHandle)
- HookHandle = IntPtr.Zero
- HookProc = Nothing
- End Sub
-
- #Region " IDisposable Support "
-
- Private disposedValue As Boolean = False ' To detect redundant calls
-
- ' IDisposable
- Protected Overridable Sub Dispose(ByVal disposing As Boolean)
- If Not Me.disposedValue Then
- If disposing Then
- ' TODO: free other state (managed objects).
- End If
-
- ' TODO: free your own state (unmanaged objects).
- UninstallHook()
- ' TODO: set large fields to null.
- End If
- Me.disposedValue = True
- End Sub
-
- ' This code added by Visual Basic to correctly implement the disposable pattern.
- Public Sub Dispose() Implements IDisposable.Dispose
- ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
- Dispose(True)
- GC.SuppressFinalize(Me)
- End Sub
-
- #End Region
-
- End Class
-
- Public Class KeyboardHook
- Inherits BaseHook
-
- Public Event KeyDown(ByVal sender As Object, ByVal e As KeyboardHookEventArgs)
- Public Event KeyUp(ByVal sender As Object, ByVal e As KeyboardHookEventArgs)
-
- Protected Overrides ReadOnly Property HookType() As WH
- Get
- Return WH.KEYBOARD_LL
- End Get
- End Property
-
- Protected Overrides Function InternalHookProcessing(ByVal WParam As System.IntPtr, ByVal LParam As System.IntPtr) As Boolean
- Dim Key As Keys
- Key = CType(Marshal.ReadInt32(LParam), Keys)
- Dim KHEA As New KeyboardHookEventArgs(Key, False)
-
- Select Case CType(WParam, WM)
- Case WM.SYSKEYDOWN, WM.KEYDOWN
- RaiseEvent KeyDown(Me, KHEA)
-
- Case WM.SYSKEYUP, WM.KEYUP
- RaiseEvent KeyUp(Me, KHEA)
-
- End Select
-
- Return KHEA.Cancel
- End Function
-
- End Class
-
- Public Class KeyboardHookEventArgs
-
- Private _Key As Keys
- Private _Cancel As Boolean
-
- Public Sub New()
- End Sub
-
- Public Sub New(ByVal Key As Keys, ByVal Cancel As Boolean)
- _Key = Key
- _Cancel = Cancel
- End Sub
-
- Public ReadOnly Property Key() As Keys
- Get
- Return _Key
- End Get
- End Property
-
- Public Property Cancel() As Boolean
- Get
- Return _Cancel
- End Get
- Set(ByVal value As Boolean)
- _Cancel = value
- End Set
- End Property
-
- End Class
-
- Public NotInheritable Class Macro
-
- Public Shared Function HiOrder(ByVal n As Integer) As Short
- Return (n >> 16) And 65535
- End Function
-
- Public Shared Function LoOrder(ByVal n As Integer) As Short
- Return n And 65535
- End Function
-
- End Class
-
- Public Structure HotKey
-
- Private M As [MOD]
- Private K As Keys
-
- Public Sub New(ByVal Value As Integer)
- M = Macro.HiOrder(Value)
- K = Macro.LoOrder(Value)
- End Sub
-
- Public Sub New(ByVal M As [MOD], ByVal K As Keys)
- Me.M = M
- Me.K = K
- End Sub
-
- Public Property Modifier() As [MOD]
- Get
- Return M
- End Get
- Set(ByVal value As [MOD])
- M = value
- End Set
- End Property
-
- Public Property Key() As Keys
- Get
- Return K
- End Get
- Set(ByVal value As Keys)
- K = value
- End Set
- End Property
-
- Public Shared Widening Operator CType(ByVal K As HotKey) As Integer
- Return (K.M << 16) Or K.K
- End Operator
-
- Public Shared Widening Operator CType(ByVal I As Integer) As HotKey
- Return New HotKey(I)
- End Operator
-
- Public Shared Operator =(ByVal a As HotKey, ByVal b As HotKey) As Boolean
- Return a.Value = b.Value
- End Operator
-
- Public Shared Operator <>(ByVal a As HotKey, ByVal b As HotKey) As Boolean
- Return Not a.Value = b.Value
- End Operator
-
- Public Overrides Function ToString() As String
- If K = Keys.None Then Return "None"
- Dim C As Char = Convert.ToChar(User32.MapVirtualKey(K, MVK.VirtualKeyToCharacter))
- If M > [MOD].None Then
- Dim S As String = ""
- If M And [MOD].Control Then S = S & "Ctrl+"
- If M And [MOD].Shift Then S = S & "Shift+"
- If M And [MOD].Alt Then S = S & "Alt+"
- If M And [MOD].Win Then S = S & "Win+"
- Return S & C
- Else
- Return C
- End If
- End Function
-
- Public ReadOnly Property HasKey() As Boolean
- Get
- Return K And Keys.KeyCode > Keys.None
- End Get
- End Property
-
- Public ReadOnly Property Value() As Integer
- Get
- Return (M << 16) Or CInt(K)
- End Get
- End Property
-
- Public Overrides Function GetHashCode() As Integer
- Return Value.GetHashCode
- End Function
-
- End Structure
-
- Public Delegate Sub HotKeyInvoker(ByVal Key As HotKey)
-
- Public Class HookHotKeyManager
-
- Public Delegate Sub HotKeyPressedHandler(ByVal sender As Object, ByVal HotKey As HotKey)
-
- Private HotKeyPressedHandlerList As New List(Of HotKeyPressedHandler)
-
- ''' <summary>
- ''' Asynchronous event
- ''' </summary>
- Public Custom Event HotKeyPressed As HotKeyPressedHandler
-
- AddHandler(ByVal value As HotKeyPressedHandler)
- HotKeyPressedHandlerList.Add(value)
- End AddHandler
-
- RemoveHandler(ByVal value As HotKeyPressedHandler)
- HotKeyPressedHandlerList.Remove(value)
- End RemoveHandler
-
- RaiseEvent(ByVal sender As Object, ByVal HotKey As HotKey)
- For Each handler As HotKeyPressedHandler In HotKeyPressedHandlerList
- If handler IsNot Nothing Then
- handler.BeginInvoke(sender, HotKey, Nothing, Nothing)
- End If
- Next
- End RaiseEvent
-
- End Event
-
- Dim WithEvents KH As New KeyboardHook
- Dim CurrentModifier As [MOD]
- Dim D As New Dictionary(Of HotKey, [Delegate])
-
- Public Sub Start()
- KH.InstallHook()
- End Sub
-
- Public Sub AddHotKey(ByVal Key As HotKey, ByVal Action As HotKeyInvoker)
- D.Add(Key, Action)
- End Sub
-
- Public Sub AddHotKey(ByVal Key As HotKey, ByVal Action As MethodInvoker)
- D.Add(Key, Action)
- End Sub
-
- Public Sub AddHotKey(ByVal Key As HotKey)
- D.Add(Key, Nothing)
- End Sub
-
- Private Sub KH_KeyDown(ByVal sender As Object, ByVal e As KeyboardHookEventArgs) Handles KH.KeyDown
- If e.Key = Keys.LMenu OrElse e.Key = Keys.RMenu Then
- CurrentModifier = CurrentModifier Or [MOD].Alt
-
- ElseIf e.Key = Keys.LControlKey OrElse e.Key = Keys.RControlKey Then
- CurrentModifier = CurrentModifier Or [MOD].Control
-
- ElseIf e.Key = Keys.LShiftKey OrElse e.Key = Keys.RShiftKey Then
- CurrentModifier = CurrentModifier Or [MOD].Shift
-
- ElseIf e.Key = Keys.LWin OrElse e.Key = Keys.RWin Then
- CurrentModifier = CurrentModifier Or [MOD].Win
-
- End If
- End Sub
-
- Private Sub KH_KeyUp(ByVal sender As Object, ByVal e As KeyboardHookEventArgs) Handles KH.KeyUp
- If e.Key = Keys.LMenu OrElse e.Key = Keys.RMenu Then
- CurrentModifier = CurrentModifier And Not [MOD].Alt
-
- ElseIf e.Key = Keys.LControlKey OrElse e.Key = Keys.RControlKey Then
- CurrentModifier = CurrentModifier And Not [MOD].Control
-
- ElseIf e.Key = Keys.LShiftKey OrElse e.Key = Keys.RShiftKey Then
- CurrentModifier = CurrentModifier And Not [MOD].Shift
-
- ElseIf e.Key = Keys.LWin OrElse e.Key = Keys.RWin Then
- CurrentModifier = CurrentModifier And Not [MOD].Win
-
- Else
- For Each HK As HotKey In D.Keys
- If HK.Modifier = CurrentModifier AndAlso HK.Key = e.Key Then
- Dim Action As [Delegate] = D(HK)
- If Action IsNot Nothing Then
- If TypeOf Action Is HotKeyInvoker Then
- DirectCast(Action, HotKeyInvoker).BeginInvoke(HK, Nothing, Nothing)
- ElseIf TypeOf Action Is MethodInvoker Then
- DirectCast(Action, MethodInvoker).BeginInvoke(Nothing, Nothing)
-
- End If
- End If
- RaiseEvent HotKeyPressed(Me, HK)
- End If
- Next
- End If
- End Sub
-
- End Class
dùng nó , bấm CTRL+A / CTRL+B để thấy
Code: Select all
- Public Class Form1
-
- Dim WithEvents HHKM As New HookHotKeyManager
-
- Public Sub New()
- ' This call is required by the Windows Form Designer.
- InitializeComponent()
-
- ' Add any initialization after the InitializeComponent() call.
- HHKM.AddHotKey(New HotKey([MOD].Control, Keys.A))
- HHKM.AddHotKey(New HotKey([MOD].Control, Keys.B), AddressOf HotKey2)
- HHKM.Start()
- End Sub
-
- Private Sub HHKM_HotKeyPressed(ByVal sender As Object, ByVal HotKey As HotKey) Handles HHKM.HotKeyPressed
- MessageBox.Show(HotKey.ToString)
- End Sub
-
- Private Sub HotKey2()
- MessageBox.Show("HotKey2 được bấm")
- End Sub
-
- End Class