在自己開發的程式裡,實作自定義功能鍵,是比較容易的事。但是,如果需要實作一些系統級别的按鍵自定義,在離開自己開發程式界面,或者在其他程式的界面,可以響應到按鍵事件,隻能使用鈎子的方式實作。
請參考以下例子,例子中捕獲了Code=112,113,114,115,116鍵值的按鍵(一般代表一些PDA的F1,F2,F3,F4,F5鍵):
class HookKeyClass
{
public delegate int HookKeyProc(int code, IntPtr wParam, IntPtr lParam);
public delegate void KeyEventHandler(int KeyValue);
public event KeyEventHandler KeyEvent;
private HookKeyProc hookKeyDeleg;
private int hHookKey = 0;
public HookKeyClass()
{ Start(); }
~HookKeyClass()
{ Stop(); }
#region public methods
//安裝鈎子
private void Start()
{
if (hHookKey != 0)
{
//Unhook the previouse one
this.Stop();
}
hookKeyDeleg = new HookKeyProc(HookKeyProcedure);
hHookKey = SetWindowsHookEx(WH_KEYBOARD_LL, hookKeyDeleg, GetModuleHandle(null), 0);
if (hHookKey == 0)
{
throw new SystemException("Failed acquiring of the hook.");
}
}
//拆除鈎子
private void Stop()
{
UnhookWindowsHookEx(hHookKey);
}
#endregion
#region protected and private methods
private int HookKeyProcedure(int code, IntPtr wParam, IntPtr lParam)
{
KBDLLHOOKSTRUCT hookStruct = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
if (code < 0)
{ return CallNextHookEx(hookKeyDeleg, code, wParam, lParam); }
if (hookStruct.vkCode == 112 || hookStruct.vkCode == 113 ||
hookStruct.vkCode == 114 || hookStruct.vkCode == 115 || hookStruct.vkCode == 116)
{
KeyEvent(hookStruct.vkCode);
}
return CallNextHookEx(hookKeyDeleg, code, wParam, lParam);
}
#endregion
#region P/Invoke declarations
[DllImport("coredll.dll")]
private static extern int SetWindowsHookEx(int type, HookKeyProc HookKeyProc, IntPtr hInstance, int m);
//private static extern int SetWindowsHookEx(int type, HookMouseProc HookMouseProc, IntPtr hInstance, int m);
[DllImport("coredll.dll")]
private static extern IntPtr GetModuleHandle(string mod);
[DllImport("coredll.dll")]
private static extern int CallNextHookEx(HookKeyProc hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("coredll.dll")]
private static extern int GetCurrentThreadId();
[DllImport("coredll.dll", SetLastError = true)]
private static extern int UnhookWindowsHookEx(int idHook);
private struct KBDLLHOOKSTRUCT
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public IntPtr dwExtraInfo;
}
const int WH_KEYBOARD_LL = 20;
public class KeyBoardInfo
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
}
#endregion
}
在界面背景代碼中,對捕獲的按鍵行為進行定義:
HookKeyClass hk = new HookKeyClass();
hk.KeyEvent += new HookKeyClass.KeyEventHandler(hk_KeyEvent);
private void hk_KeyEvent(int KeyValue)
{
if (KeyValue == 112)
{
// do something
}
else if (KeyValue == 113)
{
// do something
}
else if (KeyValue == 114)
{
// do something
}
else if (KeyValue == 115)
{
// do something
}
else if (KeyValue == 116)
{
// do something
}
}