原文:Win7 64位系统,使用(IME)模式VS2010 编写 和 安装 输入法 教程(1)

首先感谢:
http://blog.csdn.net/shuilan0066/article/details/6884483输入法 编程分析
http://blog.csdn.net/mspinyin/article/details/6141599输入法的注册、安装和卸载
http://www.setoutsoft.cn/Html/?256.html 浅谈输入法编程
http://wenku.baidu.com/view/3d179422bcd126fff7050b9d.html输入法漫谈

这些文章作者的无私奉献。

TSF(Text Service Framework)WIN7

写这篇文章的动机是:由于Win7 64 位系统的普及,按照上面这些文章来编写自己的输入法会遇到很多意想不到的问题。至今网络上没有找到现成详细的解决方案。我通过一周的摸索和总结,深知靠自己摸索编译成功并安装一个可以在win7 64位系统下运行的输入法是多么的艰难。 特将自己的经验拿出来和大家分享。

编写输入法有几种方式,如外挂式,IME式,TSF式,今天我们主要介绍IME式( 输入法接口式(Input Method Editor-IME))

1,输入法是什么东西? 
编写输入法其实就是编写一个DLL ,一个导出一些操作系统约定函数的DLL,操作系统通过这些函数和我们的程序交互,将用户输入的编码转换成汉字通过消息传送给应用程序(如记事本,word,)。用现在的话来说就是实现一个“接口”。

(1)操作系统如何和我们的Dll交互呢?



(2)我们编写的这个Dll就是IME




输入法工作原理 如下图:



(上图来自于:http://blog.csdn.net/shuilan0066/article/details/6883629 输入法工作原理)

2,具体我们应该做哪些工作呢?
(1)首先编写一个DLL,导出IME规定的函数。
注意这个DLL除了必须导出IME规定的函数外,还要满足如下条件。

包含一个.rc 的资源文件。包含一个Version资源

如下图划红线的部分必须设置成:FILETYPE : VFT_DRV FILESUBTYPE : VFT2_DRV_INPUTMETHOD 

否则输入法无法加载。


(2)如何导出这些函数呢?
通过def文件导出函数。然后如下图设置。 使用def文件导出dll函数的好处是,导出的函数名不会变化。

 


(3)要导出哪些函数,这些函数有什么用呢?
IME要求导出的有十几个函数。可真正重要的只有几个。
输入法初始化:

ImeInquire: 刚选择某输入法时,IMM调用此函数,获得输入法相关信息

BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo,LPTSTR lpszUIClass,LPCTSTR lpszOption)

{

if (!lpIMEInfo) return (FALSE);

lpIMEInfo->dwPrivateDataSize = 0;

lpIMEInfo->fdwProperty = IME_PROP_KBD_CHAR_FIRST | 

#ifdef _UNICODE

IME_PROP_UNICODE |

#endif

IME_PROP_SPECIAL_UI |

IME_PROP_END_UNLOAD; //会让输入法随应用程序的退出而退出,这个在调试程序的时候特别重要,我们重新编译了程序就无需

//重启电脑,就可以更换输入法程序,进行调试。

lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE;

lpIMEInfo->fdwSentenceCaps = IME_SMODE_NONE;

lpIMEInfo->fdwUICaps = UI_CAP_2700;

lpIMEInfo->fdwSCSCaps = 0;

lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;

_tcscpy(lpszUIClass, UICLASSNAME);

return TRUE;

}

ImeSelect: 打开或关闭输入法时被调用,在此函数中对输入法上下文进行初始化或恢复释放,

在打开输入法时 fSelect为TRUE, 在关闭输入法时fSelect为FALSE

将键盘消息转换为相应汉字:
ImeProcessKey :处理键盘消息:
IMM通过此函数,对键盘消息进行分类筛选,一类可以直接发给应用程序,一类需要发送给IME进行转换
 ,返回值为FALSE,说明键盘消息被直接发送给了应用程序; 返回值为TRUE 说明键盘消息被发送给了IME,被发送IME后,IMM会立即调用ImeToAsciiEx对键盘消息进行转换。

ImeToAsciiEx :输入法编程最重要部分----- 此函数将进过ImeProcessKey 筛选,通过IMM传递过来的键盘消息转换为composition写作窗口中的字符串,然后再查找码表,更新候选窗口,最后选择某候选字符作为最终结果,通过消息传递给应用程序。

(4)我们的输入法怎么显示和更新写作窗户,候选窗口,怎么把用户选择的汉字传递给应用程序,通过什么机制呢?
写作窗口:就是显示和编辑用户输入字符串的窗口,比如输入的是拼音


侯选窗口:就是显示符合用户输入编码的汉字,供用户选择。通常写作窗口和获选窗户可以合二为一。

首先我们要了解两个概念:

<1>UIWnd 和UIWndProc

<2>输入法上下文(HIMC)

我们都知道windos是通过消息来运作的,要显示,更新 输入法的写作和候选窗口,就需要有消息循环。

而输入法是一个插件,他需要依靠应用程序中用户的输入消息,来控制输入法写作和候选窗口的显示和更新。
可应用程序的消息怎样才能传递给输入法呢?
IME要求我们自建的输入法dll导出一个接口,原型如LRESULT WINAPI UIWndProc(HWND hUIWnd, UINT message,WPARAM wParam, LPARAM lParam),

而User.exe(一个系统进程) 会创建一个UIWnd ,这个窗口不会显示,就是它充当应用程序和输入法之间windos消息的传递。在这个窗口的消息循环中会调用我们输入法dll导出的接口:UIWndProc。 传递过来的HWND hUIWnd 就是这个窗口的句柄,它是输入法中创建的窗口如写作窗口,候选窗口的宿主(Owner)。

上面我们说了应用程序怎么把消息传递给输入法,下面我们说说输入法怎么把它的消息和数据传递给应用程序?
User.exe(一个系统进程) 会为应用程序分配一片内存,而HIMC就是这片内存的句柄,我们称之为输入法上下文。我们将输入法要传递给应用程序的消息和数据存入这片内存,再由User.exe 传递给应用程序。

下面我们我简单介绍一下消息和数据传递的具体方法。
首先要获得HIMC,通过UIWnd的句柄g_hUIWnd 使用ImmLockIMC

HIMC hIMC = (HIMC)GetWindowLong(g_hUIWnd, IMMGWL_IMC);

*lpIMC = (LPINPUTCONTEXT)ImmLockIMC(*hIMC)

然后向HIMC中写入消息

if (IsWindow(lpIMC->hWnd))

{
LPTRANSMSG lpTransMsg;

if (!(lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf,(lpIMC->dwNumMsgBuf+1) * sizeof(TRANSMSG))))

goto Error;

if (!(lpTransMsg = (LPTRANSMSG)ImmLockIMCC(lpIMC->hMsgBuf)))

goto Error;

//将消息写入HIMC中

lpTransMsg += (lpIMC->dwNumMsgBuf);

lpTransMsg->message=message;

lpTransMsg->wParam=wParam;

lpTransMsg->lParam=lParam;

lpIMC->dwNumMsgBuf++;
ImmUnlockIMCC(lpIMC->hMsgBuf);

//将消息发送到IME,IME再决定是自己处理还是继续发给应用程序

ImmGenerateMessage(hIMC);

}

向HIMC中写入数据,将用户选择的汉字传递给应用程序。

lpIMECompStr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
if (fFlag) 

{

lpResultStr = GetResultStr();//用户选择的汉字字符串

if (!lpResultStr) return FALSE;

//将用户选择的字符串写入HIMC中

_tcscpy((LPTSTR)((LPBYTE)(lpIMECompStr) + (lpIMECompStr)->dwResultStrOffset), lpResultStr);

lpIMECompStr->dwResultStrLen = _tcslen(lpResultStr);
}

ImmUnlockIMCC(lpIMC->hCompStr); 

同时将用户选择的汉字传递给应用程序需要消息的协助。 
分别是WM_IME_STARTCOMPOSITION、WM_IME_COMPOSITION和WM_IME_ENDCOMPOSITION,它们分别指示开始输入编码,输入编码或者结果(视参数而异)及编码输入完成 ,WM_IME_STARTCOMPOSITION和WM_IME_ENDCOMPOSITION需要成对使用。

当发送WM_IME_COMPOSITION (GCS_COMPREAD|GCS_COMP|GCS_CURSORPOS|GCS_DELTASTART|GCS_RESULTREAD|GCS_RESULT),消息时候,IME将HIMC中lpIMECompStr 中的汉字通过WM_IME_CHAR, 消息传递给应用程序。或者转换成WM_CHAR消息传递给应用程序。

上面总结了输入法编程的基本原理。

3,输入法的安装和调试
64位系统 的输入法安装和32位系统不同。64位系统兼容32位系统的应用程序,可输入法不行,64位的应用程序必须有64位的输入法,而32位程序必须有32位的输入法。
所以我们要在64位系统中安装输入法,首先必须将我们的输入法dll编译成64位和32位两种。
(1)如何编译64位的程序呢?使用64位的操作系统,在VS2010中打开 菜单:生成-》配置管理器


(2)如何安装输入法? 

将编译的dll扩展名改成.ime

<1>拷贝输入法dll到系统目录。将64位编译的dll放入 c:\windows\system32 目录,将32位编译的放入C:\Windows\SysWOW64目录
<2>将输入法注册,网上说可以使用ImmInstallIME 函数,可我在64位系统上始终没有成功。于是使用手动创建注册表项来实现输入法的注册

A.在注册表中HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Keyboard Layouts,创建一个新的Key,名字为xxxx0804 (低位表示语言,这里0804表示简体中文;高位表示设备句柄,0000表示默认的physical layout,如00000804表示简体中文英文键盘)。譬如:

[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Keyboard Layouts/E0200804]

"IME File"="***.IME" //你的输入法dll的文件名

"Layout File"="kbdus.dll"

"Layout Text"="****输入法 2010"

B. Enable这个输入法,譬如:

[HKEY_CURRENT_USER/Keyboard Layout/Preload]

"1"="00000804"

"2"="e0200804" //按照已有最大的序号+1 = 上面你创建的key的名字:E0200804

C,重新启动系统

(3)如何调试输入法
按照上面的方法按照好输入法以后,我们就可以使用VS2010对输入法进行调试。

<1> 使用附加到进程的方式



然后再窗口选择 写字板,或者word,等进程,



然后,设置断点,在记事本中选择你自己编写的输入法,输入编码,进行调试。

<2>设置命令参数为记事本程序的路径。c:\\windows\\system32\\notepad.exe


 


(4)关于编译源程序可能会遇到的问题
1、确保应用 Imm32.lib


 


2、如果 IMM.H 的位置在项目中,应在 additional include directories 中指定为./

 

Win7 64位系统,使用(IME)模式VS2010 编写 和 安装 输入法 教程(1)的更多相关文章

  1. 新装的win7 64位系统上装了IE11,想调试网页的时候,按F12,工具会出来,但是没法正常使用,出现空白。

    Windows专区开了一帖,没人应.这边再开一帖,看看各位遇到过没.如题,新装的win7 64位系统上装了IE11,想调试网页的时候,按F12,工具会出来,但是没法正常使用.尤其是想切换文档模式,只能 ...

  2. WIN7 64位系统注册银行支付组件

    WIN7 64位系统注册银行支付组件目前只尝试注册了银联的chinapay.dll和工行的icbcebankutil.dll 1.将dll文件拷贝到windows\syswow64\文件夹下(Win7 ...

  3. WIN7 64位系统搭建WINCE6.0系统遇到的问题

    WIN7 64位系统搭建WINCE6.0系统遇到的问题 安装顺序如下: .先装Visual Studio2005: .安装Visual Studio2005 Service Pack 1: .安装Vi ...

  4. U盘安装Win7 64位系统(笔记本+台式机亲测)

    准备工具: 1. Win7 64位系统的镜像文件(网上随便一搜即可,最好是纯净版,没有一堆乱七八糟的内置软件) 2. 4G以上的U盘一个 所用软件: 老毛桃(官网下载) 具体步骤: 1.数据备份(将原 ...

  5. Win7 64位系统上配置使用32位的Eclipse(转)

    Win7 64位系统上配置使用32位的Eclipse 博客分类: Eclipse eclipse  最近工作电脑换成了64位的win7系统,之前个人电脑上安装的jdk和Eclipse都是32位的.而新 ...

  6. win7 64位系统装oracle11 提示环境变量path 值超过1023字符

    win7 64位系统装oracle10 提示环境变量path 值超过1023字符 1.提示环境变量path 值超过1023字符. 方案: 1.oracle安装文件,右键属性--设置兼容性--兼容XP ...

  7. win7 64位系统下安装autoitlibrary库遇到问题解决

    转载来自http://blog.sina.com.cn/s/blog_53f023270101skyq.html 今天需要在win7 64位系统下安装autoitlibrary库,起初安装好了robo ...

  8. Win7 64位系统,IE11,如何让IE的Tab强制运行64位内核?

    有些人在使用TerraExplorer Pro 7版本进行web二次开发的时候,常会遇到下面截图中这样的问题, 这个问题主要是因为安装的TerraExplorer Pro 7 版本是64位的,而模型运 ...

  9. (转)Win7 64位系统下 Retional rose 2003 安装及破解

    网上关于Retional rose 2003安装和破解的文章比较多,这里,我结合自己的亲身体验,和大家分享一下win7 旗舰版 64位系统下Retional rose 2003(下面简称rose200 ...

随机推荐

  1. SQL基础总结——20150730

           SQL SQL 指结构化查询语言 SQL 使我们有能力訪问数据库 SQL 是一种 ANSI(美国国家标准化组织) 的标准计算机语言 SQL 是一门 ANSI 的标准计算机语言.用来訪问和 ...

  2. 为何在查询中索引未被使用 (Doc ID 1549181.1)

        To Bottom * 为何在查询中索引未被使用 (Doc ID 1549181.1) To Bottom 文档内容 用途   排错步骤   高速检查   表上是否存在索引?   索引是否应该 ...

  3. swift学习第十天:函数

    函数的介绍 函数相当于OC中的方法 函数的格式如下 func 函数名(参数列表) -> 返回值类型 { 代码块 return 返回值 } func是关键字,多个参数列表之间可以用逗号(,)分隔, ...

  4. C# .NET Socket

    C# .NET Socket 简单实用框架 背景: 首先向各位前辈,大哥哥小姐姐问一声好~ 这是我第一次写博客,目前为一个即将步入大四的学生,上学期在一家公司实习了半年,后期发现没有动力,而且由于薪水 ...

  5. ImageView一例 分类: H1_ANDROID 2013-10-30 23:02 1812人阅读 评论(0) 收藏

    参考自<疯狂android讲义>2.4节 效果如下: 当点击图上某点时,将之附近放大至下图. 布局文件: <LinearLayout xmlns:android="http ...

  6. JAVA 中无锁的线程安全整数 AtomicInteger介绍和使用

    Java 中无锁的线程安全整数 AtomicInteger,一个提供原子操作的Integer的类.在Java语言中,++i和i++操作并不是线程安全的,在使用的时候, 不可避免的会用到synchron ...

  7. 小强的HTML5移动开发之路(27)—— JavaScript回顾2

    Javascript面向对象基础知识 1.如何定义一个类,使用如下语法来创建一个类 function Person(name, age){ //习惯上第一个字母大写 //this修饰的变量称为属性 t ...

  8. ITFriend创业败局(序):简要概述我的第一次创业经历

    是时候, 面对过去,继续踏上未来之路了.    是时候,该给自己一个交待了,给ITFriend创业合伙人.ITFriend用户.关注我的朋友和网友们一个答复了.    是时候,全面认真总结过去的经历. ...

  9. 毕设三: spark与phoenix集成插入数据/解析json数组

    需求:将前些日子采集的评论存储到hbase中 思路: 先用fastjson解析评论,然后构造rdd,最后使用spark与phoenix交互,把数据存储到hbase中 部分数据: [ { "r ...

  10. Popup 解决位置不随窗口/元素FrameworkElement 移动更新的问题

    原文:Popup 解决位置不随窗口/元素FrameworkElement 移动更新的问题 Popup弹出后,因业务需求设置了StaysOpen=true后,移动窗口位置或者改变窗口大小,Popup的位 ...