IME输入法编程心得
原文链接: IME输入法编程心得
posted @ 2012-11-30 00:42 from [FreedomShe]
自然语言处理的输入法作业成品没有做出来,但不想再在蛋疼的Win32上面耗费时间了,整理文档,记录一下心得,新手再来研究也不会迷路太远。
1. IME简介
2. IME结构
3. IME调试环境配置及安装
3.1. 配置步骤
3.2. 配置说明及注意事项
3.3. IME安装及卸载
4. IME编程心得
4.1. 准备工作
4.2. IME数据结构介绍
4.3. IME接口调用顺序
4.4. 感想
1 IME简介
什么是IME (Input Method Editors)?广义上讲,IME是微软提供的Windows平台的一套输入法编程规范,依照这套规范(框架),你不需要处理太多输入法特性相关的操作(光标跟随,输入捕获,字码转换后输出到应用程序等),你只需要使用IME规范里面提供的工具函数(imm32库),实现规范所指定必须导出的接口即可。实际上你要做的就是写一个导出函数包含IME规范规定的接口的dll,所以,狭义上讲IME就是你写的这个dll。
IME源于Windows 95和Windows NT 4.0时代,用于统一Windows系统输入法编程规范,随着Windows系统版本更新换代,IME的结构基本没有改变。作者所能找到的最新IME官方文档为Windows 98/Windows 2000版,原始文档位于Windows98DDK内(《Win32 Multilingual IME Overview for IME Development》和《Win32 Multilingual IME Application Programming Interface》)。
2 IME结构
如前文所述,狭义IME开发就是实现类似“输入法名字.ime”这样一个动态库(编译的时候通常将.dll后缀改为.ime后缀)。这个库需要导出如下15个接口函数:
而这些函数中很多都是不重要的,进行编程的时候可以不去具体实现。
3 IME调试环境配置及安装
3.1 配置步骤
第二步:配置IDE。编译上述源码,发现170个错误,是没有配置imm.h和imm32.lib路径所致。在项目属性->VC++目录->包含目录下面添加源码文件夹下的IMM文件夹路径(包含imm.h和imm32.lib)。编译成功。
第三步:imesample.ime安装程序制作。创建Win32控制台应用程序命名为IMEInstaller,将imm.h和imm32.lib拷贝到该工程目录下,修改主函数代码为:
// IMEInstaller.cpp : 定义控制台应用程序的入口点。 //#include "stdafx.h" #include <Windows.h> #include "Imm.h" #pragma comment(lib,"imm32.lib") int _tmain(int argc, _TCHAR* argv[]) {HKL IME = ImmInstallIME(L"imesample.ime", L"我的输入法");if(IME==0){printf("注册输入法失败,请注销(或重启)计算机再试验!\n");}else{printf("注册输入法成功!\n");}printf("按任意键退出!\n");getchar();return 0; }
主要是添加Windows.h和Imm.h头文件(顺序不能颠倒,因为imm.h需要依赖前一个文件的定义)和引用imm32.lib,从而使用ImmInstallIME函数注册输入法。
第四步:安装imesample.ime。编译上一步的安装程序,得到“IMEInstaller.exe”可执行程序,将其拷贝到imesample工程编译结果imesample.dll所在目录,将imesample.dll重命名为imesample.ime,然后运行IMEInstaller.exe,如果显示注册成功的结果则安装成功,你能在输入法选择里面看到你刚注册的输入法了,如下图中“我的输入法”。
如果注册失败,重启计算机也无法解决,原因有几种可能,在后面的说明中解释。
第六步:配置调试程序。打开imesample工程,找到项目属性->调试->命令项,将上一步记下的调试程序路径填入其中,如下图。
以后修改代码,直接调试即为最新代码效果(系统能在你的工程目录下找到最新版本dll并加载?非也,看后文解释)。
3.2 配置说明及注意事项
1) 编译生成imesample.ime(假设直接生成的就是.ime后缀的文件)
2) 然后将imesample.ime拷贝到C:\Windows\System32\目录(如果你是64位系统,必须拷贝到SysWOW64目录下,因为64位系统只从SysWOW64中寻找输入法库文件)
3) 用ImmInstallIME函数注册输入法时,必须保证SysWOW64和注册函数所在目录都有imesample.ime库文件,否则无法注册成功。可以重复注册多次,但只在注册表添加一条记录。
3.3 IME安装及卸载
上一节介绍了使用imm32.dll内的ImmInstallIME函数安装输入法的方法,实际上这个函数只是在注册表内添加了两条记录。
第一条记录位于HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\在展开项中,以0804结尾的是简体中文输入法项目,一般新注册的输入法都在最后面,如图,我们注册的输入法注册表编号为E02C0804。
另外一条记录位于HKEY_CURRENT_USER\Keyboard Layout\Preload下,表示当前输入法选择菜单中列出的输入法列表,如下图。
所以,输入法的卸载就是安装的逆过程:删除上述两条注册表项目,然后删除System32 (SysWOW64)下的ime库文件即可。
4 IME编程心得
本文中提到的很多别人的文档都记录了自己进行IME编程的一些心得体会,在这里我就不作额外介绍了,只是做一下整理和补充。
4.1 准备工作
4.2 IME数据结构介绍
tagINPUTCONTEXT是IME最重要的内部数据结构,存储输入上下文数据,定义如下:
typedef struct tagINPUTCONTEXT {
DWORD dwNumMsgBuf;
HIMCC hMsgBuf;
DWORD fdwInit
DWORD dwReserve[3];
} INPUTCONTEXT;
可以认为它是IME内部数据的根节点,通过它可以读写IME内部所有信息,它由HIMC句柄表示,可以通过LPINPUTCONTEXT lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);的形式通过HIMC句柄获取该结构体。这里要提到的是hCompStr和hCandInfo两个变量,他们都是由HIMCC句柄表示,hCompStr负责用户输入字符串的信息,hCandInfo负责候选码部分的信息,将在后面介绍。
tagCOMPOSITIONSTR是负责管理用户输入字符串信息的结构体,为tagINPUTCONTEXT的子节点,定义如下:
typedef struct tagCOMPOSITIONSTR {
DWORD dwSize;
DWORD dwCompReadAttrLen;
DWORD dwCompReadAttrOffset;
DWORD dwCompReadClsLen;
DWORD dwCompReadClsOffset;
DWORD dwCompReadStrLen;
DWORD dwCompReadStrOffset;
DWORD dwCompAttrLen;
DWORD dwCompAttrOffset;
DWORD dwCompClsLen;
DWORD dwCompClsOffset;
DWORD dwCompStrLen;
DWORD dwCompStrOffset;
DWORD dwCursorPos;
DWORD dwDeltaStart;
DWORD dwResultReadClsLen;
DWORD dwResultReadClsOffset;
DWORD dwResultReadStrLen;
DWORD dwResultReadStrOffset;
DWORD dwResultClsLen;
DWORD dwResultClsOffset;
DWORD dwResultStrLen;
DWORD dwResultStrOffset;
DWORD dwPrivateSize;
DWORD dwPrivateOffset;
} COMPOSITIONSTR;
该结构体可以通过LPCOMPOSITIONSTRING lpCompStr = (LPCOMPOSITIONSTRING) ImmLockIMCC(lpIMC->hCompStr)的方式从HIMCC句柄中取得。其中dwCompStrLen和dwCompStrOffset分别表示用户输入字符串的长度和偏移量(即lpCompStr首地址+ dwCompStrOffset值指向的内存地址为用户输入字符串存放位置的首地址)。
tagCANDIDATEINFO是负责管理候选码信息的结构体,为tagINPUTCONTEXT的子节点,定义如下:
typedef struct tagCANDIDATEINFO {
DWORD dwSize;
DWORD dwCount;
DWORD dwOffset[32];
tagCANDIDATELIST用于存储码表数据,是上面tagCANDIDATEINFO的子节点,定义如下:
typedef struct tagCANDIDATELIST {
DWORD dwSize; // the size of this data structure.
DWORD dwStyle; // the style of candidate strings.
DWORD dwCount; // the number of the candidate strings.
DWORD dwSelection; // index of a candidate string now selected.
DWORD dwPageSize; // the preference number of the candidate strings shows in one page.
// TCHAR chCandidateStr[]; // the array of the candidate strings.
该结构体存储了一张候选码表的字符串信息,dwCount为候选码个数,dwOffset[i]为第i个候选码的首地址偏移量,同样通过偏移量加结构体首地址的方式可以定位到候选码字符串的首地址。
通过上述结构体,已经可以在ImeToAsciiEx函数内做字码转换的操作了(主要是存取用户输入字符和修改转换后的候选码表),然后在用户输入窗口和候选码窗口分别从上述结构体中取出对应字符串显示出来。
4.3 IME接口调用顺序
4.4 感想
IME输入法编程心得相关推荐
- IME输入法编程:第一章 Windows9x系统下汉字输入法的基本原理
IME输入法编程 第一章 Windows9x系统下汉字输入法的基本原理 Windows系统下汉字输入法实际上是将输入的标准ascii字符串按照一定的编码规则转换为汉字或汉字串,进 入到目的地. 由于应 ...
- IME输入法编程 第一章
Windows9x系统下汉字输入法的基本原理 2006-01-14 作者 不祥 Windows9x系统下汉字输入法的基本原理 Windows系统下汉字输入法实际上是将输入的标准ascii字符串按照一定 ...
- (转)VC IMM/IME输入法编程
输入法编辑器篇 输入法编辑器(IME)是允许用户使用标准键盘输入复杂字母与符号,如日文汉字的程式.本文描述创建及管理IME(input method editor)视窗的方法. 1.输入法编辑器简介 ...
- c语言编程心得,C语言编程心得
记录这些是为了日后自己想查阅以前经验的方便,同时若能给其他网友带来一些帮助,就更好了~ C语言,自己经常遇到的问题: 1.段错误 段错误一般是由于访问了不存在的地址造成的,具体的原因有文件路径不存在, ...
- 输入法编程相关资源汇集-欢迎补充
本文可以任意转载,转载时请务必以超链接形式标明文章原始出处 在这里向一些付出工作的同志们和网站站长抱歉,有些资源是我直接保存的,现在有些网站打不开让我不能够贴上链接了,如果发现有损你们的利益,给我来信 ...
- 输入法编程相关资源汇集
http://www.cnblogs.com/realfun/archive/2005/03/28/127152.aspx 本文可以任意转载,转载时请务必以超链接形式标明文章原始出处 在这里向一些付出 ...
- Win32 IME 编程心得【转】
一些术语 IME: Input Method Editor/Engine, 输入法编辑器, 引擎 IMM: Input Method Manager, 输入法管理器 Comp: Composition ...
- Win32输入法编程技术的分析研究
作者:新疆大学 巴力登 陆莲芳 [摘要]本文论述了Win32输入法编程技术的基本原理.技术要点及其实现的方法. 并分析研究了基于IMM-IME结构的输入法的构成.接口.设计方法与核心技术问题. [关 ...
- VC++ 输入法编程
一直想写一点关于输入法编程的东西,今天终于有点时间,希望对后来者有点帮助.在此要特别感谢"自由拼音"的作者李振春,我刚开始的几个问题都是在他的帮助下才解决. 首先我们需要明白输入法 ...
最新文章
- 2020下半年新机最新消息_2020年下半年新机看点汇总:最看好的还是麒麟1020处理器!...
- oracle index contention,Index Contention等待
- html输入框点击后去掉默认文字颜色,input的一些默认样式的更改
- 鸿蒙系统的全面开源,华为:打造全球的操作系统,鸿蒙今日全面开源!
- Anaconda自带Python编译器Jupyter Notebook显示代码行数
- jsp项目放入宝塔windows环境_商业裂变,之项目技术实战(第八节:宝塔面板介绍)...
- This function has none of DETERMINISTIC, NO SQL解决办法
- 【伙伴故事】一盏智能灯,点亮家庭和工业照明的新未来
- mysql 吧库下的表名都加_MySQL 数据库名、表名、字段名大小写敏感记录
- 跨域访问被禁止的演示示例
- bzoj 4316: 小C的独立集(仙人掌树形DP)
- Bootstrap-按钮
- Unable to open log device '/dev/log/main' : No such file or directory it ...
- nginx代理php不能跳转页面,nginx 解决首页跳转问题详解
- 易语言的Java皮肤_易语言软件更换皮肤的方法
- 用iPad编写C/C++代码(计算机考研党也能用iPad写算法题)
- 培训对于微软MCSA认证2011
- windows域用户切换本地用户
- Android 简单实现圆形ImageView添加双层圆形边框
- 分享一个国内可用的免费ChatGPT网站
热门文章
- pythonsparkfilter_python中的map、filter、reduce函数
- 洛谷——P1830 轰炸III
- 洛谷——P1010 [NOIP1998 普及组] 幂次方
- 微信小程序文本溢出省略号(···)
- 循环匹配对应筛选(2)
- 数据结构与与算法之插入排序
- *与**在python中的使用
- linux 6.5端口开启关闭,linux CentOS6.5 防火墙(关闭除提供系统服务以外的端口)...
- 海森堡不确定性原理实验
- Qt学习之路(60): 创建shared library