前阵子家里的笔记本出了点问题,就是键盘上的ESC键被卡住了,一直处理按下的状态,导致一系列问题(比如QQ窗口一开就提示是否关闭窗口等等)。N多不爽之后,决定写个程序暂时屏蔽掉ESC键。前阵子盗梦空间这么火,程序就叫KeyboardInception吧。哈哈。
简单地说,就是让程序捕获所有ESC键按下的事件,然后直接丢掉,这里需要用到windows下的hook技术,注意是hook,不是hooker(邪恶了:))。
Windows系统在运行过程中会产生各种各样的消息,hook,中文翻译为钩子,就是这个平台下的一种技术,它可以捕获指定的消息,通过回调函数,对消息进行响应,或是修改消息,甚至是拦截消息的传递。
应用程序使用钩子,需要把钩子安装到系统中,使用完成之后还需要进行卸载。系统中可能同时安装了很多很多很多的钩子,形成一个钩子链,最近安装的钩子在链的前端,可以获得优先的控制权。
安装钩子:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SetWindowsHookEx(int hookId, HookProc pfnHook, IntPtr hInst, int threadId);
可参考:http://msdn.microsoft.com/en-us/library/ms644990(VS.85).aspx
卸载钩子:
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern bool UnhookWindowsHookEx(IntPtr hHook);
把消息传递给钩子链的下一个钩子:
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern int CallNextHookEx(IntPtr hHook, int code, IntPtr wParam, IntPtr lParam);
废话少说,直接贴代码了。
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
namespace KeyboardInception
{
public static class HookHelper
{
#region Intercept Esc Key
private static IntPtr _hHookInterceptEscKey = IntPtr.Zero;
private static GCHandle _hInterceptEscKeyProc;
private static bool _interceptEsc;
public static bool InterceptEsc
{
get
{
return _interceptEsc;
}
set
{
_interceptEsc = value;
}
}
private static bool _interceptAll;
public static bool InterceptAll
{
get
{
return _interceptAll;
}
set
{
_interceptAll = value;
}
}
public static bool HookInterceptEscKey()
{
//
if (_hHookInterceptEscKey != IntPtr.Zero) UnhookInterceptEscKey();
//
HookProc hookProc = new HookProc(KeyboardCallback);
_hInterceptEscKeyProc = GCHandle.Alloc(hookProc);
_hHookInterceptEscKey = SetWindowsHookEx(WH_KEYBOARD, hookProc, GetModuleHandle("KERNEL32.dll"), 0);
//
return _hHookInterceptEscKey != IntPtr.Zero;
}
public static void UnhookInterceptEscKey()
{
try
{
if (_hHookInterceptEscKey != IntPtr.Zero)
{
UnhookWindowsHookEx(_hHookInterceptEscKey);
_hHookInterceptEscKey = IntPtr.Zero;
_hInterceptEscKeyProc.Free();
}
}
catch
{
// ...
}
}
private static int KeyboardCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (_interceptEsc)
{
KBDLLHOOKSTRUCT keyBoardHookStruct = new KBDLLHOOKSTRUCT();
CopyMemory(ref keyBoardHookStruct, lParam, 20);
if (keyBoardHookStruct.vkCode == 27) return 1;
}
if (_interceptAll)
{
return 1;
}
return CallNextHookEx(_hHookInterceptEscKey, nCode, wParam, lParam);
}
#endregion
#region PInvoke
#region Const
private const int WH_KEYBOARD = 13;
#endregion
#region Nested type
internal delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
public struct KBDLLHOOKSTRUCT
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
#endregion
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SetWindowsHookEx(int hookId, HookProc pfnHook, IntPtr hInst, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern bool UnhookWindowsHookEx(IntPtr hHook);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern int CallNextHookEx(IntPtr hHook, int code, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
internal static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]
internal static extern void CopyMemory(ref KBDLLHOOKSTRUCT source, IntPtr destination, int length);
#endregion
}
}
本例子的源代码下载,编译及运行需安装.net framework2.0。
http://download.csdn.net/source/3309962