C# 實現全局熱鍵 – 鍵盤消息鉤子
2014年9月11日 15:38:27 全局熱鍵不建議用這種方式實現,下篇文章再說另外一種全局熱鍵的實現方式。
全局熱鍵應該怎那麼介紹才好?寫文章開頭好難,嗯,算了。
公司內部使用軟件一般都會需要賬號和密碼登錄,方便管理權限等等,可對於開發人員調試著卻是個阻礙,調試一次輸一次密碼,儘管系統支持自動登錄,密碼又是有一定的有效期,改密碼又要去改自動登錄的密碼(其實這個自動登錄就是替你輸入密碼,關鍵是更新這個自動登錄密碼很麻煩)。
索性自己做個自動輸密碼和賬號的,幸好之前做過QQ客戶端自動登錄,對SendMessage和PostMessage也有了個基礎認識,我可不敢說掌握50%。關於這兩個API怎麼用,自行谷歌,不再重複說了。
上代碼(我是有職業操守的人,關於公司的代碼…..你懂的),都有註釋,其他自己去試吧。
首先是Hook類,封裝成類極大地方便隨時使用。
using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Windows.Forms; namespace Hook { //事件委託 public delegate void KeyAction(int nCode,IntPtr wParam,Keys Keys); class Hook { //挂钩 [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)] private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); //取消挂钩 [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)] private static extern bool UnhookWindowsHookEx(int idHook); //调用下一个钩子 [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)] private static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr LParam); //键盘消息结构 [StructLayout(LayoutKind.Sequential)] private class KeyBoardHookStruct { public int vkCode; public int scanCode; public int flags; public int time; public int dwExtraInfo; } //私有委托 private delegate int HookProc(int nCode, IntPtr wParam, IntPtr LParam); private static HookProc KeyBoardHookProcedure; //事件聲明 //按下 public static event KeyAction KeyDown; //鬆開 public static event KeyAction KeyUp; //要用到的变量,标记是否成功设置钩子 private static int hHook = 0; //LowLevel键盘截获,如果是WH_KEYBOARD=2,并不能对系统键盘截取,Acrobat Reader会在你截取之前获得键盘。 private const int WH_KEYBOARD_LL = 13; private static int KeyBoardHookProc(int nCode, IntPtr wParam, IntPtr lParam) { KeyBoardHookStruct kbh = (KeyBoardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyBoardHookStruct)); //使用前需要為KeyUp和KeyDown綁定对应的处理过程,就像使用控件的事件一樣。 //鬆開按鍵 if (wParam.ToInt32() == 257) { KeyUp(nCode, wParam, (Keys)kbh.vkCode); } else { //按下 if (KeyDown != null) { KeyDown(nCode, wParam, (Keys)kbh.vkCode); } } //將按鍵消息交給下一個鉤子 return CallNextHookEx(hHook, nCode, wParam, lParam); //這句好像沒什麼用?即使這裡不調用,其他程序還是能收到鍵盤消息,有待研究。 } //取消钩子事件 public static bool Hook_Clear() { bool retKeyboard = true; if (hHook != 0) { retKeyboard = UnhookWindowsHookEx(hHook); hHook = 0; } return retKeyboard; } //开始钩子 public static bool Hook_Start() { bool retKeyboard = true; if (hHook == 0) { KeyBoardHookProcedure = new HookProc(KeyBoardHookProc); hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardHookProcedure,Process.GetCurrentProcess().MainModule.BaseAddress, 0); //如果设置钩子失败. if (hHook == 0) { retKeyboard = false; Hook_Clear(); } } return retKeyboard; } } }
在你複製這段代碼進VS前,請大概地瀏覽下代碼,看清楚再複製進去,不要想當然地Ctrl+A,Ctral+C,Ctral+V。
這裡弄成靜態類,有兩個監聽事件,使用時把監聽事件掛接上,調用下Start,搞定。
還是上點調用代碼,免得自己忘了。
窗體內控件如圖,文本框是richTextbox
窗體代碼
private void Form1_Load(object sender, EventArgs e) { Hook.KeyDown += new KeyAction(Hook_KeyDown); Hook.KeyUp += new KeyAction(Hook_KeyUp); } private void button2_Click(object sender, EventArgs e) { Hook.Hook_Clear(); } private void button1_Click(object sender, EventArgs e) { Hook.Hook_Start(); } void Hook_KeyUp(int nCode, IntPtr wParam, Keys Keys) { if (nCode >= 0) { //Ctrl、Alt、Shift狀態 richTextBox1.AppendText("1:ModifierKeys Status:" + ((int)Control.ModifierKeys).ToString() + "r"); richTextBox1.AppendText("1:Keys: " + Keys.ToString() + ",鬆開...r"); richTextBox1.ScrollToCaret(); } } void Hook_KeyDown(int nCode, IntPtr wParam, Keys Keys) { if (nCode >= 0) { //Ctrl、Alt、Shift狀態 richTextBox1.AppendText("2:ModifierKeys Status:" + ((int)Control.ModifierKeys).ToString() + "r"); richTextBox1.AppendText("2:Keys: " + Keys.ToString() + ",按下...r"); richTextBox1.ScrollToCaret(); } }
OK,就是這麼簡單,就是這麼容易,對於有按鍵消息後做些什麼事情,自己開發去。
運行截圖