Advertisement
Guest User

InputDevice.vb by Elektro - 04-July-2015

a guest
Jul 4th, 2015
319
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VB.NET 93.47 KB | None | 0 0
  1. ' ***********************************************************************
  2. ' Author   : Elektro
  3. ' Modified : 04-July-2015
  4. ' ***********************************************************************
  5. ' <copyright file="InputDevice.vb" company="Elektro Studios">
  6. '     Copyright (c) Elektro Studios. All rights reserved.
  7. ' </copyright>
  8. ' ***********************************************************************
  9.  
  10. #Region " Option Statements "
  11.  
  12. Option Strict On
  13. Option Explicit On
  14. Option Infer Off
  15.  
  16. #End Region
  17.  
  18. #Region " Imports "
  19.  
  20. Imports Microsoft.Win32
  21. Imports System.Collections
  22. Imports System.Globalization
  23. Imports System.Linq
  24. Imports System.Runtime.InteropServices
  25. Imports System.Text
  26. Imports System.Windows.Forms
  27. Imports System.ComponentModel
  28.  
  29. #End Region
  30.  
  31. ''' ----------------------------------------------------------------------------------------------------
  32. ''' <summary>
  33. ''' Handles raw input from keyboard devices.
  34. ''' </summary>
  35. ''' ----------------------------------------------------------------------------------------------------
  36. Public NotInheritable Class InputDevice : Inherits NativeWindow : Implements IDisposable
  37.  
  38. #Region " P/Invoking "
  39.  
  40.     ''' ----------------------------------------------------------------------------------------------------
  41.     ''' <summary>
  42.     ''' Platform Invocation methods (P/Invoke), access unmanaged code.
  43.     ''' This class does not suppress stack walks for unmanaged code permission.
  44.     ''' <see cref="System.Security.SuppressUnmanagedCodeSecurityAttribute"/>  must not be applied to this class.
  45.     ''' This class is for methods that can be used anywhere because a stack walk will be performed.
  46.     ''' </summary>
  47.     ''' ----------------------------------------------------------------------------------------------------
  48.     ''' <remarks>http://msdn.microsoft.com/en-us/library/ms182161.aspx</remarks>
  49.     ''' ----------------------------------------------------------------------------------------------------
  50.     Private NotInheritable Class NativeMethods
  51.  
  52. #Region " Functions "
  53.  
  54.         ''' ----------------------------------------------------------------------------------------------------
  55.         ''' <summary>
  56.         ''' Enumerates the raw input devices attached to the system.
  57.         ''' </summary>
  58.         ''' ----------------------------------------------------------------------------------------------------
  59.         ''' <param name="pRawInputDeviceList">
  60.         ''' An array of <see cref="InputDevice.NativeMethods.RawInputDeviceList"></see> structures for the devices attached to the system.
  61.         ''' If <see cref="IntPtr.Zero"></see>, the number of devices are returned in <paramref name="puiNumDevices"></paramref> parameter.
  62.         ''' </param>
  63.         '''
  64.         ''' <param name="puiNumDevices">
  65.         ''' If <paramref name="pRawInputDeviceList"></paramref> is <see cref="IntPtr.Zero"></see>,
  66.         ''' the function populates this variable with the number of devices attached to the system;
  67.         ''' otherwise, this variable specifies the number of <see cref="InputDevice.NativeMethods.RawInputDeviceList"></see> structures that
  68.         ''' can be contained in the buffer to which <paramref name="pRawInputDeviceList"></paramref> points.
  69.         ''' If this value is less than the number of devices attached to the system,
  70.         ''' the function returns the actual number of devices in this variable and fails with ERROR_INSUFFICIENT_BUFFER.
  71.         ''' </param>
  72.         '''
  73.         ''' <param name="cbSize">
  74.         ''' The size of a <see cref="InputDevice.NativeMethods.RawInputDeviceList"></see> structure, in bytes.
  75.         ''' </param>
  76.         ''' ----------------------------------------------------------------------------------------------------
  77.         ''' <returns>
  78.         ''' If the function is successful, the return value is the number of devices stored in the buffer pointed to by <paramref name="pRawInputDeviceList"></paramref>.
  79.         ''' On any other error, the function returns -1 and <see cref="Marshal.GetLastWin32Error"></see> returns the error indication.
  80.         ''' </returns>
  81.         ''' ----------------------------------------------------------------------------------------------------
  82.         ''' <remarks>https://msdn.microsoft.com/es-es/library/windows/desktop/ms645598%28v=vs.85%29.aspx</remarks>
  83.         ''' ----------------------------------------------------------------------------------------------------
  84.         <DllImport("User32.dll", SetLastError:=True)>
  85.         Friend Shared Function GetRawInputDeviceList(
  86.                                ByVal pRawInputDeviceList As IntPtr,
  87.                                ByRef puiNumDevices As UInteger,
  88.                                ByVal cbSize As UInteger
  89.         ) As UInteger
  90.         End Function
  91.  
  92.         ''' ----------------------------------------------------------------------------------------------------
  93.         ''' <summary>
  94.         ''' Retrieves information about the raw input device.
  95.         ''' </summary>
  96.         ''' ----------------------------------------------------------------------------------------------------
  97.         ''' <param name="hDevice">
  98.         ''' A handle to the raw input device.
  99.         ''' This comes from the lParam of the WM_INPUT message,
  100.         ''' from the <see cref="InputDevice.NativeMethods.RawInputHeader.HDevice"></see> member of
  101.         ''' <see cref="InputDevice.NativeMethods.RawInputHeader"></see> structure,
  102.         ''' or from <see cref="InputDevice.NativeMethods.GetRawInputDeviceList"></see> function.
  103.         ''' It can also be <see cref="IntPtr.Zero"></see> if an application inserts input data, for example, by using SendInput fcuntion.
  104.         ''' </param>
  105.         '''
  106.         ''' <param name="uiCommand">
  107.         ''' Specifies what data will be returned in <paramref name="pData"></paramref>.
  108.         ''' </param>
  109.         '''
  110.         ''' <param name="pData">
  111.         ''' A pointer to a buffer that contains the information specified by uiCommand.
  112.         ''' If <paramref name="uiCommand"></paramref> is RIDI_DEVICEINFO, set the cbSize member of
  113.         ''' RID_DEVICE_INFO to sizeof(RID_DEVICE_INFO) before calling <see cref="InputDevice.NativeMethods.GetRawInputDeviceInfo"></see> function.
  114.         ''' </param>
  115.         '''
  116.         ''' <param name="pcbSize">
  117.         ''' The size, in bytes, of the data in <paramref name="pData"></paramref>.
  118.         ''' </param>
  119.         ''' ----------------------------------------------------------------------------------------------------
  120.         ''' <returns>
  121.         ''' If successful, this function returns a non-negative number indicating the number of bytes copied to <paramref name="pData"></paramref>.
  122.         ''' If <paramref name="pData"></paramref> is not large enough for the data, the function returns -1.
  123.         ''' If <paramref name="pData"></paramref> is <see cref="IntPtr.Zero"></see>, the function returns 0.
  124.         ''' In both of these cases, <paramref name="pcbSize"></paramref> is set to the minimum size required for the <paramref name="pData"></paramref> buffer.
  125.         ''' Call <see cref="Marshal.GetLastWin32Error"></see> to identify any other errors.
  126.         ''' </returns>
  127.         ''' ----------------------------------------------------------------------------------------------------
  128.         ''' <remarks>https://msdn.microsoft.com/es-es/library/windows/desktop/ms645597%28v=vs.85%29.aspx</remarks>
  129.         ''' ----------------------------------------------------------------------------------------------------
  130.         <DllImport("User32.dll", SetLastError:=True)>
  131.         Friend Shared Function GetRawInputDeviceInfo(
  132.                                ByVal hDevice As IntPtr,
  133.                                ByVal uiCommand As InputDevice.NativeMethods.GetRawInputDeviceInfoCommand,
  134.                                ByVal pData As IntPtr,
  135.                                ByRef pcbSize As UInteger
  136.         ) As UInteger
  137.         End Function
  138.  
  139.         ''' ----------------------------------------------------------------------------------------------------
  140.         ''' <summary>
  141.         ''' Registers the devices that supply the raw input data.
  142.         ''' </summary>
  143.         ''' ----------------------------------------------------------------------------------------------------
  144.         ''' <param name="pRawInputDevice">
  145.         ''' An array of <see cref="InputDevice.NativeMethods.RawInputDevice"></see> structures that represent the devices that supply the raw input.
  146.         ''' </param>
  147.         '''
  148.         ''' <param name="uiNumDevices">
  149.         ''' The number of <see cref="InputDevice.NativeMethods.RawInputDevice"></see> structures pointed to by <paramref name="pRawInputDevices"></paramref>.
  150.         ''' </param>
  151.         '''
  152.         ''' <param name="cbSize">
  153.         ''' The size, in bytes, of a <see cref="InputDevice.NativeMethods.RawInputDevice"></see> structure.
  154.         ''' </param>
  155.         ''' ----------------------------------------------------------------------------------------------------
  156.         ''' <returns>
  157.         ''' <c>true</c> if the function succeeds; <c>false</c> otherwise.
  158.         ''' Call <see cref="Marshal.GetLastWin32Error"></see> for more information.
  159.         ''' </returns>
  160.         ''' ----------------------------------------------------------------------------------------------------
  161.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645600%28v=vs.85%29.aspx</remarks>
  162.         ''' ----------------------------------------------------------------------------------------------------
  163.         <DllImport("User32.dll", SetLastError:=True)>
  164.         Friend Shared Function RegisterRawInputDevices(
  165.                                ByVal pRawInputDevice As RawInputDevice(),
  166.                                ByVal uiNumDevices As UInteger,
  167.                                ByVal cbSize As UInteger
  168.         ) As Boolean
  169.         End Function
  170.  
  171.         ''' ----------------------------------------------------------------------------------------------------
  172.         ''' <summary>
  173.         ''' Retrieves the raw input from the specified device.
  174.         ''' </summary>
  175.         ''' ----------------------------------------------------------------------------------------------------
  176.         ''' <param name="hRawInput">
  177.         ''' A handle to the <see cref="InputDevice.NativeMethods.Rawinput"></see> structure.
  178.         ''' This comes from the lParam in WM_INPUT.
  179.         ''' </param>
  180.         '''
  181.         ''' <param name="uiCommand">
  182.         ''' The command flag.
  183.         ''' </param>
  184.         '''
  185.         ''' <param name="pData">
  186.         ''' A pointer to the data that comes from the <see cref="InputDevice.NativeMethods.Rawinput"></see> structure.
  187.         ''' This depends on the value of <paramref name="uiCommand"></paramref>.
  188.         ''' If <paramref name="pData"></paramref> is <see cref="IntPtr.Zero"></see>, the required size of the buffer is
  189.         ''' returned in <paramref name="pcbSize"></paramref>.
  190.         ''' </param>
  191.         '''
  192.         ''' <param name="pcbSize">
  193.         ''' The size, in bytes, of the data in <paramref name="pData"></paramref>.
  194.         ''' </param>
  195.         '''
  196.         ''' <param name="cbSizeHeader">
  197.         ''' The size, in bytes, of the <see cref="InputDevice.NativeMethods.RawInputHeader"></see> structure.
  198.         ''' </param>
  199.         ''' ----------------------------------------------------------------------------------------------------
  200.         ''' <returns>
  201.         ''' If <paramref name="pData"></paramref> is <see cref="IntPtr.Zero"></see> and the function is successful, the return value is 0.
  202.         ''' If <paramref name="pData"></paramref> is not <see cref="IntPtr.Zero"></see> and the function is successful, the return value is
  203.         ''' the number of bytes copied into <paramref name="pData"></paramref>.
  204.         ''' If there is an error, the return value is -1.
  205.         ''' </returns>
  206.         ''' ----------------------------------------------------------------------------------------------------
  207.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645596%28v=vs.85%29.aspx</remarks>
  208.         ''' ----------------------------------------------------------------------------------------------------
  209.         <DllImport("User32.dll")>
  210.         Friend Shared Function GetRawInputData(
  211.                                ByVal hRawInput As IntPtr,
  212.                                ByVal uiCommand As InputDevice.NativeMethods.GetRawInputDataCommand,
  213.                                ByVal pData As IntPtr,
  214.                                ByRef pcbSize As UInteger,
  215.                                ByVal cbSizeHeader As UInteger
  216.         ) As UInteger
  217.         End Function
  218.  
  219.         ''' ----------------------------------------------------------------------------------------------------
  220.         ''' <summary>
  221.         ''' Translates the specified virtual-key code and keyboard state to the corresponding Unicode character or characters.
  222.         ''' </summary>
  223.         ''' ----------------------------------------------------------------------------------------------------
  224.         ''' <param name="wVirtKey">
  225.         ''' The virtual-key code to be translated.
  226.         ''' See Virtual-Key Codes: https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx
  227.         ''' </param>
  228.         '''
  229.         ''' <param name="wScanCode">
  230.         ''' The hardware scan code of the key to be translated.
  231.         ''' The high-order bit of this value is set if the key is up.
  232.         ''' </param>
  233.         '''
  234.         ''' <param name="lpKeyState">
  235.         ''' A pointer to a 256-byte array that contains the current keyboard state.
  236.         ''' Each element (byte) in the array contains the state of one key.
  237.         ''' If the high-order bit of a byte is set, the key is down.
  238.         ''' </param>
  239.         '''
  240.         ''' <param name="pwszBuff">
  241.         ''' The buffer that receives the translated Unicode character or characters.
  242.         ''' However, this buffer may be returned without being null-terminated even though the
  243.         ''' variable name suggests that it is null-terminated.
  244.         ''' </param>
  245.         '''
  246.         ''' <param name="cchBuff">
  247.         ''' The size, in characters, of the buffer pointed to by the <paramref name="pwszBuff"></paramref> parameter.
  248.         ''' </param>
  249.         '''
  250.         ''' <param name="wFlags">
  251.         ''' The behavior of the function.
  252.         ''' If bit 0 is set, a menu is active.
  253.         ''' Bits 1 through 31 are reserved.
  254.         ''' </param>
  255.         '''
  256.         ''' <param name="dwhkl">
  257.         ''' The input locale identifier used to translate the specified code.
  258.         ''' This parameter can be any input locale identifier previously returned by the LoadKeyboardLayout function.
  259.         ''' </param>
  260.         ''' ----------------------------------------------------------------------------------------------------
  261.         ''' <returns>
  262.         ''' The function returns one of the following values.
  263.         '''
  264.         ''' -1:
  265.         ''' The specified virtual key is a dead-key character (accent or diacritic).
  266.         ''' This value is returned regardless of the keyboard layout,
  267.         ''' even if several characters have been typed and are stored in the keyboard state.
  268.         ''' If possible, even with Unicode keyboard layouts,
  269.         ''' the function has written a spacing version of the dead-key character to the buffer specified by <paramref name="pwszBuff"></paramref>.
  270.         ''' For example, the function writes the character SPACING ACUTE (0x00B4),
  271.         ''' rather than the character NON_SPACING ACUTE (0x0301).
  272.         '''
  273.         ''' 0:
  274.         ''' The specified virtual key has no translation for the current state of the keyboard.
  275.         ''' Nothing was written to the buffer specified by <paramref name="pwszBuff"></paramref>.
  276.         '''
  277.         ''' 1:
  278.         ''' One character was written to the buffer specified by <paramref name="pwszBuff"></paramref>.
  279.         '''
  280.         ''' 2 ≤:
  281.         ''' Two or more characters were written to the buffer specified by <paramref name="pwszBuff"></paramref>.
  282.         ''' The most common cause for this is that a dead-key character (accent or diacritic) stored in the
  283.         ''' keyboard layout could not be combined with the specified virtual key to form a single character.
  284.         ''' However, the buffer may contain more characters than the return value specifies.
  285.         ''' When this happens, any extra characters are invalid and should be ignored.
  286.         ''' </returns>
  287.         ''' ----------------------------------------------------------------------------------------------------
  288.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms646322%28v=vs.85%29.aspx</remarks>
  289.         ''' ----------------------------------------------------------------------------------------------------
  290.         <DllImport("user32.dll", CharSet:=CharSet.Auto, ExactSpelling:=True, CallingConvention:=CallingConvention.Winapi)>
  291.         Friend Shared Function ToUnicodeEx(
  292.                                ByVal wVirtKey As UInteger,
  293.                                ByVal wScanCode As UInteger,
  294.                                ByVal lpKeyState As Byte(),
  295.                                <Out, MarshalAs(UnmanagedType.LPWStr)>
  296.                                ByVal pwszBuff As StringBuilder,
  297.                                ByVal cchBuff As Integer,
  298.                                ByVal wFlags As UInteger,
  299.                                ByVal dwhkl As IntPtr
  300.         ) As Integer
  301.         End Function
  302.  
  303.         <DllImport("user32.dll", CharSet:=CharSet.Auto, ExactSpelling:=True, CallingConvention:=CallingConvention.Winapi)>
  304.         Friend Shared Function ToUnicode(
  305.                                ByVal wVirtKey As UInteger,
  306.                                ByVal wScanCode As UInteger,
  307.                                ByVal lpKeyState As Byte(),
  308.                                <Out, MarshalAs(UnmanagedType.LPWStr)>
  309.                                ByVal pwszBuff As StringBuilder,
  310.                                ByVal cchBuff As Integer,
  311.                                ByVal wFlags As UInteger
  312.         ) As Integer
  313.         End Function
  314.  
  315.         ''' ----------------------------------------------------------------------------------------------------
  316.         ''' <summary>
  317.         ''' Retrieves the status of the specified virtual key.
  318.         ''' The status specifies whether the key is up, down, or toggled (on, off—alternating each time the key is pressed).
  319.         ''' </summary>
  320.         ''' ----------------------------------------------------------------------------------------------------
  321.         ''' <param name="vKey">
  322.         ''' The virtual-key code.
  323.         ''' See Virtual-Key Codes: https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx
  324.         ''' </param>
  325.         ''' ----------------------------------------------------------------------------------------------------
  326.         ''' <returns>
  327.         ''' If the high-order bit is 1, the key is down; otherwise, it is up.
  328.         ''' If the low-order bit is 1, the key is toggled.
  329.         ''' A key, such as the CAPS LOCK key, is toggled if it is turned on.
  330.         ''' The key is off and untoggled if the low-order bit is 0.
  331.         ''' A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled, and off when the key is untoggled.
  332.         ''' </returns>
  333.         ''' ----------------------------------------------------------------------------------------------------
  334.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms646301%28v=vs.85%29.aspx</remarks>
  335.         ''' ----------------------------------------------------------------------------------------------------
  336.         <DllImport("user32.dll", CharSet:=CharSet.Auto, ExactSpelling:=True, CallingConvention:=CallingConvention.Winapi)>
  337.         Friend Shared Function GetKeyState(
  338.                                ByVal vKey As Keys
  339.         ) As Short
  340.         End Function
  341.  
  342.         ''' ----------------------------------------------------------------------------------------------------
  343.         ''' <summary>
  344.         ''' Determines whether a key is up or down at the time the function is called,
  345.         ''' and whether the key was pressed after a previous call to GetAsyncKeyState.
  346.         ''' </summary>
  347.         ''' ----------------------------------------------------------------------------------------------------
  348.         ''' <param name="vKey">
  349.         ''' The virtual-key code.
  350.         ''' See Virtual-Key Codes: https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx
  351.         ''' You can use left- and right-distinguishing constants to specify certain keys.
  352.         ''' </param>
  353.         ''' ----------------------------------------------------------------------------------------------------
  354.         ''' <returns>
  355.         ''' If the function succeeds,
  356.         ''' the return value specifies whether the key was pressed since the last call to
  357.         ''' <see cref="InputDevice.NativeMethods.GetAsyncKeyState"></see>,
  358.         ''' and whether the key is currently up or down.
  359.         ''' If the most significant bit is set, the key is down,
  360.         ''' and if the least significant bit is set, the key was pressed after the previous call to
  361.         ''' <see cref="InputDevice.NativeMethods.GetAsyncKeyState"></see>.
  362.         ''' However, you should not rely on this last behavior.
  363.         ''' </returns>
  364.         ''' ----------------------------------------------------------------------------------------------------
  365.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms646293%28v=vs.85%29.aspx</remarks>
  366.         ''' ----------------------------------------------------------------------------------------------------
  367.         <DllImport("user32.dll", CharSet:=CharSet.Auto, ExactSpelling:=True, CallingConvention:=CallingConvention.Winapi)>
  368.         Friend Shared Function GetAsyncKeyState(
  369.                                 ByVal vKey As Keys
  370.         ) As Short
  371.         End Function
  372.  
  373. #End Region
  374.  
  375. #Region " Enumerations "
  376.  
  377.         ''' <summary>
  378.         ''' The system sends or posts a system-defined message when it communicates with an application.
  379.         ''' It uses these messages to control the operations of applications and to provide input and other information for applications to process.
  380.         ''' An application can also send or post system-defined messages.
  381.         ''' Applications generally use these messages to control the operation of control windows created by using preregistered window classes.
  382.         ''' </summary>
  383.         ''' ----------------------------------------------------------------------------------------------------
  384.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms644927%28v=vs.85%29.aspx</remarks>
  385.         ''' ----------------------------------------------------------------------------------------------------
  386.         Friend Enum WindowsMessages As Integer
  387.  
  388.             ''' ----------------------------------------------------------------------------------------------------
  389.             ''' <summary>
  390.             ''' Sent to the window that is getting raw input.
  391.             ''' A window receives this message through its WindowProc function.
  392.             ''' </summary>
  393.             ''' ----------------------------------------------------------------------------------------------------
  394.             ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645590%28v=vs.85%29.aspx</remarks>
  395.             ''' ----------------------------------------------------------------------------------------------------
  396.             WM_INPUT = &HFF
  397.  
  398.             ''' ----------------------------------------------------------------------------------------------------
  399.             ''' <summary>
  400.             ''' Posted to the window with the keyboard focus when a nonsystem key is pressed.
  401.             ''' A nonsystem key is a key that is pressed when the ALT key is not pressed
  402.             ''' </summary>
  403.             ''' ----------------------------------------------------------------------------------------------------
  404.             ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms646280%28v=vs.85%29.aspx</remarks>
  405.             ''' ----------------------------------------------------------------------------------------------------
  406.             WM_KEYDOWN = &H100
  407.  
  408.             ''' ----------------------------------------------------------------------------------------------------
  409.             ''' <summary>
  410.             ''' Posted to the window with the keyboard focus when the user presses the F10 key (which activates the menu bar)
  411.             ''' or holds down the ALT key and then presses another key.
  412.             ''' It also occurs when no window currently has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the active window.
  413.             ''' The window that receives the message can distinguish between these two contexts by checking the context code in the lParam parameter
  414.             ''' </summary>
  415.             ''' ----------------------------------------------------------------------------------------------------
  416.             ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms646286%28v=vs.85%29.aspx</remarks>
  417.             ''' ----------------------------------------------------------------------------------------------------
  418.             WM_SYSKEYDOWN = &H104
  419.  
  420.         End Enum
  421.  
  422.         ''' ----------------------------------------------------------------------------------------------------
  423.         ''' <summary>
  424.         ''' Specifies a type of device.
  425.         ''' </summary>
  426.         ''' ----------------------------------------------------------------------------------------------------
  427.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645568%28v=vs.85%29.aspx</remarks>
  428.         ''' ----------------------------------------------------------------------------------------------------
  429.         Friend Enum DeviceType As Integer
  430.  
  431.             ''' <summary>
  432.             ''' The device is a mouse.
  433.             ''' </summary>
  434.             Mouse = &H0 ' RIM_TYPEMOUSE
  435.  
  436.             ''' <summary>
  437.             ''' The device is a keyboard.
  438.             ''' </summary>
  439.             Keyboard = &H1 ' RIM_TYPEKEYBOARD
  440.  
  441.             ''' <summary>
  442.             ''' The device is an HID that is not a keyboard and not a mouse.
  443.             ''' </summary>
  444.             Hid = &H2 ' RIM_TYPEHID
  445.  
  446.         End Enum
  447.  
  448.         ''' ----------------------------------------------------------------------------------------------------
  449.         ''' <summary>
  450.         ''' Values for <paramref name="uiCommand"></paramref> of <see cref="InputDevice.NativeMethods.GetRawInputDeviceInfo"></see> function.
  451.         ''' </summary>
  452.         ''' ----------------------------------------------------------------------------------------------------
  453.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645581%28v=vs.85%29.aspx</remarks>
  454.         ''' ----------------------------------------------------------------------------------------------------
  455.         Friend Enum GetRawInputDeviceInfoCommand As UInteger
  456.  
  457.             ''' <summary>
  458.             ''' <paramref name="pData"></paramref> points to a string that contains the device name.
  459.             ''' </summary>
  460.             DeviceName = &H20000007UI
  461.  
  462.             ''' <summary>
  463.             ''' <paramref name="pData"></paramref> points to an RID_DEVICE_INFO structure.
  464.             ''' </summary>
  465.             DeviceInfo = &H2000000BUI
  466.  
  467.             ''' <summary>
  468.             ''' <paramref name="pData"></paramref> points to the previously parsed data.
  469.             ''' </summary>
  470.             PreParsedData = &H20000005UI
  471.  
  472.         End Enum
  473.  
  474.         ''' ----------------------------------------------------------------------------------------------------
  475.         ''' <summary>
  476.         ''' Values for <paramref name="uiCommand"></paramref> of <see cref="InputDevice.NativeMethods.GetRawInputData"></see> function.
  477.         ''' </summary>
  478.         ''' ----------------------------------------------------------------------------------------------------
  479.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645596%28v=vs.85%29.aspx</remarks>
  480.         ''' ----------------------------------------------------------------------------------------------------
  481.         Friend Enum GetRawInputDataCommand As UInteger
  482.  
  483.             ''' <summary>
  484.             ''' Get the header information from the <see cref="InputDevice.NativeMethods.Rawinput"></see> structure.
  485.             ''' </summary>
  486.             Header = &H10000005UI
  487.  
  488.             ''' <summary>
  489.             ''' Get the raw data from the <see cref="InputDevice.NativeMethods.Rawinput"></see> structure.
  490.             ''' </summary>
  491.             Input = &H10000003UI
  492.  
  493.         End Enum
  494.  
  495.         ''' ----------------------------------------------------------------------------------------------------
  496.         ''' <summary>
  497.         ''' Values for <paramref name="dwFlags"></paramref> of <see cref="InputDevice.NativeMethods.RawInputDevice"></see> structure.
  498.         ''' </summary>
  499.         ''' ----------------------------------------------------------------------------------------------------
  500.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645565%28v=vs.85%29.aspx</remarks>
  501.         ''' ----------------------------------------------------------------------------------------------------
  502.         <Flags>
  503.         Friend Enum RawInputDeviceFlags As Integer
  504.  
  505.             ''' <summary>
  506.             ''' If set, the application command keys are handled.
  507.             ''' <see cref="InputDevice.NativeMethods.RawInputDeviceFlags.AppKeys"></see> can be specified only if
  508.             ''' <see cref="InputDevice.NativeMethods.RawInputDeviceFlags.NoLegacy"></see> is specified for a keyboard device.
  509.             ''' </summary>
  510.             AppKeys = &H400
  511.  
  512.             ''' <summary>
  513.             ''' If set, the mouse button click does not activate the other window.
  514.             ''' </summary>
  515.             CaptureMouse = &H200
  516.  
  517.             ''' <summary>
  518.             ''' If set, this enables the caller to receive WM_INPUT_DEVICE_CHANGE notifications for device arrival and device removal.
  519.             ''' </summary>
  520.             DevNotify = &H2000
  521.  
  522.             ''' <summary>
  523.             ''' If set, this specifies the top level collections to exclude when reading a complete usage page.
  524.             ''' This flag only affects a TLC whose usage page is already specified with
  525.             ''' <see cref="InputDevice.NativeMethods.RawInputDeviceFlags.PageOnly"></see>.
  526.             ''' </summary>
  527.             Exclude = &H10
  528.  
  529.             ''' <summary>
  530.             ''' If set, this enables the caller to receive input in the background only if the foreground application does not process it.
  531.             ''' In other words, if the foreground application is not registered for raw input,
  532.             ''' then the background application that is registered will receive the input.
  533.             ''' </summary>
  534.             ExInputSink = &H1000
  535.  
  536.             ''' <summary>
  537.             ''' If set, this enables the caller to receive the input even when the caller is not in the foreground.
  538.             ''' Note that hwndTarget must be specified.
  539.             ''' </summary>
  540.             InputSink = &H100
  541.  
  542.             ''' <summary>
  543.             ''' If set, the application-defined keyboard device hotkeys are not handled.
  544.             ''' However, the system hotkeys; for example, ALT+TAB and CTRL+ALT+DEL, are still handled.
  545.             ''' By default, all keyboard hotkeys are handled.
  546.             ''' <see cref="InputDevice.NativeMethods.RawInputDeviceFlags.NoHotkeys"></see> can be specified even if
  547.             ''' <see cref="InputDevice.NativeMethods.RawInputDeviceFlags.NoLegacy"></see> is not specified and hwndTarget is NULL.
  548.             ''' </summary>
  549.             NoHotkeys = &H200
  550.  
  551.             ''' <summary>
  552.             ''' If set, the application-defined keyboard device hotkeys are not handled.
  553.             ''' However, the system hotkeys; for example, ALT+TAB and CTRL+ALT+DEL, are still handled.
  554.             ''' By default, all keyboard hotkeys are handled.
  555.             ''' <see cref="InputDevice.NativeMethods.RawInputDeviceFlags.NoHotkeys"></see> can be specified even if
  556.             ''' <see cref="InputDevice.NativeMethods.RawInputDeviceFlags.NoLegacy"></see> is not specified and hwndTarget is NULL.
  557.             ''' </summary>
  558.             NoLegacy = &H30
  559.  
  560.             ''' <summary>
  561.             ''' If set, this specifies all devices whose top level collection is from the
  562.             ''' specified <see cref="InputDevice.NativeMethods.RawInputDevice.UsUsagePage"></see>.
  563.             ''' Note that <see cref="InputDevice.NativeMethods.RawInputDevice.UsUsage"></see> must be zero.
  564.             ''' To exclude a particular top level collection, use <see cref="InputDevice.NativeMethods.RawInputDeviceFlags.Exclude"></see>.
  565.             ''' </summary>
  566.             PageOnly = &H20
  567.  
  568.             ''' <summary>
  569.             ''' If set, this removes the top level collection from the inclusion list.
  570.             ''' This tells the operating system to stop reading from a device which matches the top level collection.
  571.             ''' </summary>
  572.             Remove = &H1
  573.  
  574.         End Enum
  575.  
  576. #End Region
  577.  
  578. #Region " Structures"
  579.  
  580.         ''' ----------------------------------------------------------------------------------------------------
  581.         ''' <summary>
  582.         ''' Contains information about a raw input device.
  583.         ''' </summary>
  584.         ''' ----------------------------------------------------------------------------------------------------
  585.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645568%28v=vs.85%29.aspx</remarks>
  586.         ''' ----------------------------------------------------------------------------------------------------
  587.         <StructLayout(LayoutKind.Sequential)>
  588.         Friend Structure RawInputDeviceList
  589.  
  590.             ''' <summary>
  591.             ''' A handle to the raw input device.
  592.             ''' </summary>
  593.             Public HDevice As IntPtr
  594.  
  595.             ''' <summary>
  596.             ''' The type of device.
  597.             ''' </summary>
  598.             <MarshalAs(UnmanagedType.U4)>
  599.             Public DwType As InputDevice.NativeMethods.DeviceType
  600.  
  601.         End Structure
  602.  
  603.         ''' ----------------------------------------------------------------------------------------------------
  604.         ''' <summary>
  605.         ''' Contains the raw input from a device.
  606.         ''' </summary>
  607.         ''' ----------------------------------------------------------------------------------------------------
  608.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645562%28v=vs.85%29.aspx</remarks>
  609.         ''' ----------------------------------------------------------------------------------------------------
  610.         <StructLayout(LayoutKind.Explicit)>
  611.         Friend Structure Rawinput
  612.  
  613.             ''' <summary>
  614.             ''' The raw input data.
  615.             ''' </summary>
  616.             <FieldOffset(0)>
  617.             Public Header As RawInputHeader
  618.  
  619.             ''' <summary>
  620.             ''' If the data comes from a mouse, this is the raw input data.
  621.             ''' </summary>
  622.             <FieldOffset(16)>
  623.             Public Mouse As RawMouse
  624.  
  625.             ''' <summary>
  626.             ''' If the data comes from a keyboard, this is the raw input data.
  627.             ''' </summary>
  628.             <FieldOffset(16)>
  629.             Public Keyboard As RawKeyboard
  630.  
  631.             ''' <summary>
  632.             ''' If the data comes from an HID, this is the raw input data.
  633.             ''' </summary>
  634.             <FieldOffset(16)>
  635.             Public Hid As RawHid
  636.  
  637.         End Structure
  638.  
  639.         ''' ----------------------------------------------------------------------------------------------------
  640.         ''' <summary>
  641.         ''' Contains the header information that is part of the raw input data.
  642.         ''' </summary>
  643.         ''' ----------------------------------------------------------------------------------------------------
  644.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645571%28v=vs.85%29.aspx</remarks>
  645.         ''' ----------------------------------------------------------------------------------------------------
  646.         <StructLayout(LayoutKind.Sequential)>
  647.         Friend Structure RawInputHeader
  648.  
  649.             ''' <summary>
  650.             ''' The type of raw input.
  651.             ''' </summary>
  652.             <MarshalAs(UnmanagedType.U4)>
  653.             Public DwType As InputDevice.NativeMethods.DeviceType
  654.  
  655.             ''' <summary>
  656.             ''' The size, in bytes, of the entire input packet of data.
  657.             ''' This includes RAWINPUT plus possible extra input reports in the RAWHID variable length array.
  658.             ''' </summary>
  659.             <MarshalAs(UnmanagedType.U4)>
  660.             Public DwSize As Integer
  661.  
  662.             ''' <summary>
  663.             ''' A handle to the device generating the raw input data.
  664.             ''' </summary>
  665.             Public HDevice As IntPtr
  666.  
  667.             ''' <summary>
  668.             ''' The value passed in the wParam parameter of the WM_INPUT message.
  669.             ''' </summary>
  670.             <MarshalAs(UnmanagedType.U4)>
  671.             Public WParam As Integer
  672.  
  673.         End Structure
  674.  
  675.         ''' ----------------------------------------------------------------------------------------------------
  676.         ''' <summary>
  677.         ''' Describes the format of the raw input from a Human Interface Device (HID).
  678.         ''' </summary>
  679.         ''' ----------------------------------------------------------------------------------------------------
  680.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645549%28v=vs.85%29.aspx</remarks>
  681.         ''' ----------------------------------------------------------------------------------------------------
  682.         <StructLayout(LayoutKind.Sequential)>
  683.         Friend Structure RawHid
  684.  
  685.             ''' <summary>
  686.             ''' The size, in bytes, of each HID input in bRawData.
  687.             ''' </summary>
  688.             <MarshalAs(UnmanagedType.U4)>
  689.             Public DwSizHid As Integer
  690.  
  691.             ''' <summary>
  692.             ''' The number of HID inputs in bRawData.
  693.             ''' </summary>
  694.             <MarshalAs(UnmanagedType.U4)>
  695.             Public DwCount As Integer
  696.  
  697.         End Structure
  698.  
  699.         ''' ----------------------------------------------------------------------------------------------------
  700.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645578%28v=vs.85%29.aspx</remarks>
  701.         ''' ----------------------------------------------------------------------------------------------------
  702.         <StructLayout(LayoutKind.Sequential)>
  703.         Friend Structure ButtonsStr
  704.  
  705.             ''' <summary>
  706.             ''' The transition state of the mouse buttons.
  707.             ''' </summary>
  708.             <MarshalAs(UnmanagedType.U2)>
  709.             Public UsButtonFlags As UShort
  710.  
  711.             ''' <summary>
  712.             ''' If <paramref name="ButtonsStr"></paramref> is RI_MOUSE_WHEEL, this member is a signed value that specifies the wheel delta.
  713.             ''' </summary>
  714.             <MarshalAs(UnmanagedType.U2)>
  715.             Public UsButtonData As UShort
  716.  
  717.         End Structure
  718.  
  719.         ''' ----------------------------------------------------------------------------------------------------
  720.         ''' <summary>
  721.         ''' Contains information about the state of the mouse.
  722.         ''' </summary>
  723.         ''' ----------------------------------------------------------------------------------------------------
  724.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645578%28v=vs.85%29.aspx</remarks>
  725.         ''' ----------------------------------------------------------------------------------------------------
  726.         <StructLayout(LayoutKind.Explicit)>
  727.         Friend Structure RawMouse
  728.  
  729.             ''' <summary>
  730.             ''' The mouse state.
  731.             ''' </summary>
  732.             <MarshalAs(UnmanagedType.U2)>
  733.             <FieldOffset(0)>
  734.             Public UsFlags As UShort
  735.  
  736.             ''' <summary>
  737.             ''' Reserved parameter by the system.
  738.             ''' </summary>
  739.             <MarshalAs(UnmanagedType.U4)>
  740.             <FieldOffset(4)>
  741.             Public UlButtons As UInteger
  742.  
  743.             ''' <summary>
  744.             ''' The transition state of the mouse buttons.
  745.             ''' </summary>
  746.             <FieldOffset(4)>
  747.             Public ButtonsStr As InputDevice.NativeMethods.ButtonsStr ' usButtonFlags + usButtonData
  748.  
  749.             ''' <summary>
  750.             ''' The raw state of the mouse buttons.
  751.             ''' </summary>
  752.             <MarshalAs(UnmanagedType.U4)>
  753.             <FieldOffset(8)>
  754.             Public UlRawButtons As UInteger
  755.  
  756.             ''' <summary>
  757.             ''' The motion in the X direction.
  758.             ''' This is signed relative motion or absolute motion, depending on the value of <paramref name="usFlags"></paramref>.
  759.             ''' </summary>
  760.             <FieldOffset(12)>
  761.             Public LLastX As Integer
  762.  
  763.             ''' <summary>
  764.             ''' The motion in the Y direction.
  765.             ''' This is signed relative motion or absolute motion, depending on the value of <paramref name="usFlags"></paramref>.
  766.             ''' </summary>
  767.             <FieldOffset(16)>
  768.             Public LLastY As Integer
  769.  
  770.             ''' <summary>
  771.             ''' The device-specific additional information for the event.
  772.             ''' </summary>
  773.             <MarshalAs(UnmanagedType.U4)>
  774.             <FieldOffset(20)>
  775.             Public UlExtraInformation As UInteger
  776.  
  777.         End Structure
  778.  
  779.         ''' ----------------------------------------------------------------------------------------------------
  780.         ''' <summary>
  781.         ''' Contains information about the state of the keyboard.
  782.         ''' </summary>
  783.         ''' ----------------------------------------------------------------------------------------------------
  784.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645575%28v=vs.85%29.aspx</remarks>
  785.         ''' ----------------------------------------------------------------------------------------------------
  786.         <StructLayout(LayoutKind.Sequential)>
  787.         Friend Structure RawKeyboard
  788.  
  789.             ''' <summary>
  790.             ''' The scan code from the key depression.
  791.             ''' The scan code for keyboard overrun is KEYBOARD_OVERRUN_MAKE_CODE.
  792.             ''' </summary>
  793.             <MarshalAs(UnmanagedType.U2)>
  794.             Public MakeCode As UShort
  795.  
  796.             ''' <summary>
  797.             ''' Flags for scan code information.
  798.             ''' </summary>
  799.             <MarshalAs(UnmanagedType.U2)>
  800.             Public Flags As UShort
  801.  
  802.             ''' <summary>
  803.             ''' Reserved; value must be zero.
  804.             ''' </summary>
  805.             <MarshalAs(UnmanagedType.U2)>
  806.             Public Reserved As UShort
  807.  
  808.             ''' <summary>
  809.             ''' Windows message compatible virtual-key code.
  810.             ''' For more information, see Virtual Key Codes: https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx
  811.             ''' </summary>
  812.             <MarshalAs(UnmanagedType.U2)>
  813.             Public VKey As UShort
  814.  
  815.             ''' <summary>
  816.             ''' The corresponding window message, for example WM_KEYDOWN, WM_SYSKEYDOWN, and so forth.
  817.             ''' </summary>
  818.             <MarshalAs(UnmanagedType.U4)>
  819.             Public Message As UInteger
  820.  
  821.             ''' <summary>
  822.             ''' The device-specific additional information for the event.
  823.             ''' </summary>
  824.             <MarshalAs(UnmanagedType.U4)>
  825.             Public ExtraInformation As UInteger
  826.  
  827.         End Structure
  828.  
  829.         ''' ----------------------------------------------------------------------------------------------------
  830.         ''' <summary>
  831.         ''' Defines information for the raw input devices.
  832.         ''' </summary>
  833.         ''' ----------------------------------------------------------------------------------------------------
  834.         ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms645565%28v=vs.85%29.aspx</remarks>
  835.         ''' ----------------------------------------------------------------------------------------------------
  836.         <StructLayout(LayoutKind.Sequential)>
  837.         Friend Structure RawInputDevice
  838.  
  839.             ''' <summary>
  840.             ''' Top level collection Usage page for the raw input device.
  841.             ''' </summary>
  842.             <MarshalAs(UnmanagedType.U2)>
  843.             Public UsUsagePage As UShort
  844.  
  845.             ''' <summary>
  846.             ''' Top level collection Usage for the raw input device.
  847.             ''' </summary>
  848.             <MarshalAs(UnmanagedType.U2)>
  849.             Public UsUsage As UShort
  850.  
  851.             ''' <summary>
  852.             ''' Mode flag that specifies how to interpret the information provided by
  853.             ''' <see cref="InputDevice.NativeMethods.RawInputDevice.UsUsagePage"></see> and
  854.             ''' <see cref="InputDevice.NativeMethods.RawInputDevice.UsUsage"></see>.
  855.             ''' It can be zero (the default) or one of the following values.
  856.             ''' By default, the operating system sends raw input from devices with the specified top level collection (TLC) to the
  857.             ''' registered application as long as it has the window focus.
  858.             ''' </summary>
  859.             <MarshalAs(UnmanagedType.U4)>
  860.             Public DwFlags As InputDevice.NativeMethods.RawInputDeviceFlags
  861.  
  862.             ''' <summary>
  863.             ''' A handle to the target window.
  864.             ''' If this value is <see cref="IntPtr.Zero"></see>, it follows the keyboard focus.
  865.             ''' </summary>
  866.             Public HwndTarget As IntPtr
  867.  
  868.         End Structure
  869.  
  870. #End Region
  871.  
  872. #Region " Constants "
  873.  
  874.         ''' ----------------------------------------------------------------------------------------------------
  875.         ''' <summary>
  876.         '''
  877.         ''' </summary>
  878.         ''' ----------------------------------------------------------------------------------------------------
  879.         ''' <remarks></remarks>
  880.         ''' ----------------------------------------------------------------------------------------------------
  881.         Friend Const FAPPCOMMAND_MASK As Integer = &HF000
  882.  
  883.         ''' ----------------------------------------------------------------------------------------------------
  884.         ''' <summary>
  885.         ''' The last Virtual-Key Code.
  886.         ''' </summary>
  887.         ''' ----------------------------------------------------------------------------------------------------
  888.         ''' <remarks>https://msdn.microsoft.com/es-es/library/windows/desktop/dd375731%28v=vs.85%29.aspx</remarks>
  889.         ''' ----------------------------------------------------------------------------------------------------
  890.         Friend Const VKLastKey As Integer = &HFE ' VK_OEM_CLEAR
  891.  
  892. #End Region
  893.  
  894.     End Class
  895.  
  896. #End Region
  897.  
  898. #Region " Properties "
  899.  
  900.     ''' ----------------------------------------------------------------------------------------------------
  901.     ''' <summary>
  902.     ''' Gets the amount of keyboard devices.
  903.     ''' </summary>
  904.     ''' ----------------------------------------------------------------------------------------------------
  905.     ''' <value>
  906.     ''' The amount of keyboard devices.
  907.     ''' </value>
  908.     ''' ----------------------------------------------------------------------------------------------------
  909.     Public ReadOnly Property DeviceCount As Integer
  910.         Get
  911.             Return Me.deviceCountB
  912.         End Get
  913.     End Property
  914.     ''' <summary>
  915.     ''' ( Backing Field )
  916.     ''' The amount of keyboard devices.
  917.     ''' </summary>
  918.     Private deviceCountB As Integer
  919.  
  920.     ''' ----------------------------------------------------------------------------------------------------
  921.     ''' <summary>
  922.     ''' Gets or sets the keyboard language.
  923.     ''' </summary>
  924.     ''' ----------------------------------------------------------------------------------------------------
  925.     ''' <value>
  926.     ''' The keyboard language.
  927.     ''' </value>
  928.     ''' ----------------------------------------------------------------------------------------------------
  929.     Public Property Language As String
  930.         Get
  931.             Return Me.languageB
  932.         End Get
  933.         Set(ByVal value As String)
  934.             Me.languageB = value
  935.             Me.CurrentCulture = New CultureInfo(name:=value)
  936.         End Set
  937.     End Property
  938.     ''' <summary>
  939.     ''' ( Backing Field )
  940.     ''' The keyboard language.
  941.     ''' </summary>
  942.     Private languageB As String = InputLanguage.DefaultInputLanguage.Culture.Name
  943.  
  944.     ''' ----------------------------------------------------------------------------------------------------
  945.     ''' <summary>
  946.     ''' Gets or sets the keyboard culture.
  947.     ''' </summary>
  948.     ''' ----------------------------------------------------------------------------------------------------
  949.     ''' <value>
  950.     ''' The keyboard culture.
  951.     ''' </value>
  952.     ''' ----------------------------------------------------------------------------------------------------
  953.     Private Property CurrentCulture As New CultureInfo(name:=languageB)
  954.  
  955.     ''' ----------------------------------------------------------------------------------------------------
  956.     ''' <summary>
  957.     ''' Gets the keyboard layout Identifier.
  958.     ''' </summary>
  959.     ''' ----------------------------------------------------------------------------------------------------
  960.     ''' <value>
  961.     ''' The keyboard layout Identifier.
  962.     ''' </value>
  963.     ''' ----------------------------------------------------------------------------------------------------
  964.     Public ReadOnly Property KeyboardLayoutID As Integer
  965.         Get
  966.             Return Me.CurrentCulture.KeyboardLayoutId
  967.         End Get
  968.     End Property
  969.  
  970.     ''' ----------------------------------------------------------------------------------------------------
  971.     ''' <summary>
  972.     ''' Gets the keyboard layout handle (HKL).
  973.     ''' </summary>
  974.     ''' ----------------------------------------------------------------------------------------------------
  975.     ''' <value>
  976.     ''' The keyboard layout handle (HKL).
  977.     ''' </value>
  978.     ''' ----------------------------------------------------------------------------------------------------
  979.     Public ReadOnly Property KeyboardLayoutHandle As IntPtr
  980.         Get
  981.             Return InputLanguage.FromCulture(Me.CurrentCulture).Handle
  982.         End Get
  983.     End Property
  984.  
  985.     ''' ----------------------------------------------------------------------------------------------------
  986.     ''' <summary>
  987.     ''' Gets or sets a collection of <see cref="Keys"></see> to ignore from raising the <see cref="InputDevice.KeyPressed"></see> event.
  988.     ''' </summary>
  989.     ''' ----------------------------------------------------------------------------------------------------
  990.     ''' <value>
  991.     ''' The collection of <see cref="Keys"></see> to ignore.
  992.     ''' </value>
  993.     ''' ----------------------------------------------------------------------------------------------------
  994.     Public Property IgnoredKeys As IEnumerable(Of Keys) = {}
  995.  
  996.     ''' ----------------------------------------------------------------------------------------------------
  997.     ''' <summary>
  998.     ''' Gets or sets a collection of <see cref="Char"></see> to ignore from raising the <see cref="InputDevice.KeyPressed"></see> event.
  999.     ''' </summary>
  1000.     ''' ----------------------------------------------------------------------------------------------------
  1001.     ''' <value>
  1002.     ''' The collection of <see cref="Char"></see> to ignore.
  1003.     ''' </value>
  1004.     ''' ----------------------------------------------------------------------------------------------------
  1005.     Public Property IgnoredChars As IEnumerable(Of Char) = {}
  1006.  
  1007.     ''' ----------------------------------------------------------------------------------------------------
  1008.     ''' <summary>
  1009.     ''' Gets or sets the comparison behavior for <see cref="InputDevice.IgnoredChars"></see>.
  1010.     ''' </summary>
  1011.     ''' ----------------------------------------------------------------------------------------------------
  1012.     ''' <value>
  1013.     ''' The comparison behavior for <see cref="InputDevice.IgnoredChars"></see>.
  1014.     ''' </value>
  1015.     ''' ----------------------------------------------------------------------------------------------------
  1016.     Public Property IgnoredCharsComparer As IEqualityComparer(Of Char) = EqualityComparer(Of Char).Default
  1017.  
  1018.     ''' ----------------------------------------------------------------------------------------------------
  1019.     ''' <summary>
  1020.     ''' Gets or sets a collection of <see cref="String"></see> to ignore from raising the <see cref="InputDevice.KeyPressed"></see> event.
  1021.     ''' </summary>
  1022.     ''' ----------------------------------------------------------------------------------------------------
  1023.     ''' <value>
  1024.     ''' The collection of <see cref="String"></see> to ignore.
  1025.     ''' </value>
  1026.     ''' ----------------------------------------------------------------------------------------------------
  1027.     Public Property IgnoredStrings As IEnumerable(Of String) = {}
  1028.  
  1029.     ''' ----------------------------------------------------------------------------------------------------
  1030.     ''' <summary>
  1031.     ''' Gets or sets the comparison behavior for <see cref="InputDevice.IgnoredStrings"></see>.
  1032.     ''' </summary>
  1033.     ''' ----------------------------------------------------------------------------------------------------
  1034.     ''' <value>
  1035.     ''' The comparison behavior for <see cref="InputDevice.IgnoredStrings"></see>.
  1036.     ''' </value>
  1037.     ''' ----------------------------------------------------------------------------------------------------
  1038.     Public Property IgnoredStringsComparer As IEqualityComparer(Of String) = StringComparer.OrdinalIgnoreCase
  1039.  
  1040.     ''' ----------------------------------------------------------------------------------------------------
  1041.     ''' <summary>
  1042.     ''' Gets or sets a value that determines whether a paste operation (Ctrl+V) should be handled.
  1043.     ''' </summary>
  1044.     ''' ----------------------------------------------------------------------------------------------------
  1045.     ''' <value>
  1046.     ''' A value that determines whether a paste operation (Ctrl+V) should be handled.
  1047.     ''' </value>
  1048.     ''' ----------------------------------------------------------------------------------------------------
  1049.     Public Property HandlePastes As Boolean = False
  1050.  
  1051. #End Region
  1052.  
  1053. #Region " Variables "
  1054.  
  1055.     ''' ----------------------------------------------------------------------------------------------------
  1056.     ''' <summary>
  1057.     ''' The form to override its Windows Messages.
  1058.     ''' </summary>
  1059.     ''' ----------------------------------------------------------------------------------------------------
  1060.     Private WithEvents form As Form
  1061.  
  1062.     ''' ----------------------------------------------------------------------------------------------------
  1063.     ''' <summary>
  1064.     ''' List of devices.
  1065.     ''' Key: An <see cref="IntPtr"></see> that points to the device handle.
  1066.     ''' Value: The associated <see cref="InputDevice.DeviceInfo"></see> class.
  1067.     ''' </summary>
  1068.     ''' ----------------------------------------------------------------------------------------------------
  1069.     Private deviceList As New Hashtable
  1070.  
  1071. #End Region
  1072.  
  1073. #Region " Enumerations "
  1074.  
  1075.     ''' ----------------------------------------------------------------------------------------------------
  1076.     ''' <summary>
  1077.     ''' Specifies a type of input device event.
  1078.     ''' </summary>
  1079.     ''' ----------------------------------------------------------------------------------------------------
  1080.     Public Enum DeviceEvent As Integer
  1081.  
  1082.         ''' <summary>
  1083.         ''' A key is pressed.
  1084.         ''' </summary>
  1085.         Key = 0
  1086.  
  1087.         ''' <summary>
  1088.         ''' A mouse button is click.
  1089.         ''' </summary>
  1090.         Mouse = 1
  1091.  
  1092.         ''' <summary>
  1093.         ''' An unidentified hardware source generated the event.
  1094.         ''' It could be a mouse or a keyboard event.
  1095.         ''' </summary>
  1096.         Oem = 2
  1097.  
  1098.     End Enum
  1099.  
  1100.     ''' ----------------------------------------------------------------------------------------------------
  1101.     ''' <summary>
  1102.     '''
  1103.     ''' </summary>
  1104.     ''' ----------------------------------------------------------------------------------------------------
  1105.     ''' <remarks>https://msdn.microsoft.com/en-us/library/windows/desktop/ms646248%28v=vs.85%29.aspx</remarks>
  1106.     ''' ----------------------------------------------------------------------------------------------------
  1107.     Private Enum GetDeviceLparam As Integer
  1108.  
  1109.         ''' <summary>
  1110.         ''' User pressed a key.
  1111.         ''' </summary>
  1112.         Key = &H0
  1113.  
  1114.         ''' <summary>
  1115.         ''' User clicked a mouse button.
  1116.         ''' </summary>
  1117.         Mouse = &H8000
  1118.  
  1119.         ''' <summary>
  1120.         ''' An unidentified hardware source generated the event.
  1121.         ''' It could be a mouse or a keyboard event.
  1122.         ''' </summary>
  1123.         Oem = &H1000
  1124.  
  1125.     End Enum
  1126.  
  1127. #End Region
  1128.  
  1129. #Region " Types "
  1130.  
  1131.     ''' <summary>
  1132.     ''' Encapsulates the information about a keyboard event, including the device it originated with and what key was pressed.
  1133.     ''' </summary>
  1134.     <Serializable>
  1135.     Public NotInheritable Class DeviceInfo
  1136.  
  1137. #Region " Properties "
  1138.  
  1139.         ''' <summary>
  1140.         ''' Gets or sets the device name.
  1141.         ''' </summary>
  1142.         ''' <value>The device name.</value>
  1143.         Public Property DeviceName As String
  1144.  
  1145.         ''' <summary>
  1146.         ''' Gets or sets the device type.
  1147.         ''' </summary>
  1148.         ''' <value>The device type.</value>
  1149.         Public Property DeviceType As String
  1150.  
  1151.         ''' <summary>
  1152.         ''' Gets or sets the device handle.
  1153.         ''' </summary>
  1154.         ''' <value>The device handle.</value>
  1155.         Public Property DeviceHandle As IntPtr
  1156.  
  1157.         ''' <summary>
  1158.         ''' Gets or sets the device description.
  1159.         ''' </summary>
  1160.         ''' <value>The device description.</value>
  1161.         Public Property DeviceDescription As String
  1162.  
  1163.         ''' <summary>
  1164.         ''' Gets or sets the source.
  1165.         ''' </summary>
  1166.         ''' <value>The source.</value>
  1167.         Public Property Source As String
  1168.  
  1169.         ''' <summary>
  1170.         ''' Gets or sets the key number.
  1171.         ''' </summary>
  1172.         ''' <value>The key.</value>
  1173.         Public Property KeyNum As UShort
  1174.  
  1175.         ''' <summary>
  1176.         ''' Gets or sets the key.
  1177.         ''' </summary>
  1178.         ''' <value>The key.</value>
  1179.         Public Property Key As Keys
  1180.  
  1181.         ''' <summary>
  1182.         ''' Gets or sets the characters.
  1183.         ''' </summary>
  1184.         ''' <value>The characters.</value>
  1185.         Public Property Chars As String
  1186.  
  1187. #End Region
  1188.  
  1189.     End Class
  1190.  
  1191. #End Region
  1192.  
  1193. #Region " Events "
  1194.  
  1195.     ''' ----------------------------------------------------------------------------------------------------
  1196.     ''' <summary>
  1197.     ''' This event is raised when a key was pressed.
  1198.     ''' </summary>
  1199.     ''' ----------------------------------------------------------------------------------------------------
  1200.     Public Event KeyPressed As EventHandler(Of KeyPressedEventArgs)
  1201.  
  1202.     ''' ----------------------------------------------------------------------------------------------------
  1203.     ''' <summary>
  1204.     ''' This event is raised when a paste hotkey was pressed (Ctrl+V).
  1205.     ''' </summary>
  1206.     ''' ----------------------------------------------------------------------------------------------------
  1207.     Public Event HotkeyPastePressed As EventHandler(Of HotkeyPastePressedEventArgs)
  1208.  
  1209. #End Region
  1210.  
  1211. #Region " Event Aarguments "
  1212.  
  1213. #Region " KeyPressedEventArgs "
  1214.  
  1215.     ''' ----------------------------------------------------------------------------------------------------
  1216.     ''' <summary>
  1217.     ''' Arguments provided by the handler for the <see cref="InputDevice.KeyPressed"></see> event.
  1218.     ''' </summary>
  1219.     ''' ----------------------------------------------------------------------------------------------------
  1220.     Public NotInheritable Class KeyPressedEventArgs : Inherits EventArgs
  1221.  
  1222. #Region " Properties "
  1223.  
  1224.         ''' <summary>
  1225.         ''' Gets the device info.
  1226.         ''' </summary>
  1227.         ''' <value>The device info.</value>
  1228.         Public ReadOnly Property DeviceInfo() As DeviceInfo
  1229.             Get
  1230.                 Return Me.deviceInfoB
  1231.             End Get
  1232.         End Property
  1233.         ''' <summary>
  1234.         ''' ( Backing Field )
  1235.         ''' The device info.
  1236.         ''' </summary>
  1237.         Private ReadOnly deviceInfoB As DeviceInfo
  1238.  
  1239.         ''' <summary>
  1240.         ''' Gets the device event.
  1241.         ''' </summary>
  1242.         ''' <value>The device event.</value>
  1243.         Public ReadOnly Property DeviceEvent() As DeviceEvent
  1244.             Get
  1245.                 Return Me.deviceEventB
  1246.             End Get
  1247.         End Property
  1248.         ''' <summary>
  1249.         ''' ( Backing Field )
  1250.         ''' The device event.
  1251.         ''' </summary>
  1252.         Private ReadOnly deviceEventB As DeviceEvent
  1253.  
  1254. #End Region
  1255.  
  1256. #Region " Constructors "
  1257.  
  1258.         ''' ----------------------------------------------------------------------------------------------------
  1259.         ''' <summary>
  1260.         ''' Initializes a new instance of the <see cref="KeyPressedEventArgs"/> class.
  1261.         ''' </summary>
  1262.         ''' ----------------------------------------------------------------------------------------------------
  1263.         Public Sub New()
  1264.         End Sub
  1265.  
  1266.         ''' ----------------------------------------------------------------------------------------------------
  1267.         ''' <summary>
  1268.         ''' Initializes a new instance of the <see cref="KeyPressedEventArgs"/> class.
  1269.         ''' </summary>
  1270.         ''' ----------------------------------------------------------------------------------------------------
  1271.         ''' <param name="deviceInfo">
  1272.         ''' The device data.
  1273.         ''' </param>
  1274.         '''
  1275.         ''' <param name="deviceEvent">
  1276.         ''' The device event.
  1277.         ''' </param>
  1278.         ''' ----------------------------------------------------------------------------------------------------
  1279.         Public Sub New(ByVal deviceInfo As DeviceInfo,
  1280.                        ByVal deviceEvent As DeviceEvent)
  1281.  
  1282.             Me.deviceInfoB = deviceInfo
  1283.             Me.deviceEventB = deviceEvent
  1284.  
  1285.         End Sub
  1286.  
  1287. #End Region
  1288.  
  1289.     End Class
  1290.  
  1291. #End Region
  1292.  
  1293.  
  1294. #Region " KeyPressedEventArgs "
  1295.  
  1296.     ''' ----------------------------------------------------------------------------------------------------
  1297.     ''' <summary>
  1298.     ''' Arguments provided by the handler for the <see cref="InputDevice.HotkeyPastePressedEventArgs"></see> event.
  1299.     ''' </summary>
  1300.     ''' ----------------------------------------------------------------------------------------------------
  1301.     Public NotInheritable Class HotkeyPastePressedEventArgs : Inherits EventArgs
  1302.  
  1303. #Region " Properties "
  1304.  
  1305.         ''' <summary>
  1306.         ''' Gets the device info.
  1307.         ''' </summary>
  1308.         ''' <value>The device info.</value>
  1309.         Public ReadOnly Property DeviceInfo() As DeviceInfo
  1310.             Get
  1311.                 Return Me.deviceInfoB
  1312.             End Get
  1313.         End Property
  1314.         ''' <summary>
  1315.         ''' ( Backing Field )
  1316.         ''' The device info.
  1317.         ''' </summary>
  1318.         Private ReadOnly deviceInfoB As DeviceInfo
  1319.  
  1320.         ''' <summary>
  1321.         ''' Gets the clipboard data.
  1322.         ''' </summary>
  1323.         ''' <value>The clipboard data.</value>
  1324.         Public ReadOnly Property ClipboardData() As String
  1325.             Get
  1326.                 Return Me.clipboardDatab
  1327.             End Get
  1328.         End Property
  1329.         ''' <summary>
  1330.         ''' ( Backing Field )
  1331.         ''' The clipboard data.
  1332.         ''' </summary>
  1333.         Private ReadOnly clipboardDatab As String
  1334.  
  1335. #End Region
  1336.  
  1337. #Region " Constructors "
  1338.  
  1339.         ''' ----------------------------------------------------------------------------------------------------
  1340.         ''' <summary>
  1341.         ''' Initializes a new instance of the <see cref="HotkeyPastePressedEventArgs"/> class.
  1342.         ''' </summary>
  1343.         ''' ----------------------------------------------------------------------------------------------------
  1344.         Public Sub New()
  1345.         End Sub
  1346.  
  1347.         ''' ----------------------------------------------------------------------------------------------------
  1348.         ''' <summary>
  1349.         ''' Initializes a new instance of the <see cref="HotkeyPastePressedEventArgs"/> class.
  1350.         ''' </summary>
  1351.         ''' ----------------------------------------------------------------------------------------------------
  1352.         ''' <param name="deviceInfo">
  1353.         ''' The device data.
  1354.         ''' </param>
  1355.         '''
  1356.         ''' <param name="clipboardData">
  1357.         ''' The clipboard data.
  1358.         ''' </param>
  1359.         ''' ----------------------------------------------------------------------------------------------------
  1360.         Public Sub New(ByVal deviceInfo As DeviceInfo,
  1361.                        ByVal clipboardData As String)
  1362.  
  1363.             Me.deviceInfoB = deviceInfo
  1364.             Me.clipboardDatab = clipboardData
  1365.  
  1366.         End Sub
  1367.  
  1368. #End Region
  1369.  
  1370.     End Class
  1371.  
  1372. #End Region
  1373.  
  1374. #End Region
  1375.  
  1376. #Region " Constructors "
  1377.  
  1378.     ''' ----------------------------------------------------------------------------------------------------
  1379.     ''' <summary>
  1380.     ''' InputDevice constructor; registers the raw input devices
  1381.     ''' for the calling window.
  1382.     ''' </summary>
  1383.     ''' ----------------------------------------------------------------------------------------------------
  1384.     ''' <param name="hwnd">
  1385.     ''' A handle to the window that will listen for device events.
  1386.     ''' </param>
  1387.     ''' ----------------------------------------------------------------------------------------------------
  1388.     <DebuggerStepThrough>
  1389.     Public Sub New(ByVal hwnd As IntPtr)
  1390.  
  1391.         Me.form = DirectCast(Control.FromHandle(hwnd), Form)
  1392.  
  1393.         ' Create an array of all the raw input devices we want to listen to.
  1394.         ' In this case, only keyboard devices.
  1395.         Dim rid As InputDevice.NativeMethods.RawInputDevice() =
  1396.             New InputDevice.NativeMethods.RawInputDevice(0) {}
  1397.  
  1398.         With rid(0)
  1399.             .UsUsagePage = 1US
  1400.             .UsUsage = 6US
  1401.             .HwndTarget = hwnd
  1402.             .DwFlags = NativeMethods.RawInputDeviceFlags.InputSink Or
  1403.                        NativeMethods.RawInputDeviceFlags.NoHotkeys
  1404.         End With
  1405.  
  1406.         If Not InputDevice.NativeMethods.RegisterRawInputDevices(rid, CUInt(rid.Length), CUInt(Marshal.SizeOf(rid(0)))) Then
  1407.             Throw New ApplicationException("Failed to register raw input device(s).")
  1408.         End If
  1409.  
  1410.         Me.deviceCountB = Me.EnumerateDevices()
  1411.  
  1412.     End Sub
  1413.  
  1414.     ''' <summary>
  1415.     ''' Prevents a default instance of the <see cref="InputDevice"/> class from being created.
  1416.     ''' </summary>
  1417.     Private Sub New()
  1418.     End Sub
  1419.  
  1420. #End Region
  1421.  
  1422. #Region " Private Methods "
  1423.  
  1424.     ''' ----------------------------------------------------------------------------------------------------
  1425.     ''' <summary>
  1426.     ''' Determines what type of device triggered a WM_INPUT message.
  1427.     ''' (Used in the ProcessInputCommand method).
  1428.     ''' </summary>
  1429.     ''' ----------------------------------------------------------------------------------------------------
  1430.     ''' <param name="lParam">
  1431.     ''' The LParam from a WM_INPUT message.
  1432.     ''' </param>
  1433.     ''' ----------------------------------------------------------------------------------------------------
  1434.     ''' <returns>
  1435.     ''' A <see cref="InputDevice.DeviceEvent"></see> Enum value.
  1436.     ''' </returns>
  1437.     ''' ----------------------------------------------------------------------------------------------------
  1438.     ''' <exception cref="NotImplementedException">
  1439.     ''' Unrecognized GetDeviceLparam Enum value
  1440.     ''' </exception>
  1441.     ''' ----------------------------------------------------------------------------------------------------
  1442.     Private Function GetDevice(ByVal lParam As Integer) As DeviceEvent
  1443.  
  1444.         Select Case DirectCast(lParam >> 16 And InputDevice.NativeMethods.FAPPCOMMAND_MASK, GetDeviceLparam)
  1445.  
  1446.             Case GetDeviceLparam.Key
  1447.                 Return DeviceEvent.Key
  1448.  
  1449.             Case GetDeviceLparam.Mouse
  1450.                 Return DeviceEvent.Mouse
  1451.  
  1452.             Case GetDeviceLparam.Oem
  1453.                 Return DeviceEvent.Oem
  1454.  
  1455.             Case Else
  1456.                 Return DeviceEvent.Key
  1457.                 ' Throw New NotImplementedException(message:="Unrecognized GetDeviceLparam Enum value.")
  1458.  
  1459.         End Select
  1460.  
  1461.     End Function
  1462.  
  1463.     ''' ----------------------------------------------------------------------------------------------------
  1464.     ''' <summary>
  1465.     ''' Converts a <see cref="InputDevice.NativeMethods.RawInputDeviceList.DwType"></see> value to a string
  1466.     ''' describing the device type.
  1467.     ''' </summary>
  1468.     ''' ----------------------------------------------------------------------------------------------------
  1469.     ''' <param name="deviceType">
  1470.     ''' A <see cref="InputDevice.NativeMethods.RawInputDeviceList.DwType"></see> value.
  1471.     ''' </param>
  1472.     ''' ----------------------------------------------------------------------------------------------------
  1473.     ''' <returns>
  1474.     ''' A string representation of the input value.
  1475.     ''' </returns>
  1476.     ''' ----------------------------------------------------------------------------------------------------
  1477.     Private Function GetDeviceType(ByVal deviceType As InputDevice.NativeMethods.DeviceType) As String
  1478.  
  1479.         Select Case deviceType
  1480.  
  1481.             Case NativeMethods.DeviceType.Mouse
  1482.                 Return "MOUSE"
  1483.  
  1484.             Case NativeMethods.DeviceType.Keyboard
  1485.                 Return "KEYBOARD"
  1486.  
  1487.             Case NativeMethods.DeviceType.Hid
  1488.                 Return "HID"
  1489.  
  1490.             Case Else
  1491.                 Return "UNKNOWN"
  1492.  
  1493.         End Select
  1494.  
  1495.     End Function
  1496.  
  1497.     ''' ----------------------------------------------------------------------------------------------------
  1498.     ''' <summary>
  1499.     ''' Iterates through the list provided by <see cref="InputDevice.NativeMethods.GetRawInputDeviceList"></see>,
  1500.     ''' counting keyboard devices and adding them to <see cref="InputDevice.deviceList"></see>.
  1501.     ''' </summary>
  1502.     ''' ----------------------------------------------------------------------------------------------------
  1503.     ''' <returns>
  1504.     ''' The number of keyboard devices found.
  1505.     ''' </returns>
  1506.     ''' ----------------------------------------------------------------------------------------------------
  1507.     Private Function EnumerateDevices() As Integer
  1508.  
  1509.         Dim numberOfDevices As Integer
  1510.         Dim deviceCount As UInteger
  1511.         Dim dwSize As Integer = (Marshal.SizeOf(GetType(InputDevice.NativeMethods.RawInputDeviceList)))
  1512.  
  1513.         ' Get the number of raw input devices in the list, then allocate sufficient memory and get the entire list.
  1514.         If InputDevice.NativeMethods.GetRawInputDeviceList(IntPtr.Zero, deviceCount, CUInt(dwSize)) = 0 Then
  1515.  
  1516.             Dim pRawInputDeviceList As IntPtr = Marshal.AllocHGlobal(CInt(dwSize * deviceCount))
  1517.             InputDevice.NativeMethods.GetRawInputDeviceList(pRawInputDeviceList, deviceCount, CUInt(dwSize))
  1518.  
  1519.             ' Iterate through the list, discarding undesired items and retrieving further information on keyboard devices.
  1520.             For i As Integer = 0 To CInt(deviceCount - 1)
  1521.  
  1522.                 Dim dInfo As DeviceInfo
  1523.                 Dim deviceName As String
  1524.                 Dim pcbSize As UInteger = 0
  1525.  
  1526.                 Dim rid As InputDevice.NativeMethods.RawInputDeviceList =
  1527.                     CType(Marshal.PtrToStructure(New IntPtr((pRawInputDeviceList.ToInt32() + (dwSize * i))),
  1528.                                                  GetType(InputDevice.NativeMethods.RawInputDeviceList)), InputDevice.NativeMethods.RawInputDeviceList)
  1529.  
  1530.                 InputDevice.NativeMethods.GetRawInputDeviceInfo(rid.HDevice,
  1531.                                                                 NativeMethods.GetRawInputDeviceInfoCommand.DeviceName,
  1532.                                                                 IntPtr.Zero,
  1533.                                                                 pcbSize)
  1534.  
  1535.                 If pcbSize > 0 Then
  1536.  
  1537.                     Dim pData As IntPtr = Marshal.AllocHGlobal(CInt(pcbSize))
  1538.                     InputDevice.NativeMethods.GetRawInputDeviceInfo(rid.HDevice,
  1539.                                                                     NativeMethods.GetRawInputDeviceInfoCommand.DeviceName,
  1540.                                                                     pData,
  1541.                                                                     pcbSize)
  1542.                     deviceName = Marshal.PtrToStringAnsi(pData)
  1543.  
  1544.                     ' Drop the "root" keyboard and mouse devices used for 'Terminal Services' and the 'Remote Desktop'.
  1545.                     If deviceName.ToUpper().Contains("ROOT") Then
  1546.                         Continue For
  1547.                     End If
  1548.  
  1549.                     ' If the device is identified in the list as a keyboard or HID device,
  1550.                     ' create a DeviceInfo object to store information about it.
  1551.                     If (rid.DwType = NativeMethods.DeviceType.Keyboard) OrElse
  1552.                        (rid.DwType = NativeMethods.DeviceType.Hid) Then
  1553.  
  1554.                         dInfo = New DeviceInfo()
  1555.                         dInfo.DeviceName = Marshal.PtrToStringAnsi(pData)
  1556.                         dInfo.DeviceHandle = rid.HDevice
  1557.                         dInfo.DeviceType = GetDeviceType(rid.DwType)
  1558.  
  1559.                         ' Check the Registry to see whether this is actually a keyboard, and to retrieve a more friendly description.
  1560.                         Dim isKeyboardDevice As Boolean = False
  1561.                         Dim deviceDesc As String = Me.ReadRegistry(deviceName, isKeyboardDevice, dInfo.DeviceType)
  1562.                         dInfo.DeviceDescription = deviceDesc
  1563.  
  1564.                         ' If it is a keyboard and it isn't already in the list,
  1565.                         ' add it to the deviceList hashtable and increase the numberOfDevices count.
  1566.                         If Not deviceList.Contains(rid.HDevice) AndAlso isKeyboardDevice Then
  1567.                             numberOfDevices += 1
  1568.                             deviceList.Add(rid.HDevice, dInfo)
  1569.                         End If
  1570.  
  1571.                     End If
  1572.  
  1573.                     Marshal.FreeHGlobal(pData)
  1574.  
  1575.                 End If
  1576.  
  1577.             Next i
  1578.  
  1579.             Marshal.FreeHGlobal(pRawInputDeviceList)
  1580.  
  1581.             Return numberOfDevices
  1582.         Else
  1583.             Throw New ApplicationException("An error occurred while retrieving the list of devices.")
  1584.  
  1585.         End If
  1586.  
  1587.     End Function
  1588.  
  1589.     ''' ----------------------------------------------------------------------------------------------------
  1590.     ''' <summary>
  1591.     ''' Reads the Registry to retrieve a friendly description of the device, and determine whether it is a keyboard.
  1592.     ''' </summary>
  1593.     ''' ----------------------------------------------------------------------------------------------------
  1594.     ''' <param name="nameID">
  1595.     ''' The device name identifier to search for,
  1596.     ''' as provided by <see cref="InputDevice.NativeMethods.GetRawInputDeviceInfo"></see> function.
  1597.     ''' </param>
  1598.     '''
  1599.     ''' <param name="isKeyboard">
  1600.     ''' A reffered variable that determines whether the device's class is "Keyboard".
  1601.     ''' </param>
  1602.     '''
  1603.     ''' <param name="deviceType">
  1604.     ''' The device type.
  1605.     ''' </param>
  1606.     ''' ----------------------------------------------------------------------------------------------------
  1607.     ''' <returns>
  1608.     ''' The device description stored in the registry entry's DeviceDesc value.
  1609.     ''' </returns>
  1610.     ''' ----------------------------------------------------------------------------------------------------
  1611.     Private Function ReadRegistry(ByVal nameID As String,
  1612.                                   ByRef isKeyboard As Boolean,
  1613.                                   ByVal deviceType As String) As String
  1614.  
  1615.         ' Example Device Identification string:
  1616.         ' @"\??\ACPI#PNP0303#3&13c0b0c5&0#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}";
  1617.  
  1618.         ' Remove the '\??\'.
  1619.         Dim idSplit As IEnumerable(Of String) = nameID.Substring(4).Split("#"c)
  1620.  
  1621.         ' ACPI (Class code).
  1622.         Dim id01 As String = idSplit(0)
  1623.  
  1624.         ' PNP0303 (SubClass code).
  1625.         Dim id02 As String = idSplit(1)
  1626.  
  1627.         ' 3&13c0b0c5&0 (Protocol code).
  1628.         ' The final splitted part, idSplit(3), is the class GUID and is not needed here.
  1629.         Dim id03 As String = idSplit(2)
  1630.  
  1631.         Dim idSubkeyPath As String = String.Format("System\CurrentControlSet\Enum\{0}\{1}\{2}", id01, id02, id03)
  1632.  
  1633.         Using regKey As RegistryKey = Registry.LocalMachine.OpenSubKey(idSubkeyPath, writable:=False)
  1634.  
  1635.             'Retrieve the desired information.
  1636.             Dim deviceDesc As String = DirectCast(regKey.GetValue("DeviceDesc", defaultValue:="Nothing"), String)
  1637.             Dim deviceClass As String = DirectCast(regKey.GetValue("Class", defaultValue:="Nothing"), String)
  1638.  
  1639.             If deviceType.Equals("KEYBOARD", StringComparison.OrdinalIgnoreCase) OrElse
  1640.                deviceClass.Equals("KEYBOARD", StringComparison.OrdinalIgnoreCase) Then
  1641.  
  1642.                 isKeyboard = True
  1643.  
  1644.             Else
  1645.                 isKeyboard = False
  1646.  
  1647.             End If
  1648.  
  1649.             Return deviceDesc
  1650.  
  1651.         End Using
  1652.  
  1653.     End Function
  1654.  
  1655.     ''' ----------------------------------------------------------------------------------------------------
  1656.     ''' <summary>
  1657.     ''' Gets the characters from keys.
  1658.     ''' </summary>
  1659.     ''' ----------------------------------------------------------------------------------------------------
  1660.     ''' <param name="key">
  1661.     ''' The key.
  1662.     ''' </param>
  1663.     ''' <param name="shift">
  1664.     ''' The state of <see cref="Keys.ShiftKey"></see>, <c>True</c> if enabled.
  1665.     ''' </param>
  1666.     ''' <param name="altGr">
  1667.     ''' The state of <see cref="Keys.Menu"></see>, <c>True</c> if enabled.
  1668.     ''' </param>
  1669.     ''' ----------------------------------------------------------------------------------------------------
  1670.     ''' <returns>
  1671.     ''' The characters.
  1672.     ''' </returns>
  1673.     ''' ----------------------------------------------------------------------------------------------------
  1674.     Private Function GetCharsFromKeys(ByVal key As Keys,
  1675.                                       ByVal shift As Boolean,
  1676.                                       ByVal altGr As Boolean) As String
  1677.  
  1678.         Dim buf As New StringBuilder(256)
  1679.         Dim keyboardState As Byte() = New Byte(255) {}
  1680.  
  1681.         If shift Then
  1682.             keyboardState(CInt(Keys.ShiftKey)) = &HFF
  1683.         End If
  1684.  
  1685.         If altGr Then
  1686.             keyboardState(CInt(Keys.ControlKey)) = &HFF
  1687.             keyboardState(CInt(Keys.Menu)) = &HFF
  1688.         End If
  1689.  
  1690.         Dim rc As Integer
  1691.         rc = InputDevice.NativeMethods.ToUnicodeEx(CUInt(key), 0UI, keyboardState, buf, buf.Capacity, 0UI,
  1692.                                                    Me.KeyboardLayoutHandle)
  1693.  
  1694.         Select Case rc
  1695.  
  1696.             Case -1 ' Its a dead key, like for example "`´" accents or "^".
  1697.                 Return ""
  1698.  
  1699.             Case 0 ' Single character in buffer.
  1700.                 Return ""
  1701.  
  1702.             Case 1
  1703.                 Return buf(0).ToString()
  1704.  
  1705.             Case Else ' Two or more (only two of them are relevant).
  1706.                 Return buf.ToString().Substring(0, 2)
  1707.  
  1708.         End Select
  1709.  
  1710.     End Function
  1711.  
  1712.     ''' ----------------------------------------------------------------------------------------------------
  1713.     ''' <summary>
  1714.     ''' Processes WM_INPUT messages to retrieve information about any keyboard events that occur.
  1715.     ''' </summary>
  1716.     ''' ----------------------------------------------------------------------------------------------------
  1717.     ''' <param name="message">
  1718.     ''' The WM_INPUT message to process.
  1719.     ''' </param>
  1720.     ''' ----------------------------------------------------------------------------------------------------
  1721.     Private Sub ProcessInputCommand(ByVal message As Message)
  1722.  
  1723.         Dim dwSize As UInteger = 0
  1724.  
  1725.         ' First call to GetRawInputData sets the value of dwSize,
  1726.         ' which can then be used to allocate the appropriate amount of memory, storing the pointer in "buffer".
  1727.         InputDevice.NativeMethods.GetRawInputData(message.LParam,
  1728.                                                   NativeMethods.GetRawInputDataCommand.Input,
  1729.                                                   IntPtr.Zero,
  1730.                                                   dwSize,
  1731.                                                   CUInt(Marshal.SizeOf(GetType(InputDevice.NativeMethods.RawInputHeader))))
  1732.  
  1733.         Dim buffer As IntPtr = Marshal.AllocHGlobal(CInt(dwSize))
  1734.  
  1735.         Try
  1736.             ' Check that buffer points to something,
  1737.             ' and if so, call GetRawInputData again to fill the allocated memory with information about the input.
  1738.             If (buffer <> IntPtr.Zero) AndAlso
  1739.                (InputDevice.NativeMethods.GetRawInputData(message.LParam,
  1740.                                                           NativeMethods.GetRawInputDataCommand.Input,
  1741.                                                           buffer,
  1742.                                                           dwSize,
  1743.                                                           CUInt(Marshal.SizeOf(GetType(InputDevice.NativeMethods.RawInputHeader)))) = dwSize) Then
  1744.  
  1745.                 ' Store the message information in "raw",
  1746.                 ' then check that the input comes from a keyboard device before processing it to raise an appropriate KeyPressed event.
  1747.                 Dim raw As InputDevice.NativeMethods.Rawinput =
  1748.                     CType(Marshal.PtrToStructure(buffer, GetType(InputDevice.NativeMethods.Rawinput)), InputDevice.NativeMethods.Rawinput)
  1749.  
  1750.                 If raw.Header.DwType = NativeMethods.DeviceType.Keyboard Then
  1751.  
  1752.                     ' Filter for Key Down events and then retrieve informationabout the keystroke.
  1753.                     If (raw.Keyboard.Message = InputDevice.NativeMethods.WindowsMessages.WM_KEYDOWN) OrElse
  1754.                        (raw.Keyboard.Message = InputDevice.NativeMethods.WindowsMessages.WM_SYSKEYDOWN) Then
  1755.  
  1756.                         Dim key As UShort = raw.Keyboard.VKey
  1757.  
  1758.                         ' On most keyboards, "extended" keys such as the arrow or page keys return two codes:
  1759.                         ' 1: the key 's own code, and 2: a "extended key" flag, which translates to 255.
  1760.                         ' The flag isn't useful to us, so it can be disregarded.
  1761.                         If key > InputDevice.NativeMethods.VKLastKey Then
  1762.                             Return
  1763.                         End If
  1764.  
  1765.                         Dim isPaste As Boolean
  1766.  
  1767.                         Dim isShiftPress As Boolean = (InputDevice.NativeMethods.GetAsyncKeyState(Keys.ShiftKey) <> 0)
  1768.                         Dim isAltGrPress As Boolean = (InputDevice.NativeMethods.GetAsyncKeyState(Keys.Menu) <> 0)
  1769.                         Dim isCrtlPress As Boolean = (InputDevice.NativeMethods.GetAsyncKeyState(Keys.ControlKey) <> 0)
  1770.                         Dim isCapsLockPress As Boolean = Control.IsKeyLocked(Keys.CapsLock)
  1771.                         ' Dim isCapsLockPress As Boolean = ((CUShort(InputDevice.NativeMethods.GetKeyState(Keys.Capital)) And &HFFFF) <> 0)
  1772.  
  1773.                         ' Determines whether a key press on an alphabetic character should be translated to Upper-Case.
  1774.                         ' This is thinked to simulate these combinations:
  1775.                         '   · CapsLock Enabled  + Shift Enabled  = Lower Character
  1776.                         '   · CapsLock Enabled  + Shift Disabled = Upper Character
  1777.                         '   · CapsLock Disabled + Shift Disabled = Lower Character
  1778.                         '   · CapsLock Disabled + Shift Enabled  = Upper Character
  1779.                         Dim charToUpperCase As Boolean = (isCapsLockPress = True And isShiftPress = False) Or
  1780.                                                          (isCapsLockPress = False And isShiftPress = True)
  1781.  
  1782.                         ' Retrieve information about the device and the key that was pressed.
  1783.                         Dim dInfo As DeviceInfo = CType(deviceList(raw.Header.HDevice), DeviceInfo)
  1784.                         dInfo.KeyNum = key
  1785.                         dInfo.Key = CType([Enum].Parse(GetType(Keys), [Enum].GetName(GetType(Keys), key)), Keys)
  1786.                        
  1787.                         If (isCrtlPress) AndAlso (dInfo.Key = Keys.V) Then ' Paste hotkey (Ctrl+V).
  1788.                             isPaste = True
  1789.                         End If
  1790.  
  1791.                         dInfo.Chars = Me.GetCharsFromKeys(dInfo.Key, isShiftPress, isAltGrPress).ToLower
  1792.                         If charToUpperCase Then
  1793.                             dInfo.Chars = dInfo.Chars.ToUpper
  1794.                         End If
  1795.  
  1796.                         ' If the key that was pressed is valid and there was no problem retrieving information on the device,
  1797.                         ' raise the KeyPressed event.
  1798.                         If (Me.KeyPressedEvent IsNot Nothing) AndAlso (dInfo IsNot Nothing) Then
  1799.  
  1800.                             ' If is not an ignored key and also is not an ignored string then...
  1801.                             If (Not Me.IgnoredKeys.Contains(dInfo.Key)) AndAlso
  1802.                                (Not Me.IgnoredStrings.Any(Function(s As String) s.Equals(dInfo.Chars))) Then
  1803.  
  1804.                                 ' Remove ignored characters.
  1805.                                 Dim isEmpty As Boolean = String.IsNullOrEmpty(dInfo.Chars)
  1806.                                 dInfo.Chars = String.Join("", From c As Char In dInfo.Chars Where Not Me.IgnoredChars.Contains(c))
  1807.  
  1808.                                 ' If original string is empty (like when pressing a SHIFT key),
  1809.                                 ' Or else the string is not empty after removing ignored chars, then...
  1810.                                 If isEmpty OrElse (Not String.IsNullOrEmpty(dInfo.Chars)) Then
  1811.  
  1812.                                     If (Me.HandlePastes) AndAlso (HotkeyPastePressedEvent IsNot Nothing) AndAlso (isPaste) Then
  1813.                                         RaiseEvent HotkeyPastePressed(Me, New HotkeyPastePressedEventArgs(dInfo, Clipboard.GetText))
  1814.  
  1815.                                     Else
  1816.                                         RaiseEvent KeyPressed(Me, New KeyPressedEventArgs(dInfo, Me.GetDevice(message.LParam.ToInt32())))
  1817.  
  1818.                                     End If
  1819.  
  1820.                                 End If
  1821.  
  1822.                             End If
  1823.  
  1824.                         Else
  1825.                             Throw New ApplicationException(String.Format("Received Unknown Key: {0}. Possibly an unknown device.", key))
  1826.  
  1827.                         End If
  1828.  
  1829.                     End If
  1830.  
  1831.                 End If
  1832.  
  1833.             End If
  1834.  
  1835.         Finally
  1836.             Marshal.FreeHGlobal(buffer)
  1837.  
  1838.         End Try
  1839.  
  1840.     End Sub
  1841.  
  1842. #End Region
  1843.  
  1844. #Region " Hidden Methods "
  1845.  
  1846.     ''' <summary>
  1847.     ''' Assigns a handle to this window.
  1848.     ''' </summary>
  1849.     <EditorBrowsable(EditorBrowsableState.Never)>
  1850.     Public Shadows Sub AssignHandle(handle As IntPtr)
  1851.         MyBase.AssignHandle(handle)
  1852.     End Sub
  1853.  
  1854.     ''' <summary>
  1855.     ''' Creates a window and its handle with the specified creation parameters.
  1856.     ''' </summary>
  1857.     <EditorBrowsable(EditorBrowsableState.Never)>
  1858.     Public Shadows Sub CreateHandle(cp As CreateParams)
  1859.         MyBase.CreateHandle(cp)
  1860.     End Sub
  1861.  
  1862.     ''' <summary>
  1863.     ''' Destroys the window and its handle.
  1864.     ''' </summary>
  1865.     <EditorBrowsable(EditorBrowsableState.Never)>
  1866.     Public Shadows Sub DestroyHandle()
  1867.         MyBase.DestroyHandle()
  1868.     End Sub
  1869.  
  1870.     ''' <summary>
  1871.     ''' Releases the handle associated with this window.
  1872.     ''' </summary>
  1873.     <EditorBrowsable(EditorBrowsableState.Never)>
  1874.     Public Shadows Sub ReleaseHandle()
  1875.         MyBase.ReleaseHandle()
  1876.     End Sub
  1877.  
  1878.     ''' <summary>
  1879.     ''' Retrieves the current lifetime service object that controls the lifetime policy for this instance.
  1880.     ''' </summary>
  1881.     <EditorBrowsable(EditorBrowsableState.Never)>
  1882.     Public Shadows Function GetLifeTimeService() As Object
  1883.         Return MyBase.GetLifetimeService
  1884.     End Function
  1885.  
  1886.     ''' <summary>
  1887.     ''' Obtains a lifetime service object to control the lifetime policy for this instance.
  1888.     ''' </summary>
  1889.     <EditorBrowsable(EditorBrowsableState.Never)>
  1890.     Public Shadows Function InitializeLifeTimeService() As Object
  1891.         Return MyBase.InitializeLifetimeService
  1892.     End Function
  1893.  
  1894.     ''' <summary>
  1895.     ''' Creates an object that contains all the relevant information required to generate a proxy used to communicate with a remote object.
  1896.     ''' </summary>
  1897.     <EditorBrowsable(EditorBrowsableState.Never)>
  1898.     Public Shadows Function CreateObjRef(requestedType As Type) As System.Runtime.Remoting.ObjRef
  1899.         Return MyBase.CreateObjRef(requestedType)
  1900.     End Function
  1901.  
  1902.     ''' <summary>
  1903.     ''' Invokes the default window procedure associated with this window.
  1904.     ''' </summary>
  1905.     <EditorBrowsable(EditorBrowsableState.Never)>
  1906.     Public Shadows Sub DefWndProc(ByRef m As Message)
  1907.         MyBase.DefWndProc(m)
  1908.     End Sub
  1909.  
  1910. #End Region
  1911.  
  1912. #Region " Event-Handlers "
  1913.  
  1914.     ''' <summary>
  1915.     ''' Assign the handle of the target Form to this NativeWindow,
  1916.     ''' necessary to override target Form's WndProc.
  1917.     ''' </summary>
  1918.     Private Sub SetFormHandle() _
  1919.     Handles form.HandleCreated,
  1920.             form.Load,
  1921.             form.Shown
  1922.  
  1923.         If Not MyBase.Handle.Equals(Me.form.Handle) Then
  1924.             MyBase.AssignHandle(Me.form.Handle)
  1925.         End If
  1926.  
  1927.     End Sub
  1928.  
  1929.     ''' <summary>
  1930.     ''' Releases the Handle.
  1931.     ''' </summary>
  1932.     Private Sub OnHandleDestroyed() _
  1933.     Handles form.HandleDestroyed
  1934.  
  1935.         MyBase.ReleaseHandle()
  1936.  
  1937.     End Sub
  1938.  
  1939. #End Region
  1940.  
  1941. #Region " Windows Procedure (WndProc) "
  1942.  
  1943.     ''' ----------------------------------------------------------------------------------------------------
  1944.     ''' <summary>
  1945.     ''' Invokes the default window procedure associated with this window to process windows messages.
  1946.     ''' </summary>
  1947.     ''' ----------------------------------------------------------------------------------------------------
  1948.     ''' <param name="m">
  1949.     ''' A <see cref="System.Windows.Forms.Message" /> that is associated with the current window message.
  1950.     ''' </param>
  1951.     ''' ----------------------------------------------------------------------------------------------------
  1952.     Protected Overrides Sub WndProc(ByRef m As Message)
  1953.  
  1954.         Select Case m.Msg
  1955.  
  1956.             Case InputDevice.NativeMethods.WindowsMessages.WM_INPUT
  1957.                 Me.ProcessInputCommand(m)
  1958.  
  1959.         End Select
  1960.  
  1961.         MyBase.WndProc(m)
  1962.  
  1963.     End Sub
  1964.  
  1965. #End Region
  1966.  
  1967. #Region " IDisposable "
  1968.  
  1969.     ''' ----------------------------------------------------------------------------------------------------
  1970.     ''' <summary>
  1971.     ''' To detect redundant calls when disposing.
  1972.     ''' </summary>
  1973.     ''' ----------------------------------------------------------------------------------------------------
  1974.     Private isDisposed As Boolean = False
  1975.  
  1976.     ' ''' ----------------------------------------------------------------------------------------------------
  1977.     ' ''' <summary>
  1978.     ' ''' Prevent calls to methods after disposing.
  1979.     ' ''' </summary>
  1980.     ' ''' ----------------------------------------------------------------------------------------------------
  1981.     ' ''' <exception cref="System.ObjectDisposedException"></exception>
  1982.     ' ''' ----------------------------------------------------------------------------------------------------
  1983.     '<DebuggerStepThrough>
  1984.     'Private Sub DisposedCheck()
  1985.  
  1986.     '    If Me.isDisposed Then
  1987.     '        Throw New ObjectDisposedException(Me.GetType().FullName)
  1988.     '    End If
  1989.  
  1990.     'End Sub
  1991.  
  1992.     ''' ----------------------------------------------------------------------------------------------------
  1993.     ''' <summary>
  1994.     ''' Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
  1995.     ''' </summary>
  1996.     ''' ----------------------------------------------------------------------------------------------------
  1997.     <DebuggerStepThrough>
  1998.     Public Sub Dispose() Implements IDisposable.Dispose
  1999.         Me.Dispose(isDisposing:=True)
  2000.         GC.SuppressFinalize(obj:=Me)
  2001.     End Sub
  2002.  
  2003.     ''' ----------------------------------------------------------------------------------------------------
  2004.     ''' <summary>
  2005.     ''' Releases unmanaged and - optionally - managed resources.
  2006.     ''' </summary>
  2007.     ''' ----------------------------------------------------------------------------------------------------
  2008.     ''' <param name="isDisposing">
  2009.     ''' <c>True</c> to release both managed and unmanaged resources;
  2010.     ''' <c>False</c> to release only unmanaged resources.
  2011.     ''' </param>
  2012.     ''' ----------------------------------------------------------------------------------------------------
  2013.     <DebuggerStepThrough>
  2014.     Protected Sub Dispose(ByVal isDisposing As Boolean)
  2015.  
  2016.         If Not Me.isDisposed Then
  2017.  
  2018.             If isDisposing Then
  2019.                 Me.form = Nothing
  2020.                 MyBase.ReleaseHandle()
  2021.                 MyBase.DestroyHandle()
  2022.             End If
  2023.  
  2024.         End If
  2025.  
  2026.         Me.isDisposed = True
  2027.  
  2028.     End Sub
  2029.  
  2030. #End Region
  2031.  
  2032. End Class
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement