wyb36870 发表于 2018-5-3 10:09:17

用键盘钩子定义全局快捷键

折腾了很久终于通过键盘钩子解决了按ESC键响应事件,把关键的两个类贴出来供大家使用.QQ:570869611
    public class Win32Api
    {
      public const int WM_KEYDOWN = 0x100;
      public const int WM_KEYUP = 0x101;
      public const int WM_SYSKEYDOWN = 0x104;
      public const int WM_SYSKEYUP = 0x105;
      public const int WH_KEYBOARD_LL = 13;
      
      public class KeyboardHookStruct
      {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
      }
      public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
      
      public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
      
      public static extern bool UnhookWindowsHookEx(int idHook);
      
      public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
      
      public static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState);
      
      public static extern int GetKeyboardState(byte[] pbKeyState);
      
      public static extern IntPtr GetModuleHandle(string lpModuleName);
    } public class KeyboardHook
    {
      int hHook;
      Win32Api.HookProc KeyboardHookDelegate;
      public event KeyEventHandler OnKeyDownEvent;
      public event KeyEventHandler OnKeyUpEvent;
      public event KeyPressEventHandler OnKeyPressEvent;
      public KeyboardHook() { }
      public void SetHook()
      {
            KeyboardHookDelegate = new Win32Api.HookProc(KeyboardHookProc);
            Process cProcess = Process.GetCurrentProcess();
            ProcessModule cModule = cProcess.MainModule;
            var mh = Win32Api.GetModuleHandle(cModule.ModuleName);
            hHook = Win32Api.SetWindowsHookEx(Win32Api.WH_KEYBOARD_LL, KeyboardHookDelegate, mh, 0);
      }
      public void UnHook()
      {
            Win32Api.UnhookWindowsHookEx(hHook);
      }
      private List<Keys> preKeysList = new List<Keys>();
      private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
      {
            if ((nCode >= 0) && (OnKeyDownEvent != null || OnKeyUpEvent != null || OnKeyPressEvent != null))
            {
                Win32Api.KeyboardHookStruct KeyDataFromHook = (Win32Api.KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.KeyboardHookStruct));
                Keys keyData = (Keys)KeyDataFromHook.vkCode;
                if ((OnKeyDownEvent != null || OnKeyPressEvent != null) && (wParam == Win32Api.WM_KEYDOWN || wParam == Win32Api.WM_SYSKEYDOWN))
                {
                  if (IsCtrlAltShiftKeys(keyData) && preKeysList.IndexOf(keyData) == -1)
                  {
                        preKeysList.Add(keyData);
                  }
                }
                if (OnKeyDownEvent != null && (wParam == Win32Api.WM_KEYDOWN || wParam == Win32Api.WM_SYSKEYDOWN))
                {
                  KeyEventArgs e = new KeyEventArgs(GetDownKeys(keyData));

                  OnKeyDownEvent(this, e);
                }
                if (OnKeyPressEvent != null && wParam == Win32Api.WM_KEYDOWN)
                {
                  byte[] keyState = new byte;
                  Win32Api.GetKeyboardState(keyState);

                  byte[] inBuffer = new byte;
                  if (Win32Api.ToAscii(KeyDataFromHook.vkCode, KeyDataFromHook.scanCode, keyState, inBuffer, KeyDataFromHook.flags) == 1)
                  {
                        KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer);
                        OnKeyPressEvent(this, e);
                  }
                }
                if ((OnKeyDownEvent != null || OnKeyPressEvent != null) && (wParam == Win32Api.WM_KEYUP || wParam == Win32Api.WM_SYSKEYUP))
                {
                  if (IsCtrlAltShiftKeys(keyData))
                  {
                        for (int i = preKeysList.Count - 1; i >= 0; i--)
                        {
                            if (preKeysList == keyData) { preKeysList.RemoveAt(i); }
                        }
                  }
                }
                if (OnKeyUpEvent != null && (wParam == Win32Api.WM_KEYUP || wParam == Win32Api.WM_SYSKEYUP))
                {
                  KeyEventArgs e = new KeyEventArgs(GetDownKeys(keyData));
                  OnKeyUpEvent(this, e);
                }
            }
            return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);
      }
      private Keys GetDownKeys(Keys key)
      {
            Keys rtnKey = Keys.None;
            foreach (Keys i in preKeysList)
            {
                if (i == Keys.LControlKey || i == Keys.RControlKey) { rtnKey = rtnKey | Keys.Control; }
                if (i == Keys.LMenu || i == Keys.RMenu) { rtnKey = rtnKey | Keys.Alt; }
                if (i == Keys.LShiftKey || i == Keys.RShiftKey) { rtnKey = rtnKey | Keys.Shift; }
            }
            return rtnKey | key;
      }
      private Boolean IsCtrlAltShiftKeys(Keys key)
      {
            if (key == Keys.LControlKey || key == Keys.RControlKey || key == Keys.LMenu || key == Keys.RMenu || key == Keys.LShiftKey || key == Keys.RShiftKey) { return true; }
            return false;
      }
    }调用方法

      static KeyboardHook hook;

      
      public static void CommandName()
      {
            hook = new KeyboardHook();
            hook.SetHook();
            hook.OnKeyDownEvent += Hook_OnKeyDownEvent;
      }

      private static void Hook_OnKeyDownEvent(object sender, KeyEventArgs e)
      {
            if (e.KeyData == Keys.Escape)
            {
                System.Windows.Forms.MessageBox.Show("你按了ESC键");
            }
      }




阿霸jun 发表于 2018-5-3 10:16:58

多谢分享,谢谢!

pxt2001 发表于 2022-12-7 13:39:54

多谢分享,仅Esc键没意思,如何响应其他按键?例如单字母按键a,b,组合键Ctrl+a,shift+b,下箭头等等

clinber 发表于 2022-12-31 21:50:43

pxt2001 发表于 2022-12-7 13:39
多谢分享,仅Esc键没意思,如何响应其他按键?例如单字母按键a,b,组合键Ctrl+a,shift+b,下箭头等等

https://blog.csdn.net/ipzlkmy/article/details/7296832

https://blog.csdn.net/gaiazhang/article/details/53942531

d1742647821 发表于 2023-1-4 15:33:45

如果只是在cad里用,建议用cad自带的钩子,dllimport不稳定
页: [1]
查看完整版本: 用键盘钩子定义全局快捷键