C#鍵盤鈎子實例


  1. 使用鈎子之前,需要使用SetWindowsHookEx()函數創建鈎子,使用完畢之后要UnhookWindowsHookEx()函數卸載鈎子,“鈎”到消息后操作系統會自動調用在創建鈎子時注冊的回調函數來處理消息,處理完后調用CallNextHookEx()函數等待或處理下一條消息。有關鈎子的詳細信息請見參考--C#鼠標鈎子,其中已介紹。
  2. 2

    對於鍵盤鈎子,鈎子類型為WH_KEYBOARD_LL=13,只需要設置SetWindowsHookEx的idHook參數為13即可“鈎”到鍵盤消息。關於鈎子類型的資料見參考資料--鈎子類型。

     

    鍵盤鈎子實例
 
  1. 1

    啟動VS,新建C# WinForm項目,命名為“Cs鍵盤鈎子”,如下:

  2. 2

    對主窗口布局,如下:

  3. 3

    添加Win32Api引用,代碼如下:

     public  class Win32Api

        {

            #region 常數和結構

            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;

           

            [StructLayout(LayoutKind.Sequential)] //聲明鍵盤鈎子的封送結構類型 

            public class KeyboardHookStruct

            {

                public int vkCode; //表示一個在1到254間的虛似鍵盤碼 

                public int scanCode; //表示硬件掃描碼 

                public int flags;

                public int time;

                public int dwExtraInfo;

            }

            #endregion

            #region Api

            public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);

            //安裝鈎子的函數 

            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]

            public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

     

            //卸下鈎子的函數 

            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]

            public static extern bool UnhookWindowsHookEx(int idHook);

     

            //下一個鈎掛的函數 

            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]

            public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);

     

            [DllImport("user32")]

            public static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState);

     

            [DllImport("user32")]

            public static extern int GetKeyboardState(byte[] pbKeyState);

     

            [DllImport("kernel32.dll", CharSet = CharSet.Auto,CallingConvention = CallingConvention.StdCall)]

            public  static extern IntPtr GetModuleHandle(string lpModuleName);

            #endregion

     

  4. 4

    添加新建類KeyboardHook,封裝鍵盤鈎子,代碼如下:

     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)

            {

                //如果該消息被丟棄(nCode<0)或者沒有事件綁定處理程序則不會觸發事件

                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);

                        }

                    }

                    //WM_KEYDOWN和WM_SYSKEYDOWN消息,將會引發OnKeyDownEvent事件

                    if (OnKeyDownEvent != null && (wParam == Win32Api.WM_KEYDOWN || wParam == Win32Api.WM_SYSKEYDOWN))

                    {

                        KeyEventArgs e = new KeyEventArgs(GetDownKeys(keyData));

                        

                        OnKeyDownEvent(this, e);

                    }

                    //WM_KEYDOWN消息將引發OnKeyPressEvent 

                    if (OnKeyPressEvent != null && wParam == Win32Api.WM_KEYDOWN)

                    {

                        byte[] keyState = new byte[256];

                        Win32Api.GetKeyboardState(keyState);

     

                        byte[] inBuffer = new byte[2];

                        if (Win32Api.ToAscii(KeyDataFromHook.vkCode, KeyDataFromHook.scanCode, keyState, inBuffer, KeyDataFromHook.flags) == 1)

                        {

                            KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer[0]);

                            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[i] == keyData) { preKeysList.RemoveAt(i); }

                            }

                        }

                    }

                    //WM_KEYUP和WM_SYSKEYUP消息,將引發OnKeyUpEvent事件 

                    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);

            }

            //根據已經按下的控制鍵生成key

            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;

            }

        }

     

  5. 5

    在主窗體中添加代碼,如下:

     public MainForm()

            {

                InitializeComponent();

            }

            KeyboardHook kh;

            private void Form1_Load(object sender, EventArgs e)

            {

                kh = new KeyboardHook();

                kh.SetHook();

                kh.OnKeyDownEvent += kh_OnKeyDownEvent;

            }

            void kh_OnKeyDownEvent(object sender, KeyEventArgs e)

            {

                if (e.KeyData == (Keys.S | Keys.Control)) { this.Show(); }//Ctrl+S顯示窗口

                if (e.KeyData == (Keys.H | Keys.Control)) { this.Hide(); }//Ctrl+H隱藏窗口

                if (e.KeyData == (Keys.C | Keys.Control)) { this.Close(); }//Ctrl+C 關閉窗口 

                if (e.KeyData == (Keys.A | Keys.Control | Keys.Alt)) { this.Text = "你發現了什么?"; }//Ctrl+Alt+A

            }

            private void Form1_FormClosing(object sender, FormClosingEventArgs e)

            {

                kh.UnHook();

            }

        }

  6. 6

    代碼添加完畢后,運行調試。當按下Ctrl+H是窗口隱藏,當按下Ctrl+S窗口顯示,當按下Ctrl+C時窗口關閉,開着QQ按下Ctrl+Alt+A時...(會出現什么呢?這個要你自己去發現哦)。

    C#鍵盤鈎子實現全局快捷鍵


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM