冰楓論壇

 找回密碼
 立即註冊
搜索
查看: 3748|回覆: 0
打印 上一主題 下一主題

[心得] [C#] (HOOK 鉤子)監聽系統鍵盤消息

[複製鏈接]

821

主題

0

好友

854

積分

高級贊助會員

Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20

UID
390967
帖子
1592
主題
821
精華
0
積分
854
楓幣
10961
威望
395
存款
10100
贊助金額
1800
推廣
0
GP
2677
閱讀權限
150
在線時間
189 小時
註冊時間
2023-5-18
最後登入
2024-11-21

2023年紀念勳章 太陽勳章 神手勳章 高級客戶 VIP會員 私服達人 懶人勳章 幼兒勳章 音樂勳章 屁孩勳章 貢獻王 性別(女) 性別(男) 積分勳章 發帖達人 2023端午節紀念勳章 富豪勳章 富可敵國 2023中秋節紀念勳章 解說達人 論壇粉絲 2023聖誕節紀念勳章 2024年紀念勳章 2024端午節紀念勳章 2024中秋節紀念勳章

跳轉到指定樓層
1
發表於 2023-10-15 00:35:50 |只看該作者 |倒序瀏覽
當焦點不在程式上時,用程式加入監控按下鍵盤事件是無法捕抓到相關鍵盤消息!
這時就要用HOOK監聽系統整體的消息發送
先創一個專門監聽功能的類別,這裡命名空間 SystemHook
  1. using System;using System.Collections.Generic;
  2. using System.Text;
  3. using System.Runtime.InteropServices;
  4. using System.windows.Forms;
  5. using System.Reflection;

  6. namespace SystemHook
  7. {
  8.     class KeyboardHook
  9.     {
  10.         public event KeyEventHandler KeyDownEvent;
  11.         public event KeyPressEventHandler KeyPressEvent;
  12.         public event KeyEventHandler KeyUpEvent;

  13.         public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
  14.         static int hKeyboardHook = 0;
  15.         public const int WH_KEYBOARD_LL = 13;
  16.         HookProc KeyboardHookProcedure;

  17.         //鍵盤鉤子結構
  18.         [StructLayout(LayoutKind.Sequential)]
  19.         public class KeyboardHookStruct
  20.         {
  21.             public int vkCode;
  22.             public int scanCode;
  23.             public int flags;
  24.             public int time;
  25.             public int dwExtraInfo;
  26.         }

  27.         // 裝載鉤子
  28.         [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
  29.         public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

  30.         // 卸載鉤子
  31.         [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
  32.         public static extern bool UnhookWindowsHookEx(int idHook);

  33.         // 呼叫下一個鉤子
  34.         [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
  35.         public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);

  36.         // 取得當前執行緒編號
  37.         [DllImport("kernel32.dll")]
  38.         static extern int GetCurrentThreadId();

  39.         // 使用WINDOWS API函數取代取得目前執行個體的函數,防止鉤子失效
  40.         [DllImport("kernel32.dll")]
  41.         public static extern IntPtr GetModuleHandle(string name);

  42.         public void Start()
  43.         {
  44.             // 裝載鍵盤鉤子
  45.             if (hKeyboardHook == 0)
  46.             {
  47.                 KeyboardHookProcedure = new HookProc(KeyboardHookProc);
  48.                 hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName), 0);

  49.                 if (hKeyboardHook == 0)
  50.                 {
  51.                     Stop();
  52.                     throw new Exception("裝載鍵盤鉤子失敗");
  53.                 }
  54.             }
  55.         }

  56.         public void Stop()
  57.         {
  58.             bool retKeyboard = true;
  59.             if (hKeyboardHook != 0)
  60.             {
  61.                 retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
  62.                 hKeyboardHook = 0;
  63.             }
  64.             if (!(retKeyboard)) throw new Exception("卸載鉤子失敗!");
  65.         }

  66.         // ToAscii 轉換指定的虛擬鍵碼和鍵盤狀態的對應字元或字元
  67.         [DllImport("user32")]
  68.         public static extern int ToAscii(int uVirtKey,
  69.                                          int uScanCode,
  70.                                          byte[] lpbKeyState,
  71.                                          byte[] lpwTransKey,
  72.                                          int fuState);

  73.         // 取得按鍵的狀態
  74.         [DllImport("user32")]
  75.         public static extern int GetKeyboardState(byte[] pbKeyState);

  76.         [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
  77.         private static extern short GetKeyState(int vKey);

  78.         private const int WM_KEYDOWN = 0x100;
  79.         private const int WM_KEYUP = 0x101;
  80.         private const int WM_SYSKEYDOWN = 0x104;
  81.         private const int WM_SYSKEYUP = 0x105;

  82.         private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
  83.         {
  84.             // 監聽鍵盤事件
  85.             if ((nCode >= 0) && (KeyDownEvent != null || KeyUpEvent != null || KeyPressEvent != null))
  86.             {
  87.                 KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));

  88.                 if (KeyDownEvent != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
  89.                 {
  90.                     Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
  91.                     KeyEventArgs e = new KeyEventArgs(keyData);
  92.                     KeyDownEvent(this, e);
  93.                 }

  94.                 // 按下鍵盤
  95.                 if (KeyPressEvent != null && wParam == WM_KEYDOWN)
  96.                 {
  97.                     byte[] keyState = new byte[256];
  98.                     GetKeyboardState(keyState);

  99.                     byte[] inBuffer = new byte[2];
  100.                     if (ToAscii(MyKeyboardHookStruct.vkCode, MyKeyboardHookStruct.scanCode, keyState, inBuffer, MyKeyboardHookStruct.flags) == 1)
  101.                     {
  102.                         KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer[0]);
  103.                         KeyPressEvent(this, e);
  104.                     }
  105.                 }

  106.                 // 放開鍵盤
  107.                 if (KeyUpEvent != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
  108.                 {
  109.                     Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
  110.                     KeyEventArgs e = new KeyEventArgs(keyData);
  111.                     KeyUpEvent(this, e);
  112.                 }

  113.             }
  114.             // 如果返回1,則結束訊息,這個訊息到此為止,不再傳遞。
  115.             // 如果回傳0或呼叫CallNextHookEx函數,則訊息離開這個鉤子繼續往下傳遞,也就是傳給訊息真正的接受者
  116.             return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
  117.         }
  118.         ~KeyboardHook()
  119.         {
  120.             Stop();
  121.         }
  122.     }
  123. }
複製代碼
實作上把就是訂閱KeyboardHook類別的KeyDownEvent事件再回調自己設定的事件處理器函數
這裡舉例一個按下Alt+A就彈出訊息提示
  1. using System.Runtime.InteropServices;
  2. using Microsoft.Win32;

  3. KeyboardHook kb_hook = new KeyboardHook();
  4. kb_hook.KeyDownEvent += new KeyEventHandler(hook_KeyDown);//鉤住鍵按下
  5. kb_hook.Start();

  6. private void hook_KeyDown(object sender, KeyEventArgs e)
  7. {
  8.         //判斷按下的按鍵(Alt + A)
  9.         if (e.KeyValue == (int)Keys.A && (int)Control.ModifierKeys == (int)Keys.Alt)
  10.         {
  11.                 System.Windows.Forms.MessageBox.Show(“按下了指定快捷键组合”);
  12.         }
  13. }
複製代碼
若要再多組合幾個按鍵就把判斷條件再拓展就可以了
[發帖際遇]: whitefox 為了避免被「就讀腐大的咬蚊子」嗆「多讀點書」,因此購買大量書籍,花費 1 楓幣 幸運榜 / 衰神榜
收藏收藏0 推0 噓0


把本文推薦給朋友或其他網站上,每次被點擊增加您在本站積分: 1彩票
複製連結並發給好友,以賺取推廣點數
簡單兩步驟,註冊、分享網址,即可獲得獎勵! 一起推廣文章換商品、賺$$
高級模式
B Color Image Link Quote Code Smilies |上傳

廣告刊登意見回饋關於我們管群招募本站規範DMCA隱私權政策

Copyright © 2011-2024 冰楓論壇, All rights reserved

免責聲明:本網站是以即時上載留言的方式運作,本站對所有留言的真實性、完整性及立場等,不負任何法律責任。

而一切留言之言論只代表留言者個人意見,並非本網站之立場,用戶不應信賴內容,並應自行判斷內容之真實性。

小黑屋|手機版|冰楓論壇

GMT+8, 2024-11-21 17:29

回頂部