KeyboardHookHelper.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. using System.Diagnostics;
  2. using System.Runtime.InteropServices;
  3. using System.Windows.Input;
  4. namespace ProximaAnalizer.Helpers;
  5. internal class KeyboardHook
  6. {
  7. public delegate void KeyDownEvent(Key key);
  8. public delegate void KeyUpEvent(Key key);
  9. private int _hKeyboardHook;
  10. private Win32Helper.HookProc? _keyboardHookDelegate;
  11. private KeyDownEvent? _onKeyDown;
  12. private KeyUpEvent? _onKeyUp;
  13. public void SetHook()
  14. {
  15. _keyboardHookDelegate = KeyboardHookProc;
  16. var cModule = Process.GetCurrentProcess().MainModule;
  17. if (null == cModule) return;
  18. var moduleHandle = Win32Helper.GetModuleHandle(cModule.ModuleName);
  19. _hKeyboardHook = Win32Helper.SetWindowsHookEx(Win32Helper.WH_KEYBOARD_LL, _keyboardHookDelegate, moduleHandle, 0);
  20. }
  21. public void SetOnKeyDownEvent(KeyDownEvent callback)
  22. {
  23. _onKeyDown = callback;
  24. }
  25. public void SetOnKeyUpEvent(KeyUpEvent callback)
  26. {
  27. _onKeyUp = callback;
  28. }
  29. public void UnHook()
  30. {
  31. var retKeyboard = true;
  32. if (_hKeyboardHook != 0)
  33. {
  34. retKeyboard = Win32Helper.UnhookWindowsHookEx(_hKeyboardHook);
  35. _hKeyboardHook = 0;
  36. }
  37. //如果卸下钩子失败
  38. if (!retKeyboard)
  39. throw new Exception("卸下钩子失败!");
  40. }
  41. /// <summary>
  42. /// 获取键盘消息
  43. /// </summary>
  44. /// <param name="nCode"></param>
  45. /// <param name="wParam"></param>
  46. /// <param name="lParam"></param>
  47. /// <returns></returns>
  48. private int KeyboardHookProc(int nCode, int wParam, IntPtr lParam)
  49. {
  50. // 如果该消息被丢弃 nCode<0
  51. if (nCode < 0)
  52. return Win32Helper.CallNextHookEx(_hKeyboardHook, nCode, wParam, lParam);
  53. if (Marshal.PtrToStructure(lParam, typeof(Win32Helper.KeyboardHookStruct)) is not Win32Helper.KeyboardHookStruct keyboardHookStruct)
  54. return Win32Helper.CallNextHookEx(_hKeyboardHook, nCode, wParam, lParam);
  55. var key = KeyInterop.KeyFromVirtualKey(keyboardHookStruct.vkCode);
  56. switch (wParam)
  57. {
  58. case Win32Helper.WM_KEYDOWN:
  59. case Win32Helper.WM_SYSKEYDOWN:
  60. _onKeyDown?.Invoke(key);
  61. break;
  62. case Win32Helper.WM_KEYUP:
  63. case Win32Helper.WM_SYSKEYUP:
  64. _onKeyUp?.Invoke(key);
  65. break;
  66. }
  67. return Win32Helper.CallNextHookEx(_hKeyboardHook, nCode, wParam, lParam);
  68. }
  69. }
  70. internal class Win32Helper
  71. {
  72. public delegate int HookProc(int nCode, int wParam, IntPtr lParam);
  73. public const int WM_KEYDOWN = 0x100;
  74. public const int WM_KEYUP = 0x101;
  75. public const int WM_SYSKEYDOWN = 0x104;
  76. public const int WM_SYSKEYUP = 0x105;
  77. public const int WH_KEYBOARD_LL = 13;
  78. //安装钩子的函数
  79. [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
  80. public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
  81. //卸下钩子的函数
  82. [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
  83. public static extern bool UnhookWindowsHookEx(int idHook);
  84. //下一个钩挂的函数
  85. [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
  86. public static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
  87. [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
  88. public static extern IntPtr GetModuleHandle(string lpModuleName);
  89. [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
  90. public static extern bool SetForegroundWindow(IntPtr hWnd);
  91. [DllImport("winmm.dll", EntryPoint = "mciSendString", CharSet = CharSet.Auto)]
  92. public static extern int MciSendString(string lpstrCommand, string lpstrReturnString, int uReturnLength,
  93. int hwndCallback);
  94. [StructLayout(LayoutKind.Sequential)] //声明键盘钩子的封送结构类型
  95. public class KeyboardHookStruct
  96. {
  97. public int vkCode; //表示一个在1到254间的虚似键盘码
  98. public int scanCode; //表示硬件扫描码
  99. public int flags;
  100. public int time;
  101. public int dwExtraInfo;
  102. }
  103. }