KeyBoard Hook

8 篇文章 0 订阅
1 篇文章 0 订阅
/* ****************************************************************
 * author	:	ShianYuan
 * email	:	a-shyuan@microsoft.com, sayuan@outlook.com
 * clr		:	4.0.30319.34014
 * itemname	:	KeyboardHook
 * history	:	created by ShianYuan 2014/9/24 14:23:11 
 * ****************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FirstHook
{
	#region 基础类型
	/// <summary>
	/// Window相关消息
	/// </summary>
	public class WindowMessage
	{
		public const int WM_KEYDOWN = 0x100;  //按下键  
		public const int WM_KEYUP = 0x101; //按键抬起  
		public const int WM_SYSKEYDOWN = 0x104;
		public const int WM_SYSKEYUP = 0x105;
		public const int WM_MOUSEMOVE = 0x200;
		public const int WM_LBUTTONDOWN = 0x201;
		public const int WM_RBUTTONDOWN = 0x204;
		public const int WM_MBUTTONDOWN = 0x207;
		public const int WM_LBUTTONUP = 0x202;
		public const int WM_RBUTTONUP = 0x205;
		public const int WM_MBUTTONUP = 0x208;
		public const int WM_LBUTTONDBLCLK = 0x203;
		public const int WM_RBUTTONDBLCLK = 0x206;
		public const int WM_MBUTTONDBLCLK = 0x209;
	}
	/// <summary>
	/// Hook类型
	/// </summary>
	public enum HookType : int
	{
		WH_JOURNALRECORD = 0,
		WH_JOURNALPLAYBACK = 1,
		WH_KEYBOARD = 2,
		WH_GETMESSAGE = 3,
		WH_CALLWNDPROC = 4,
		WH_CBT = 5,
		WH_SYSMSGFILTER = 6,
		WH_MOUSE = 7,
		WH_HARDWARE = 8,
		WH_DEBUG = 9,
		WH_SHELL = 10,
		WH_FOREGROUNDIDLE = 11,
		WH_CALLWNDPROCRET = 12,
		WH_KEYBOARD_LL = 13,
		WH_MOUSE_LL = 14
	}
	/// <summary>
	/// 
	/// </summary>
	[StructLayout(LayoutKind.Sequential)]
	public struct KBDLLHOOKSTRUCT
	{
		public uint vkCode;
		public uint scanCode;
		public KBDLLHOOKSTRUCTFlags flags;
		public uint time;
		public UIntPtr dwExtraInfo;
	}
	[Flags]
	public enum KBDLLHOOKSTRUCTFlags : uint
	{
		LLKHF_EXTENDED = 0x01,
		LLKHF_INJECTED = 0x10,
		LLKHF_ALTDOWN = 0x20,
		LLKHF_UP = 0x80,
	}
	/// <summary>
	/// 键盘按键事件
	/// </summary>
	public class HookEventArgs : EventArgs
	{
		// using Windows.Forms.Keys instead of Input.Key since the Forms.Keys maps  
		// to the Win32 KBDLLHOOKSTRUCT virtual key member, where Input.Key does not  
		public Keys Key;
		public bool Alt;
		public bool Ctrl;
		public bool Shift;

		public HookEventArgs(UInt32 keyCode)
		{
			// detect what modifier keys are pressed, using   
			// Windows.Forms.Control.ModifierKeys instead of Keyboard.Modifiers  
			// since Keyboard.Modifiers does not correctly get the state of the   
			// modifier keys when the application does not have focus
			this.Key = (Keys)keyCode;
			this.Alt = (Control.ModifierKeys & Keys.Alt) != 0;
			this.Ctrl = (Control.ModifierKeys & Keys.Control) != 0;
			this.Shift = (Control.ModifierKeys & Keys.Shift) != 0;
		}
	}
	/// <summary>
	/// 处理Hook的子程序
	/// </summary>
	/// <param name="code"></param>
	/// <param name="wParam"></param>
	/// <param name="lParam"></param>
	/// <returns></returns>
	public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
	/// <summary>
	/// 处理收到的消息句柄
	/// </summary>
	/// <param name="sender"></param>
	/// <param name="e"></param>
	public delegate void HookEventHandler(object sender, HookEventArgs e);
	#endregion

	/// <summary>
	/// 键盘Hook类
	/// </summary>
	public class KeyboardHook
	{
		#region 对外事件接口
		/// <summary>
		/// 按键按下事件
		/// </summary>
		public event HookEventHandler KeyDown;
		/// <summary>
		/// 按键弹出事件
		/// </summary>
		public event HookEventHandler KeyUp;
		#endregion

		#region Windows API对象
		/// <summary>
		/// 安装钩子
		/// </summary>
		/// <param name="idHook"></param>
		/// <param name="lpfn"></param>
		/// <param name="hInstance"></param>
		/// <param name="threadId"></param>
		/// <returns></returns>
		[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
		private static extern int SetWindowsHookEx(int lpcode, HookProc lpfn, IntPtr hInstance, int threadId);

		/// <summary>
		/// 卸载钩子
		/// </summary>
		/// <param name="idHook"></param>
		/// <returns></returns>
		[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
		private static extern bool UnhookWindowsHookEx(IntPtr idHook);

		/// <summary>
		/// 继续下一个钩子处理程序
		/// </summary>
		/// <param name="idHook"></param>
		/// <param name="nCode"></param>
		/// <param name="wParam"></param>
		/// <param name="lParam"></param>
		/// <returns></returns>
		[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
		private static extern int CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);

		/// <summary>
		/// 取得当前线程编号
		/// </summary>
		/// <returns></returns>
		[DllImport("kernel32.dll")]
		private static extern int GetCurrentThreadId();
		/// <summary>
		/// 获取扩展模块
		/// </summary>
		/// <param name="module"></param>
		/// <returns></returns>
		[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
		public static extern IntPtr GetModuleHandle(string lpModuleName);
		#endregion

		#region 私有成员对象
		private static IntPtr _hookHandle;
		#endregion

		/// <summary>
		/// 键盘勾子事件
		/// </summary>
		/// <param name="nCode"></param>
		/// <param name="wParam"></param>
		/// <param name="lParam"></param>
		/// <returns></returns>
		private int HookCallback(int code, IntPtr wParam, IntPtr lParam)
		{
			if (code < 0)
				return CallNextHookEx(_hookHandle, code, wParam, lParam);

			var dataStruce = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));

			//((int)dataStruce.flags & 0x80) != 0
			if (((int)wParam == WindowMessage.WM_KEYUP || (int)wParam == WindowMessage.WM_SYSKEYUP) && this.KeyUp != null)
			{
				this.KeyUp(this, new HookEventArgs(dataStruce.vkCode));
			}
			//((int)dataStruce.flags & 0x80) == 0
			if (((int)wParam == WindowMessage.WM_KEYDOWN || (int)wParam == WindowMessage.WM_SYSKEYDOWN) && this.KeyDown != null)
			{
				this.KeyDown(this, new HookEventArgs(dataStruce.vkCode));
				if (dataStruce.vkCode == 44) return 0;
			}

			return -1;
			//return CallNextHookEx(_hookHandle, code, wParam, lParam);
		}

		/// <summary>
		/// 安装钩子
		/// </summary>
		public void Install(HookType hookType, HookProc callBack)
		{
			if (_hookHandle != IntPtr.Zero)
				return;
			var _hookFunction = new HookProc(HookCallback);

			var pInstance = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
			//var pInstance =Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().ManifestModule);

			_hookHandle = (IntPtr)SetWindowsHookEx((int)hookType, _hookFunction, pInstance, 0);
			//_hookHandle = (IntPtr)SetWindowsHookEx((int)hookType, _hookFunction, IntPtr.Zero, GetCurrentThreadId());
		}

		/// <summary>
		/// 卸载钩子
		/// </summary>
		public void Uninstall()
		{
			if (_hookHandle != IntPtr.Zero)
			{
				UnhookWindowsHookEx(_hookHandle);
				_hookHandle = IntPtr.Zero;
			}
		}
	}
}
在安装全局勾子时, 因为获取了错误的窗口句柄导致无法正常的安装键盘勾子,
句柄的获取方式改成了以下的语句
var pInstance = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);  

安装局部的勾子时,用
Marshal .PtrToStructure读取非托管参数 lParam参数时,会失败, 应该是参数不正确,
估计局部的勾子的lParam参数只是一个整数,因此读成
KBDLLHOOKSTRUCT结构对象时,会报受保护的内存不能访问的错误,具体是否该原因需要进一步证明。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烈火蜓蜻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值