C# 实现键盘钩子,在搜狗输入法使用中,获取键盘输入
百度百科:解释
Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都是通过消息的传递来实现的。而钩子是Windows系统中非常重要的系统接口,用它可以截获并处理送给其他应用程序的消息,来完成普通应用程序难以实现的功能。
钩子可以监视系统或进程中的各种事件消息,截获发往目标窗口的消息并进行处理。这样,我们就可以在系统中安装自定义的钩子,监视系统中特定事件的发生,完成特定的功能,比如截获键盘、鼠标的输入,屏幕取词,日志监视等等。
钩子的本质是一段用以处理系统消息的程序,通过系统调用,将其挂入系统。钩子的种类有很多,每种钩子可以截获并处理相应的消息,每当特定的消息发出,在到达目的窗口之前,钩子程序先行截获该消息、得到对此消息的控制权。此时在钩子函数中就可以对截获的消息进行加工处理,甚至可以强制结束消息的传递。
全局钩子:全局钩子,能够截获所有运行在操作系统上的程序发送的消息,但是因其全局性,钩子安装之后,会比较损耗性能,在使用完毕之后,必须实时的卸载。
进程钩子:可以针对某一个进程,仅仅截获某一个应用程序的消息,比较具有针对性,适用于普通的信息管理系统。
//定义委托
/// <summary> /// 键盘处理事件委托,接受返回win32的委托 /// </summary> /// <param name="nCode"></param> /// <param name="wParam"></param> /// <param name="lParam"></param> /// <returns></returns> public delegate int HookHandle(int nCode, int wParam, IntPtr lParam); /// <summary> /// 客户端处理钩子回调的键盘处理事件 /// </summary> /// <param name="hookKey">钩子的唯一标志</param> /// <param name="key">按下的键</param> /// <param name="handle">客户端是否处理了这个值</param> public delegate void ProcessKeyHandle(int hookKey, Keys key, out bool handle);
//抽象键盘钩子KeyBoardHook
/// <summary>
/// 键盘钩子
/// </summary>
public abstract class KeyBoardHook
{
#region 字段
/// <summary>
/// 当前钩子的id
/// </summary>
protected int hHookId = 0;
/// <summary>
/// 外部调用的键盘处理事件
/// </summary>
protected ProcessKeyHandle clientMethod = null;
/// <summary>
/// 当前模块的句柄
/// </summary>
protected IntPtr hookWindowPtr = IntPtr.Zero;
/// <summary>
/// 勾子程序处理事件
/// </summary>
protected HookHandle keyBoardHookProcedure;
protected int hookKey;
#endregion
#region 属性
/// <summary>
/// 获取或设置钩子的唯一标志
/// </summary>
public int HookKey
{
get { return this.hookKey; }
set { this.hookKey = value; }
}
#endregion
/// <summary>
/// 安装钩子
/// </summary>
/// <param name="clientMethod"></param>
/// <returns></returns>
public abstract bool Install(ProcessKeyHandle clientMethod);
/// <summary>
/// 钩子处理函数
/// </summary>
/// <param name="nCode"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <returns></returns>
protected abstract int GetHookProc(int nCode, int wParam, IntPtr lParam);
/// <summary>
/// 卸载钩子
/// </summary>
public virtual void UnInstall()
{
bool retKeyboard = true;
if (hHookId != 0)
{
retKeyboard = Win32API.UnhookWindowsHookEx(hHookId);
hHookId = 0;
}
//if (hookWindowPtr != IntPtr.Zero)
//{
// Marshal.FreeHGlobal(hookWindowPtr);
//}
if (!retKeyboard)
{
throw new Exception("UnhookWindowsHookEx failed.");
}
}
}//进程钩子,只能捕捉本进程的按键信息
/// <summary>
/// 进程钩子,只能捕捉本进程的按键信息
/// </summary>
public class ProcessHook : KeyBoardHook
{
public override bool Install(ProcessKeyHandle clientMethod)
{
try
{
this.clientMethod = clientMethod;
// 安装键盘钩子
if (hHookId == 0)
{
keyBoardHookProcedure = GetHookProc;
hookWindowPtr = Win32API.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
hHookId = Win32API.SetWindowsHookEx(
(int)HookType.WH_KEYBOARD,
keyBoardHookProcedure,
IntPtr.Zero,
Win32API.GetCurrentThreadId()
);
//如果设置钩子失败.
if (hHookId == 0)
UnInstall();
}
return true;
}
catch
{
return false;
}
}
protected override int GetHookProc(int nCode, int wParam, IntPtr lParam)
{
if (nCode == 0 && nCode != 3)
{
bool isKeyDown = false;
if (IntPtr.Size == 4)
{
isKeyDown = (((lParam.ToInt32() & 0x80000000) == 0));
}
if (IntPtr.Size == 8)
{
isKeyDown = (((lParam.ToInt64() & 0x80000000) == 0));
}
// 键盘按下
if (isKeyDown)
{
//Debug.WriteLine("key down_________________________");
//触发事件把安装信息通知客户端
if (clientMethod != null)
{
//进程钩子,按键值在这里
Keys keyData = (Keys)wParam;
bool handle;
clientMethod(this.hookKey, keyData, out handle);
if (handle)//如果处理了就直接停止 1:
{
Win32API.CallNextHookEx(hHookId, nCode, wParam, lParam);
return 1;
}
}
}
}
return Win32API.CallNextHookEx(hHookId, nCode, wParam, lParam);
}
}//Win32API 调用封装在User32.dll中的方法,如果我们的程序需要用到钩子,首先需要将钩子对应的程序集导入到我们的系统中。
public class Win32API
{
/// <summary>
/// 获取窗体线程ID
/// </summary>
/// <param name="hwnd">窗体句柄</param>
/// <param name="ID"></param>
/// <returns></returns>
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowThreadProcessId(IntPtr hwnd, int ID);
/// <summary>
/// 设置钩子
/// </summary>
/// <param name="idHook">钩子id</param>
/// <param name="lpfn">钩子处理方法</param>
/// <param name="hInstance">句柄</param>
/// <param name="threadId">线程id</param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern int SetWindowsHookEx(int idHook, HookHandle lpfn, IntPtr hInstance, int threadId);
/// <summary>
/// 取消钩子
/// </summary>
/// <param name="idHook"></param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
/// <summary>
/// 调用下一个钩子
/// </summary>
/// <param name="idHook">本钩子id</param>
/// <param name="nCode"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
/// <summary>
/// 获取当前线程ID
/// </summary>
/// <returns></returns>
[DllImport("kernel32.dll")]
public static extern int GetCurrentThreadId();
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string name);
}钩子工厂 KeyBoardHookHelper
public class KeyBoardHookHelper
{
public static KeyBoardHook CreateHook(KeyBoardHookType keyBoardHookType)
{
return new ProcessHook();
}
}窗口辅助类:FromHelper
public class FromHelper
{
private KeyBoardHook hook;
/// <summary>
/// 创建进程键盘钩子
/// </summary>
public void CreateProcessHook()
{
if (hook != null)
{
hook.UnInstall();
}
//使用工厂类创建出对应的钩子。
hook = KeyBoardHookHelper.CreateHook(KeyBoardHookType.Process);
if (hook.Install(ClientProcessKeyHandle))
{
hook.HookKey = this.GetHashCode();
}
}
//客户端传给钩子的监听方法。
private void ClientProcessKeyHandle(int hookKey, Keys key, out bool handle)
{
handle = false;
if (hookKey == hook.HookKey)
{
OnClientProcessKeyHandle(key, out handle);
}
return;
}
/// <summary>
/// 子类重写键盘钩子处理方法(系统中存在多个窗体,可将该代码放入到窗体基类中,子类只需重写该方法即可。)
/// </summary>
/// <param name="key"></param>
/// <param name="handle"></param>
protected virtual void OnClientProcessKeyHandle(Keys key, out bool handle)
{
handle = false;
Console.WriteLine(key);
////截获消息并进行处理。
//if ((int)key == (int)Keys.F2)//保存,
//{
// OnSaveOrder(this.tsbtn_Save);
// handle = true;
//}
}
}界面调用方法:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private FromHelper fhelper = new FromHelper();
private void Form1_Load(object sender, EventArgs e)
{
fhelper.CreateProcessHook();
}
}界面效果:

这时在搜索浮动窗口时,可以获取键盘输入字符串