BOOL WINAPI ImeSelect(HIMC hIMC,BOOL fSelect)
在这个接口中,系统通知输入法当前是否打开了输入法输入。一般输入法启动时会调用一次,在一些软件(如EmEditor)中提供打开与关闭输入法的功能就是通过这个接口实现的。如果打开输入法,一般会在这个接口中做一些数据的初始化工作。
BOOL WINAPI ImeProcessKey(HIMC hIMC,UINT uKey,LPARAM lKeyData,CONST LPBYTE lpbKeyState)
观察注释您可以看到在个接口是用来判断用户敲击的哪个键需要处理,哪个键又应该交给系统自己处理,如果输入法需要自己处理用户输入的键,则在这个接口中返回true,否则返回false。
UINT WINAPI ImeToAsciiEx (UINT uVKey,UINT uScanCode,CONST LPBYTE lpbKeyState,LPDWORD lpdwTransKey,UINT fuState,HIMC hIMC)
这个接口可以说是输入法最重要的部分,程序员需要在这个接口中实现编码与重码的转换,转换完成或者显示在编码窗口及重码窗口,或者发送到应用程序。由于在 这个接口中没有传入窗口句柄,如果通知输入法程序的窗口更新显示呢?当然我们可以使用全局变量,在此我个人推荐的方法是使用IME消息(没有什么道理), 您将消息类型、参数保存到lpdwTransKey指示的缓冲区中,User.exe会根据消息类型做相应的处理并传递到UIWnd这个窗口中。
那么如何输入文字呢?要输入文字需要3个消息配合使用,分别是WM_IME_STARTCOMPOSITION、 WM_IME_COMPOSITION和WM_IME_ENDCOMPOSITION,它们分别指示开始输入编码,输入编码或者结果(视参数而异)及编码 输入完成。在开始编写输入法的时候,为了省事,我的输入法在用户确定要输入一个重码时才连续调用这3个消息以向编码器中输入文字。由于 WM_IME_STARTCOMPOSITION和WM_IME_ENDCOMPOSITION需要成对使用,这种方法可以确保它们配对。最初这种方式工 作得很好,但是后来发现在一些软件中出现兼容性问题。如“智能五笔”在“遨游”中就存在这个问题,在“遨游”中的地址栏中打开“智能五笔”,当需要使用回 退键来删除错误输入的编码时,会发现删除的不是编码窗口中的编码而是编辑器中的文字。这是因为类似“遨游”这类软件主动接管了按键输入如处理一些控制键, 当它发现这些控制键不在WM_IME_STARTCOMPOSITION和WM_IME_ENDCOMPOSITION这两个消息之间时就自己处理控制键 而不是先交给User.exe了。因此正确的流程应该是在开始输入编码时发送WM_IME_STARTCOMPOSITION,输入结束后发送 WM_IME_ENDCOMPOSITION消息。
LRESULT WINAPI UIWndProc(HWND hUIWnd, UINT message,WPARAM wParam, LPARAM lParam)
这是一个非常重要的接口,基本上一它负责各种消息的传递。一般您需要在这个接口中根据不同的消息类型,实现输入法窗口(如编码窗口、重码窗口、状态栏窗 口)的显示、隐藏及更新等操作。这个接口实现的功能可能非常复杂,视情况而异,在此就不做更加深入的说明了。在使用时可以参见示例工程。
BOOL WINAPI ImeConfigure(HKL hKL,HWND hWnd, DWORD dwMode, LPVOID lpData)
这是最后一个需要注意的接口,在显示输入法属性配置时会Windows会调用这个接口。
基本的接口就介绍到这里,下面谈一谈我个人在编写输入法程序时遇到的一些问题或者发现的一些需要注意的地方。
1、 关于输入法窗口:阅读一些输入法的代码会奇怪,为什么输入法窗口在创建时需要指定WM_DISABLE属性呢?原来是因为如果不指定这个属性标志,在打开 输入法时,会导致当前的应用程序失去输入焦点。但是指定了这个标志后,输入法窗口不能收到鼠标消息怎么办?解决的方法就在于WM_SETCURSOR这个 消息。这个消息不管窗口是否可用,只要有鼠标在窗口内窗口都会收到。您可以在这个消息中模拟鼠标消息也可以选择调用SetCapture这个函数,这样窗 口就可以收到鼠标消息了。
2、关于窗口模式:使用了几种输入法后,你会发现,有的输入法的编码窗口和重码窗口 是一个窗口,有的又是两个窗口,它们有什么区别?或者有的人会觉得这个问题很可笑,但是当您研究了一段输入法可能就会发现您也有类似的问题:因为在输入法 的导出接口中关于用户界面的函数就有4个,其它3个分类对应3个窗口回调函数。事实上它们并没有本质的区别,关键在于您的输入法的使用范围。一些软件(如 某些游戏)为了界面的整体美观,不希望用户在打开输入法时显示输入法自己的窗口,而是希望输入法按照它的意愿将输入法窗口需要显示的内容显示在它创建的窗 口中,英文称之为IME Aware。由于我自己的输入法目标不是在游戏中使用,所在并没有按照这个规矩来管理输入法窗口,而是为了简化,将编码窗口和重码窗口显示的内容放到了一 个窗口中。
3、关于自定义消息:UIWndProc在WM_IME_NOTIFY中提供了一个 IMN_PRIVATE,最初我理解为这个消息应该和WM_USER一样,当我需要不只一人自定义消息时只需要在这个ID的基础上增加值就好了。但事实是 您定义的值可能是系统已经占用的(视Windows的版本而异),您能够使用的自定义消息应该只有这一个,为了指示多个消息类型,我使用的方法是在 WM_IME_NOTIFY的LPARAM中进行区分。
4、调试信息输出:一般编写输入法都不会使用MFC, 为了输出调试信息,一般只能使用OutputDebugString这个API,在示例代码中的helper.c中我编写了一个模拟TRACE的函数 Helper_Trace,您可以用这个函数来将调试信息输出到调试窗口。
5、最后再谈一谈输入法类型:前面 提到输入法分为外挂式和IME两种,但是目前一些输入法发展了第3种类型,那就是结合这两种类型的优点。例如拼音加加,启动拼音加加您会发现进程列表里会 多一个拼音加加的服务进程,其实它才是拼音加加输入法的内核即数据处理部分。拼音加加的IME部分只是一个外壳,它提供传统的IME输入法一样的系统兼容 性。在我的输入法中也采用了这种结构,使用内存文件映射及普通的Windows消息结合来实现两个进程间的通讯。您可以在我的输入法的源代码中找到进程间 的通讯源代码及输入法代码。
好象没有更多的经验可言,总之,输入法其实并不神秘,在我看来,只要能够在VC中跟踪代码,我就不相信我会搞不定它!
关 于示例代码:示例代码是我编写的一个最基本的输入法程序的框架,它显示您输入的编码,并显示一个固定的重码,输入空格后实现该重码上屏的功能。通常我们能 找到的代码是一个完整的工程,这样对于初学输入法编程的人可能会陷入大量的非输入法编码框架的阅读中,对于实际的输入法编程并没有多大的意义。这份代码就 是为了让您摆脱那些无谓代码的阅读。
如果需要更加完整的输入法代码,推荐参考“自由拼音”的源代码,当然也可以参考我写的输入法《启程输入之星》的代码,您可以在我的网站上找到下载,http://www.setoutsoft.cn。这份代码的界面部分我自认为是当前的输入法中写得非常出色的。