|
7 | 7 | '| |' |
8 | 8 | '| === COPYRIGHT LICENSE === |' |
9 | 9 | '| |' |
10 | | -'| Copyright (c) 2016-2018, Vincent Bengtsson |' |
| 10 | +'| Copyright (c) 2016-2019, Vincent Bengtsson |' |
11 | 11 | '| All rights reserved. |' |
12 | 12 | '| |' |
13 | 13 | '| Redistribution and use in source and binary forms, with or without |' |
@@ -465,6 +465,10 @@ Public NotInheritable Class InputHelper |
465 | 465 | Return New KeyboardHookEventArgs(KeyCode, ScanCode, Extended, If(KeyDown, KeyState.Down, KeyState.Up), Me.Modifiers) |
466 | 466 | End Function |
467 | 467 |
|
| 468 | + ''' <summary> |
| 469 | + ''' Initializes a new instance of the KeyboardHook class. |
| 470 | + ''' </summary> |
| 471 | + ''' <remarks></remarks> |
468 | 472 | Public Sub New() |
469 | 473 | hHook = NativeMethods.SetWindowsHookEx(NativeMethods.HookType.WH_KEYBOARD_LL, HookProcedureDelegate, NativeMethods.GetModuleHandle(Nothing), 0) |
470 | 474 | If hHook = IntPtr.Zero Then |
@@ -507,6 +511,133 @@ Public NotInheritable Class InputHelper |
507 | 511 | End Class |
508 | 512 | #End Region |
509 | 513 |
|
| 514 | +#Region "Local keyboard hook" |
| 515 | + ''' <summary> |
| 516 | + ''' A local keyboard hook that raises events when a key is pressed or released in a specific thread. |
| 517 | + ''' </summary> |
| 518 | + ''' <remarks></remarks> |
| 519 | + Public Class LocalKeyboardHook |
| 520 | + Implements IDisposable |
| 521 | + |
| 522 | + ''' <summary> |
| 523 | + ''' Occurs when a key is pressed or held down. |
| 524 | + ''' </summary> |
| 525 | + ''' <remarks></remarks> |
| 526 | + Public Event KeyDown As EventHandler(Of KeyboardHookEventArgs) |
| 527 | + |
| 528 | + ''' <summary> |
| 529 | + ''' Occurs when a key is released. |
| 530 | + ''' </summary> |
| 531 | + ''' <remarks></remarks> |
| 532 | + Public Event KeyUp As EventHandler(Of KeyboardHookEventArgs) |
| 533 | + |
| 534 | + Private hHook As IntPtr = IntPtr.Zero |
| 535 | + Private HookProcedureDelegate As New NativeMethods.KeyboardProc(AddressOf HookCallback) |
| 536 | + |
| 537 | + Private Modifiers As ModifierKeys = ModifierKeys.None |
| 538 | + |
| 539 | + Private Function HookCallback(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr |
| 540 | + Dim Block As Boolean = False |
| 541 | + |
| 542 | + If nCode >= NativeMethods.HookCode.HC_ACTION Then |
| 543 | + Dim KeyCode As Keys = CType(wParam.ToInt32(), Keys) |
| 544 | + Dim KeyFlags As New NativeMethods.DWORD(lParam.ToInt64()) |
| 545 | + Dim ScanCode As Byte = BitConverter.GetBytes(KeyFlags)(2) 'The scan code is the third byte in the integer (bits 16-23). |
| 546 | + Dim Extended As Boolean = (KeyFlags.High And NativeMethods.KeyboardFlags.KF_EXTENDED) = NativeMethods.KeyboardFlags.KF_EXTENDED |
| 547 | + Dim AltDown As Boolean = (KeyFlags.High And NativeMethods.KeyboardFlags.KF_ALTDOWN) = NativeMethods.KeyboardFlags.KF_ALTDOWN |
| 548 | + Dim KeyUp As Boolean = (KeyFlags.High And NativeMethods.KeyboardFlags.KF_UP) = NativeMethods.KeyboardFlags.KF_UP |
| 549 | + |
| 550 | + 'Set the ALT modifier if the KF_ALTDOWN flag is set. |
| 551 | + If AltDown = True _ |
| 552 | + AndAlso InputHelper.IsModifier(KeyCode, ModifierKeys.Alt) = False _ |
| 553 | + AndAlso (Me.Modifiers And ModifierKeys.Alt) <> ModifierKeys.Alt Then |
| 554 | + |
| 555 | + Me.Modifiers = Me.Modifiers Or ModifierKeys.Alt |
| 556 | + End If |
| 557 | + |
| 558 | + 'Raise KeyDown/KeyUp event. |
| 559 | + If KeyUp = False Then |
| 560 | + Dim HookEventArgs As New KeyboardHookEventArgs(KeyCode, ScanCode, Extended, KeyState.Down, Me.Modifiers) |
| 561 | + |
| 562 | + If InputHelper.IsModifier(KeyCode, ModifierKeys.Control) = True Then Me.Modifiers = Me.Modifiers Or ModifierKeys.Control |
| 563 | + If InputHelper.IsModifier(KeyCode, ModifierKeys.Shift) = True Then Me.Modifiers = Me.Modifiers Or ModifierKeys.Shift |
| 564 | + If InputHelper.IsModifier(KeyCode, ModifierKeys.Alt) = True Then Me.Modifiers = Me.Modifiers Or ModifierKeys.Alt |
| 565 | + If InputHelper.IsModifier(KeyCode, ModifierKeys.Windows) = True Then Me.Modifiers = Me.Modifiers Or ModifierKeys.Windows |
| 566 | + |
| 567 | + RaiseEvent KeyDown(Me, HookEventArgs) |
| 568 | + Block = HookEventArgs.Block |
| 569 | + Else |
| 570 | + 'Must be done before creating the HookEventArgs during KeyUp. |
| 571 | + If InputHelper.IsModifier(KeyCode, ModifierKeys.Control) = True Then Me.Modifiers = Me.Modifiers And Not ModifierKeys.Control |
| 572 | + If InputHelper.IsModifier(KeyCode, ModifierKeys.Shift) = True Then Me.Modifiers = Me.Modifiers And Not ModifierKeys.Shift |
| 573 | + If InputHelper.IsModifier(KeyCode, ModifierKeys.Alt) = True Then Me.Modifiers = Me.Modifiers And Not ModifierKeys.Alt |
| 574 | + If InputHelper.IsModifier(KeyCode, ModifierKeys.Windows) = True Then Me.Modifiers = Me.Modifiers And Not ModifierKeys.Windows |
| 575 | + |
| 576 | + Dim HookEventArgs As New KeyboardHookEventArgs(KeyCode, ScanCode, Extended, KeyState.Up, Me.Modifiers) |
| 577 | + |
| 578 | + RaiseEvent KeyUp(Me, HookEventArgs) |
| 579 | + Block = HookEventArgs.Block |
| 580 | + End If |
| 581 | + End If |
| 582 | + |
| 583 | + Return If(Block, New IntPtr(1), NativeMethods.CallNextHookEx(hHook, nCode, wParam, lParam)) |
| 584 | + End Function |
| 585 | + |
| 586 | + ''' <summary> |
| 587 | + ''' Initializes a new instance of the LocalKeyboardHook class attached to the current thread. |
| 588 | + ''' </summary> |
| 589 | + ''' <remarks></remarks> |
| 590 | + Public Sub New() |
| 591 | + Me.New(NativeMethods.GetCurrentThreadId()) |
| 592 | + End Sub |
| 593 | + |
| 594 | + ''' <summary> |
| 595 | + ''' Initializes a new instance of the LocalKeyboardHook class attached to the specified thread. |
| 596 | + ''' </summary> |
| 597 | + ''' <param name="ThreadID">The thread to attach the hook to.</param> |
| 598 | + ''' <remarks></remarks> |
| 599 | + Public Sub New(ByVal ThreadID As UInteger) |
| 600 | + hHook = NativeMethods.SetWindowsHookEx(NativeMethods.HookType.WH_KEYBOARD, HookProcedureDelegate, IntPtr.Zero, ThreadID) |
| 601 | + If hHook = IntPtr.Zero Then |
| 602 | + Dim Win32Error As Integer = Marshal.GetLastWin32Error() |
| 603 | + Throw New Win32Exception(Win32Error, "Failed to create local keyboard hook! (" & Win32Error & ")") |
| 604 | + End If |
| 605 | + End Sub |
| 606 | + |
| 607 | +#Region "IDisposable Support" |
| 608 | + Private disposedValue As Boolean ' To detect redundant calls |
| 609 | + |
| 610 | + ' IDisposable |
| 611 | + Protected Overridable Sub Dispose(disposing As Boolean) |
| 612 | + If Not Me.disposedValue Then |
| 613 | + If disposing Then |
| 614 | + ' TODO: dispose managed state (managed objects). |
| 615 | + End If |
| 616 | + |
| 617 | + ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below. |
| 618 | + ' TODO: set large fields to null. |
| 619 | + If hHook <> IntPtr.Zero Then NativeMethods.UnhookWindowsHookEx(hHook) |
| 620 | + End If |
| 621 | + Me.disposedValue = True |
| 622 | + End Sub |
| 623 | + |
| 624 | + Protected Overrides Sub Finalize() |
| 625 | + ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above. |
| 626 | + Dispose(False) |
| 627 | + MyBase.Finalize() |
| 628 | + End Sub |
| 629 | + |
| 630 | + ' This code added by Visual Basic to correctly implement the disposable pattern. |
| 631 | + Public Sub Dispose() Implements IDisposable.Dispose |
| 632 | + ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above. |
| 633 | + Dispose(True) |
| 634 | + GC.SuppressFinalize(Me) |
| 635 | + End Sub |
| 636 | +#End Region |
| 637 | + |
| 638 | + End Class |
| 639 | +#End Region |
| 640 | + |
510 | 641 | #Region "Mouse hook" |
511 | 642 | ''' <summary> |
512 | 643 | ''' A global low-level mouse hook that raises events when a mouse event occurs. |
@@ -669,6 +800,10 @@ Public NotInheritable Class InputHelper |
669 | 800 | Return If(Block, New IntPtr(1), NativeMethods.CallNextHookEx(hHook, nCode, wParam, lParam)) |
670 | 801 | End Function |
671 | 802 |
|
| 803 | + ''' <summary> |
| 804 | + ''' Initializes a new instance of the MouseHook clas. |
| 805 | + ''' </summary> |
| 806 | + ''' <remarks></remarks> |
672 | 807 | Public Sub New() |
673 | 808 | hHook = NativeMethods.SetWindowsHookEx(NativeMethods.HookType.WH_MOUSE_LL, HookProcedureDelegate, NativeMethods.GetModuleHandle(Nothing), 0) |
674 | 809 | If hHook = IntPtr.Zero Then |
@@ -1563,18 +1698,27 @@ Public NotInheritable Class InputHelper |
1563 | 1698 | #End Region |
1564 | 1699 |
|
1565 | 1700 | #Region "WinAPI P/Invokes" |
1566 | | - Private NotInheritable Class NativeMethods |
| 1701 | + ''' <summary> |
| 1702 | + ''' A class containing all the native WinAPI methods, structures, declarations, etc. used by InputHelper. |
| 1703 | + ''' </summary> |
| 1704 | + ''' <remarks></remarks> |
| 1705 | + Public NotInheritable Class NativeMethods |
1567 | 1706 | Private Sub New() |
1568 | 1707 | End Sub |
1569 | 1708 |
|
1570 | 1709 | #Region "Delegates" |
| 1710 | + Public Delegate Function KeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr |
1571 | 1711 | Public Delegate Function LowLevelKeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr |
1572 | 1712 | Public Delegate Function LowLevelMouseProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr |
1573 | 1713 | #End Region |
1574 | 1714 |
|
1575 | 1715 | #Region "Methods" |
1576 | 1716 |
|
1577 | 1717 | #Region "Hook methods" |
| 1718 | + <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _ |
| 1719 | + Public Shared Function SetWindowsHookEx(ByVal idHook As HookType, ByVal lpfn As KeyboardProc, ByVal hMod As IntPtr, ByVal dwThreadId As UInteger) As IntPtr |
| 1720 | + End Function |
| 1721 | + |
1578 | 1722 | <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _ |
1579 | 1723 | Public Shared Function SetWindowsHookEx(ByVal idHook As HookType, ByVal lpfn As LowLevelKeyboardProc, ByVal hMod As IntPtr, ByVal dwThreadId As UInteger) As IntPtr |
1580 | 1724 | End Function |
@@ -1693,6 +1837,15 @@ Public NotInheritable Class InputHelper |
1693 | 1837 | HC_NOREMOVE = 3 |
1694 | 1838 | End Enum |
1695 | 1839 |
|
| 1840 | + Public Enum KeyboardFlags As UInteger |
| 1841 | + KF_EXTENDED = &H100 |
| 1842 | + KF_DLGMODE = &H800 |
| 1843 | + KF_MENUMODE = &H1000 |
| 1844 | + KF_ALTDOWN = &H2000 |
| 1845 | + KF_REPEAT = &H4000 |
| 1846 | + KF_UP = &H8000 |
| 1847 | + End Enum |
| 1848 | + |
1696 | 1849 | Public Enum LowLevelKeyboardHookFlags As UInteger |
1697 | 1850 | LLKHF_EXTENDED = &H1 |
1698 | 1851 | LLKHF_LOWER_IL_INJECTED = &H2 |
@@ -1970,8 +2123,8 @@ Public NotInheritable Class InputHelper |
1970 | 2123 | Public y As Integer |
1971 | 2124 |
|
1972 | 2125 | Public Sub New(ByVal X As Integer, ByVal Y As Integer) |
1973 | | - Me.X = X |
1974 | | - Me.Y = Y |
| 2126 | + Me.x = X |
| 2127 | + Me.y = Y |
1975 | 2128 | End Sub |
1976 | 2129 | End Structure |
1977 | 2130 | #End Region |
|
0 commit comments