[C#] (HOOK 鉤子)監聽系統鍵盤消息
當焦點不在程式上時,用程式加入監控按下鍵盤事件是無法捕抓到相關鍵盤消息!這時就要用HOOK監聽系統整體的消息發送
先創一個專門監聽功能的類別,這裡命名空間 SystemHookusing System;using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Reflection;
namespace SystemHook
{
class KeyboardHook
{
public event KeyEventHandler KeyDownEvent;
public event KeyPressEventHandler KeyPressEvent;
public event KeyEventHandler KeyUpEvent;
public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
static int hKeyboardHook = 0;
public const int WH_KEYBOARD_LL = 13;
HookProc KeyboardHookProcedure;
//鍵盤鉤子結構
public class KeyboardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
// 裝載鉤子
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);
// 取得當前執行緒編號
static extern int GetCurrentThreadId();
// 使用WINDOWS API函數取代取得目前執行個體的函數,防止鉤子失效
public static extern IntPtr GetModuleHandle(string name);
public void Start()
{
// 裝載鍵盤鉤子
if (hKeyboardHook == 0)
{
KeyboardHookProcedure = new HookProc(KeyboardHookProc);
hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName), 0);
if (hKeyboardHook == 0)
{
Stop();
throw new Exception("裝載鍵盤鉤子失敗");
}
}
}
public void Stop()
{
bool retKeyboard = true;
if (hKeyboardHook != 0)
{
retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
hKeyboardHook = 0;
}
if (!(retKeyboard)) throw new Exception("卸載鉤子失敗!");
}
// ToAscii 轉換指定的虛擬鍵碼和鍵盤狀態的對應字元或字元
public static extern int ToAscii(int uVirtKey,
int uScanCode,
byte[] lpbKeyState,
byte[] lpwTransKey,
int fuState);
// 取得按鍵的狀態
public static extern int GetKeyboardState(byte[] pbKeyState);
private static extern short GetKeyState(int vKey);
private const int WM_KEYDOWN = 0x100;
private const int WM_KEYUP = 0x101;
private const int WM_SYSKEYDOWN = 0x104;
private const int WM_SYSKEYUP = 0x105;
private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
// 監聽鍵盤事件
if ((nCode >= 0) && (KeyDownEvent != null || KeyUpEvent != null || KeyPressEvent != null))
{
KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
if (KeyDownEvent != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
{
Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e = new KeyEventArgs(keyData);
KeyDownEvent(this, e);
}
// 按下鍵盤
if (KeyPressEvent != null && wParam == WM_KEYDOWN)
{
byte[] keyState = new byte;
GetKeyboardState(keyState);
byte[] inBuffer = new byte;
if (ToAscii(MyKeyboardHookStruct.vkCode, MyKeyboardHookStruct.scanCode, keyState, inBuffer, MyKeyboardHookStruct.flags) == 1)
{
KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer);
KeyPressEvent(this, e);
}
}
// 放開鍵盤
if (KeyUpEvent != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
{
Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e = new KeyEventArgs(keyData);
KeyUpEvent(this, e);
}
}
// 如果返回1,則結束訊息,這個訊息到此為止,不再傳遞。
// 如果回傳0或呼叫CallNextHookEx函數,則訊息離開這個鉤子繼續往下傳遞,也就是傳給訊息真正的接受者
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
~KeyboardHook()
{
Stop();
}
}
}實作上把就是訂閱KeyboardHook類別的KeyDownEvent事件再回調自己設定的事件處理器函數
這裡舉例一個按下Alt+A就彈出訊息提示using System.Runtime.InteropServices;
using Microsoft.Win32;
KeyboardHook kb_hook = new KeyboardHook();
kb_hook.KeyDownEvent += new KeyEventHandler(hook_KeyDown);//鉤住鍵按下
kb_hook.Start();
private void hook_KeyDown(object sender, KeyEventArgs e)
{
//判斷按下的按鍵(Alt + A)
if (e.KeyValue == (int)Keys.A && (int)Control.ModifierKeys == (int)Keys.Alt)
{
System.Windows.Forms.MessageBox.Show(“按下了指定快捷键组合”);
}
}
若要再多組合幾個按鍵就把判斷條件再拓展就可以了
頁:
[1]