从N年前的微软的蹩脚的智能abc输入法到今天的各种方便的搜狗,QQ,百度输入法,我们在使用计算机的时候输入法为我们输入中文提供了极大的便利。但是我们在使用这些五花八门的输入法的时候有没有想过,这些输入法是如何将键盘的输入转换成汉字最终输出到我们想要输入的地方的?我们常常听说键盘记录,那么能否记录经过输入法处理过的中文输入呢? 想要了解这个问题,首先得了解输入法的输入原理。 首先我们要知道什么是输入法,我们经常用输入法,但是你发现一个现象没有,在任务 管理器中并没有看到输入法进程。输入法的核心文件你找到安装目录就会发现一个后缀 是.ime的文件,你用十六进制查看器看看就会发现他其实是一个类似dll的模块,当一个 进程打开输入法要输入汉字的时候其实就是载入了这个模块,如下图: ![]() 在这个模块里进行文字的接收,处理,发送。 然后,我们要摸清输入法的输入原理,这个问题我探索了好久,发现微软从windows 9x到Windows XP等NT5. 0以上版本还是有很大差别的。虽然我没有验证Windows 9X系统的输入法处理过程,但是在试验中发现关于9X的原理并不适用于NT5.0以上版本。首先看看各个版本的处理方法。 Windows 9x 系统 系统的键盘事件有windows的user.exe软件接收后,user.exe在将键盘事件传导输入法管理器(input Meth0dManager,简称 IMM)中,管理器再将键盘事件传到输入法中,输入法根据用户编码字典,翻译键盘事件为对应的汉字(或汉字串),然后再反传到user.exe中,user.exe再将翻译后的键盘事件传给当前正运行的应用程序,从而完成汉字的输入。这个是windows 9x系统下的。 windows N4.0以上系统 这个是重点,以windows xp为例。 Windows xp系统下的输入法和9x系统的输入法有很大区别,对输入法的处理完全不同。 先看一个例子: while((r=GetMessageff(&msg, 0,0,0))!=-l) { if(r==0)break; Trans1ateMessage(&msg); DispatchMessageW(&msg); } 这是一个消息循环,直到r等于0,表示有wm_quit,r=-1表示出错,是系统从消息队列中取消息的一般过程。那么输入法是怎么回事呢? 我们可以用一些工具挂钩窗口的消息来分析输入法原理,这里直接给出结论。 一般情况下GetMessage得到WM_KEYDOWN的wParam是虚拟键码,如果我们开了输入法, teMessage,WM_KEYDOWN 的 wParam 虚拟码是 VK_PROCESSKEY, TranslateK 生 WM_CHAR, WM_SYSCHAR 之类的,但是当 TranslateMessage 遇到了 VK_PROCESSKEY,就会有 特殊处理。这时候TranslateMessage就会把控制权交给DefWindowProc这个缺省的消息处理例程,DefWindowProc再通知输入法程序的窗口,把那些候选的显示出来,当你的你输入 法将接受到的虚拟码做一系列转换以后合成相应的汉字,输入法再将合成好的WM_CHAR用 PostMessage插入消息队列,edit控件接受WM_CHAR显示字符。如果你没有开输入法WM_CHAR 直接由WM_CHAR直接由TranslateMessage产生。 流程图如下: ![]() 好了,到这里大家应该明白目前常见输入法是如何工作的了,那么我们现在的目的是截 获输入法合成后的中文汉字。想必这时候思路就很明显了,我们只要做一个系统钩子,捕获输入法处理后发送到消息队列的WM_CHAR消息之后就能够实现相应的功能。但是值得注意的 是汉字是由汉字编码组成的,占两个字节,而钩子子程一次只能传送一个字节,下文我们讲 处理方法。 至于系统钩子的安装,在此我就不做过多的赘述了,这个应该是一个非常普遍的技术, 随便一本书上都能找到,我们直接看一些关键的程序段。 首先看一下钩子的安装: B00L WINAPI SetKeyHook(BOOL bInstall,DWORD dwThreadId) { BOOL bOk; if(bInstall){ g_hHook=::SetWindowsHookEx(WH_GETMESSAGE, KeyHookProc, ModuleFromAddress( KeyHookProc),dwThreadId) ;//注意这呈安装的是WH—GETMESSAGE类型钩子。应用程序 使//用 WH—GETMESSAGE Hook 永监视从 GetMessage or PeekMessage 函数返回的消 息。//你岢以使用WH—GETMESSAGEHook去监视鼠标和键盘输入,以及其他发送到消息//队列中的消息。 bOk=(g_hHook!=NULL); } else { bOk=::UnhookWindowsHookEx(g_hHook); g_hHook=NULL; _ } return bOk; } 然后我们看一下钩子子程,这个是重点。 int temp; int flag=0; LRESULT CALLBACK KeyHookProc(int nCode, WPARAM wParam, LPARAM lParam) {//各个参数的意义参看在线版的MSDN PMSG pcw=(PMSG)lParam; |