冰楓論壇

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

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

[複製鏈接]

1114

主題

0

好友

1042

積分

高級贊助會員

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

UID
390967
帖子
2182
主題
1114
精華
0
積分
1042
楓幣
26494
威望
578
存款
10100
贊助金額
1800
推廣
0
GP
3799
閱讀權限
150
在線時間
272 小時
註冊時間
2023-5-18
最後登入
2025-12-27

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

跳轉到指定樓層
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-2026 冰楓論壇, All rights reserved

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

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

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

GMT+8, 2026-1-6 08:01

回頂部