IME 输入法 VC 编程的详细解说
初探 WINDOWS 下 IME 编程
IME 编程心得
第一章 Windows9x 系统下汉字输入法的基本原理
第二章 Windows9x 系统提供的 ime 管理函数
第三章 ime 文件中必须使用的结构
自由拼音输入法的测试
输入法程序[ime]的调试方法
输入法(IME)实现原理
初探 WINDOWS 下 IME 编程
大家知道,DELPHI 许多控件有 IME 属性。这么好用的东西 VC 可没自带,怎么办呢?其
实,可通过注册表,用 API 实现。下面说一下本人对 IME 的研究结果,并提供示例工程供
大家参考:
1、将用到的 API
Cpp 代码
1. RegOpenKey:打开注册表一键
2. RegQueryValue:查询一键值
3. RegQueryValueEx:同上
4. RegCloseKey:关闭打开的键
5.
6. LoadKeyboardLayout:装载输入法
7. ActivateKeyboardLayout:激活输入法
2、IME 信息在注册表中的位置
在 HKEY_USERS:".DEFAULT\keyboard layout\preload"放的是已安装的输入法,下有几
个以数字为名的子键,内容是输入法代号(keyboard layout),如"e0040804",其中左 4 位是
设备代码(device identifier),右 4 位是语言代码(language identifier)。例如上面:左 e004
指智能 ABC,右 0804 指大陆中文。(详见 MSDN)
在 HKEY_LOCAL_MACHINE:"System\CurrentControlSet\Control\Keyboard Layouts\"放
的是已注册的输入法。他的子键名为输入法代号(keyboard layout),内容为该输入法的
ime 文件,名称等信息。
3、主要思路
我们可先把已装的输入法枚举出来(从注册表),用户选择其一后,再激活该输入法。
两关键函数:
HKL LoadKeyboardLayout(LPCTSTR pwszKLID,UINT Flags);
第一个参数是待打开的输入法代号,如"e0040804"(智能 ABC);
第二个参数是标志位,如 KLF_ACTIVATE(激活)。
HKL ActivateKeyboardLayout(HKL hkl,UINT Flags);
第一个参数是打开的输入法句柄(由 LoadKeyboardLayout 返回);
第二个参数是标志位,如 KLF_SETFORPROCESS。(详见 MSDN)
4、例子程序
新建一基于对话框的工程,加入一 combobox 控件,增加控制变量 m_cb1。加入一 edit 控
件,增加控制变量 m_edt1.对 combobox,增加对 CBN_SELCHANGE 的映射函数
OnSelchangeCombo1()。对 edit1,增加对 EN_SETFOCUOS 的 SetfocusEdit1().在对话
框类头文件的 public:下加入数组声明:CString lst[10];
在 OnInitDialog()的 return 前加如下代码:
Cpp 代码
1. HKEY hk,hk1;
long cp=16;
2.
3. char lp[15];
4. char a[2];
5. a[0]='1';
6. a[1]='\0';
7. CString str,str1;
8. str=".DEFAULT\\keyboard layout\\preload\\";//已装的输入法。注:win2000 有所不
同
9. str+=a;
10. int i=0;
11. while(::RegOpenKey(HKEY_USERS,str,&hk)==ERROR_SUCCESS)//打开键
12. {
13. a[0]++;//下一子键
14. str=".DEFAULT\\keyboard layout\\preload\\";
15. str+=a;
16. if(::RegQueryValue(hk,NULL,lp,&cp)!=ERROR_SUCCESS)//已装的输入法
17. MessageBox("Error");
18. ::RegEnumKeyEx
19. str1="System\\CurrentControlSet\\Control\\Keyboard Layouts\\";//keyboardlay
outLayout
20. str1+=lp;
21. lst[i++]=lp;
22. //打开对应的 keyboardlayoutLayout
23. if(RegOpenKey(HKEY_LOCAL_MACHINE,str1,&hk1)==ERROR_SUCCESS
)
24. {
25. LPBYTE lpD=new BYTE[80];//DataValue
26. DWORD lpT=REG_SZ;//DataType
27. DWORD lpS=80; //DataSize
28. if(RegQueryValueEx(hk1,"Layout text",NULL,&lpT,lpD,&lpS)!=ERROR_SUC
CESS)
29. MessageBox("Query error",(LPCTSTR)lpD);
30. m_cb1.AddString((LPCTSTR)lpD);
31. delete lpD;
32. }
33. else MessageBox("open error");
34. RegCloseKey(hk1);
35. }
36. ::RegCloseKey(hk);
37. m_cb1.SetCurSel(0);
在 OnSetfocusEdit1()加入如下代码:
Cpp 代码
temp=m_cb1.GetCurSel()!=CB_ERR?st[m_cb1.GetCurSel()]:"00000409";
1. CString temp;
2.
3.
4. HKL hkl;
5. hkl=LoadKeyboardLayout(temp,KLF_ACTIVATE);//装载输入法
6.
7. ActivateKeyboardLayout(hkl,KLF_SETFORPROCESS);//激活输入法
if(hkl==NULL) OnOK();
在 OnSelchangeCombo1()加入如下代码:
Cpp 代码
1. m_edt1.SetFocus();
即可编译运行。
5、注意:win2000 下有所不同。注册表 HKEY_USERS:".DEFAULT\keyboard
layout\preload 没有子键只有以数字为名的项,值为输入法代号(keyboard layout)。在示例
代码中不仅提供了 WIN 9X 下的代码,也提供了 2000 下的相应代码段,具体请参考示例
工程。
IME 编程心得
一、基础知识:(不断补充)
1.输入法管理器(IMM)
2.输入法编程器(IME)
3.输入上下文(IC)
4.应用程序(App)
二、IMM-IME 结构的基本工作过程及特点
用户键盘消息->系统通过 IMM 传递给与当前线程对应的 IME->IME 根据输入的消息和输入
上下文中记录的数据,将用户的键盘动作转换成结果串->以字串消息的形式返回给 IMM->
放到应用程序窗口的消息队列中。
三、IME 的构成
1.IME 转换接口(IME conversion interface)
2.IME 用户接口(IME user interface)
由用户实现的一组窗口,这些窗口用来接收和处理由 IMM 发来的输入消息,提供与用户交互
的界面.由下面的窗口组成:
1)缺省的 IME 窗口(Default IME window)
2)用户接口窗口(UI interface)
3)用户接口窗口的组件:状态窗口(status window);编码窗口(compsition window);候选窗口
(candidate window).
4)软键盘和系统菜单/图标等
四、IME 的实现
1.IME 转换接口的实现
这些接口函数在供管理器在适当的时候调用.这些函数并非每个都要进行自己的处理,大部
分保留一个空函数即可,但没有却不可.系统默认是要调用的,找不到就不行.有以下函数:
1)ImeInquire
2)ImeConfigure
3)ImeProcessKey
4)ImeToAsciiEx
5)ImeSelect
6)ImeSetActiveContext
7)NotifyIME
8)ImeDestroy
9)ImeConversionList
10)ImeEscape
11)ImeSetCompsitionString
12)ImeRegisterWord
13)ImeUnregisterWord
14)ImeGetRegisterWordStyle
15)ImeEnumRegisterWord
2.IME 用户接口的实现
主要包括用户接口窗口(窗口类和窗口过程),用户界面窗口的组件(状态窗口,编码窗口和候
选窗口的窗口类和窗口过程),输入法的配置窗口,软键盘,任务条上的指示器窗口(图标,菜单,
工具提示)和输入法热键等.
1)用户接口窗口:编程中主要是处理由缺省的 IME 窗口传入的 IME 消息,当然,并非所有的
IME 消息都需要给出具体处理(可以看出这是 IME 编程中的一个原则).如:
WM_IME_COMPOSITION
WM_IME_STARTCOMPSITION/WM_IME_ENDCOMPOSITION
WM_IME_SELECT
WM_IME_NOTIFY
WM_IME_CHAR
五、具体实现步骤:
IME 实质上是一个 DLL 实现,由系统调用。而这个 DLL 则分别实现了系统要调用的功能
函数。所以有些函数虽然不做什么事情,但是必需挂上一个空壳。否则调用出错。
1.DLLMain()的架构
1)进入进程
DLL_PROCESS_ATTACH 事件中,注册用户接口窗口类及其组件的窗口类:使用
RegisterClassEx()完成此注册过程。设置类名字段(lpszClassName)为用户接口窗口类类
名(包括结束标志'\0'在内最长可达 16 字符),在类风格(style)字段中必须包括 CS_IME
风格。设置附加内存大小(cbWndExtra)。
2)退出进程
注销上述与输入法编辑器有关的窗口类,进行全局性的清理工作。
2.打开/关闭输入法编辑器时进行的初始化操作
1)用户接口窗口是由缺省的 IME 窗口在接到 WM_IME_SELECT 消息时创建的。输入法管
理器通过调用 ImeRequire 接口函数获取输入法编辑器的相关信息(属性、用户接口窗口
类,可选项),据此进行输入法编辑器的初始化工作,创建输入法编辑器的用户接口窗口。
所以 ImeRequire 是输入法转换接口必须实现的第一个函数。
2)在用户接口窗口被创建后,可以进行输入法编辑器全局性的一些初始化工作,比如申请
自己的私有内存,建立私有上下文等,这些工作一般在处理 WM_IME_SELECT 消息或在
接口函数 ImeSelect 中进行,也可以在窗口过程处理 WM_CREATE 消息时进行。
3.进入进程后:
1)初始化词库
2)创建字体
3)注册窗口类
4.在 UI 窗口建立后,建立写作窗口和候选窗口
各个窗口下进行各自的消息函数处理
在这里有疑问:UI 窗口是什么?UI 窗口处理了 IME 的好多消息.--解答参看<<基于 IMM-IME
输入法接口的实现方法>>
下一个任务:看这个论文
UI 窗口是对用户不可见的,但是它是所有用户界面窗口的组件窗口的父窗口,是全部组件窗
口的管理者.
5.构建框架的问题
在 projects-settings-c/c++-catagory:prepossessor:additional include directories:./
避免添加系统默认的头文件
6.注意的细节问题:
1)global.c 中的#pragma data_seg(".zhenhuadic"),应详细了解其作用,其与 Czh.def 中的定
义有相关联的地方.(对我们的工程名 Czh 来说)
2)freepy.exp : warning LNK4070: /OUT:Czh.ime directive in .EXP differs from output
filename;C:\WINDOWS\system32\freepy.ime; ignoring directive
对于这个 BUILD 中的错误,关联之处在于 Czh.def 中定义了 lib 的输出名为 Czh,要求这个
lib 的输出名与 Output file name freepy 相同.
3)如果.ime 名和上述 2)中说的问题没有的话,且 freepy.h(原工程)中的#define
FREEPYFILENAME _T("freepy.ime")定义正确,则在 HZfreepy.h 中改变以下几个文件名
与 C:\windows\system32\(window xp 系统下)下的相关文件名相同则可:
freepy.tab--字库
freepysys.dic--系统词库
freepyusr.dic--用户词库
4)在 ImeSelect 的函数中,有个注册表键值的处理与工程有关联
5)有四条消息的遗漏: