输入法(IME)实现原理


输入法(IME)实现原理


一、实现原理

1.中文输入法的组成

微软 Windows 系统中输入法由程序(DLL)名称为:*.ime文件和码表文件(字典)

名称为*.mb文件组成。


2.中文输入法的界面

http://wjy.hanwenhua.com/images/Projec6.gif


3.在 Windows 任务栏“EN图标”中增加输入法名称

这也就是 Setup 程序的关键,实际上,可以利用 Win32Api 函数 ImmInstallIME() 。

该函数的原形是:

HKL ImmInstallIME( LPCTSTR lpszIMEFileName, LPCTSTR lpszLayoutText);

前一个参数 lpszIMEFileName 是“.ime”文件的路径,Win9x 为“\System”下,

WinNT/2000为“\System32”下。后一个参数 lpszLayoutText  是输入法的明称。如 HKL MyIme=ImmInstallIME("Windows\\system\\3jaja.ime","3++输入法"); 

如果 MyIme 不返回 NULL ,则调用成功。


4.“.ime”文件的实现

程序中的输出函数(必须)即文件“.def”中的函数,以下为函数的名称和原形,部分函数给出了原函数,

希望对你能有所帮助。

 

Cpp代码   收藏代码
  1. //初始化输入法函数  
  2. BOOL WINAPI ImeInquire(LPIMEINFO lpImeInfo,LPTSTR lpszWndCls,DWORD lpszOptions)  
  3. {  
  4.     if (!lpImeInfo)  
  5.         return (FALSE);  
  6.     lpImeInfo->dwPrivateDataSize = sizeof(PRIVCONTEXT);  
  7.     lpImeInfo->fdwProperty = IME_PROP_KBD_CHAR_FIRST | IME_PROP_CANDLIST_START_FROM_1 | IME_PROP_IGNORE_UPKEYS;  
  8.     lpImeInfo->fdwConversionCaps = IME_CMODE_NATIVE|IME_CMODE_NATIVE|IME_CMODE_FULLSHAPE|IME_CMODE_CHARCODE | IME_CMODE_SOFTKBD | IME_CMODE_NOCONVERSION;  
  9.     lpImeInfo->fdwSentenceCaps = 0;  
  10.     lpImeInfo->fdwUICaps = UI_CAP_ROT90 | UI_CAP_SOFTKBD;  
  11.     lpImeInfo->fdwSCSCaps = SCS_CAP_COMPSTR | SCS_CAP_MAKEREAD;  
  12.     lpImeInfo->fdwSelectCaps = (DWORD)0;  
  13.     lstrcpy(lpszWndCls, (LPTSTR)szUIClassName);  
  14.     return (TRUE);  
  15. }        
  16.   
  17. //自定义汉字编码格式,未作处理。  
  18. DWORD WINAPI ImeConversionList(HIMC hIMC,LPCTSTR lpszSrc,DWORD uBufLen,UINT uFlag)  
  19. {  
  20.     return (0);  
  21. }  
  22. //设置输入法状态函数,如光标跟随等  
  23. BOOL WINAPI ImeConfigure(HKL hKL,HWND hAppWnd,DWORD dwMode,LPVOID  lpData)  
  24. {  
  25.     switch (dwMode)   
  26.     {  
  27.     case IME_CONFIG_GENERAL:  
  28.         DialogBox(hInst, MAKEINTRESOURCE(SETIME), (HWND)hAppWnd, (DLGPROC)ImeSetDlgProc);  
  29.         break;  
  30.     default:  
  31.         return (FALSE);  
  32.         break;  
  33.     }  
  34.     return (TRUE);  
  35. }  
  36. //退出  
  37. BOOL WINAPI ImeDestroy(UINT uReserved)  
  38. {  
  39.     if (uReserved)   
  40.         return (FALSE);   
  41.     return (TRUE);  
  42. }   
  43.   
  44. //应用接口函数  
  45. LRESULT WINAPI ImeEscape(HIMC hIMC,UINT uSubFunc,LPVOID lpData)  
  46. {  
  47.     LRESULT lRet;  
  48.     switch (uSubFunc)   
  49.     {  
  50.     case IME_ESC_QUERY_SUPPORT:  
  51.         if ( lpData == NULL )  
  52.             return FALSE;  
  53.         switch (*(LPUINT)lpData)  
  54.         {  
  55.         case IME_ESC_QUERY_SUPPORT:  
  56.         case IME_ESC_MAX_KEY:  
  57.         case IME_ESC_IME_NAME:  
  58.         case IME_ESC_GETHELPFILENAME:  
  59.             return (TRUE);  
  60.         case IME_ESC_SEQUENCE_TO_INTERNAL:  
  61.         case IME_ESC_GET_EUDC_DICTIONARY:  
  62.         case IME_ESC_SET_EUDC_DICTIONARY:  
  63.         case IME_INPUTKEYTOSEQUENCE:  
  64.             return (FALSE);           
  65.         default:  
  66.             return (FALSE);  
  67.         }  
  68.         break;  
  69.     case IME_ESC_SEQUENCE_TO_INTERNAL:  
  70.     case IME_ESC_GET_EUDC_DICTIONARY:  
  71.     case IME_ESC_SET_EUDC_DICTIONARY:  
  72.     case IME_INPUTKEYTOSEQUENCE:  
  73.         return (FALSE);  
  74.     case IME_ESC_MAX_KEY:  
  75.         return ((WORD) 4);  
  76.     case IME_ESC_GETHELPFILENAME:  
  77.         {  
  78.             TCHAR szIMEGUDHlpName[MAXSTRLEN];  
  79.             if (lpData == NULL )  
  80.                 return FALSE;  
  81.             szIMEGUDHlpName[0] = 0;  
  82.             GetWindowsDirectory((LPTSTR)szIMEGUDHlpName, MAXSTRLEN);  
  83.             lstrcat((LPTSTR)szIMEGUDHlpName, TEXT("file://HELP//3JaJa.hlp"));  
  84.             lstrcpy((char*)lpData, (char*)szIMEGUDHlpName);  
  85.             return TRUE;  
  86.         }  
  87.     default:  
  88.         return (FALSE);  
  89.     }  
  90.     return (lRet);  
  91. }   
  92.   
  93. //启动输入法设置功能  
  94. BOOL WINAPI ImeSelect(HIMC hIMC,BOOL fSelect)  
  95. {  
  96.     LPINPUTCONTEXT lpIMC;  
  97.     BOOL           fRet;  
  98.     if (!hIMC)   
  99.         return (FALSE);  
  100.     lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);  
  101.     if (!lpIMC)   
  102.         return (FALSE);  
  103.     fRet = Select(hIMC, lpIMC, fSelect);  
  104.     ImmUnlockIMC(hIMC);  
  105.     return (fRet);  
  106. }  
  107. //设置输入活动状态  
  108. BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fOn)  
  109. {  
  110.     if (fOn&&hIMC)   
  111.     {  
  112.         LPINPUTCONTEXT lpIMC;  
  113.         lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);  
  114.         if (!lpIMC)   
  115.             return (FALSE);  
  116.         InitContext(lpIMC);  
  117.         ImmUnlockIMC(hIMC);  
  118.     }  
  119.     return (TRUE);  
  120. }  
  121. //用户按键处理函数,例如中英文状态,返回 FALSE 为英文状态,按键不作处理。  
  122. BOOL WINAPI ImeProcessKey(HIMC hIMC,UINT uVirtKey,LPARAM lParam,CONST LPBYTE lpbKeyState);  
  123.   
  124. //输入法编码字符处理。  
  125. BOOL WINAPI ImeSetCompositionString(HIMC hIMC,DWORD dwIndex,LPVOID lpComp,DWORD dwCompLen,LPVOID lpRead,DWORD  dwReadLen);  
  126. //将用户按键转换为汉字编码  
  127. UINT WINAPI ImeToAsciiEx(UINT uVirtKey,UINT uScanCode,CONST LPBYTE lpbKeyState,LPTRANSMSGLIST lpTransBuf,UINT fuState,HIMC hIMC)             
  128.   
  129. //处理IME消息函数  
  130. BOOL WINAPI NotifyIME(HIMC hIMC,DWORD dwAction,DWORD dwIndex,DWORD dwValue);       
  131. //自定义汉字编码格式,未作处理。  
  132. BOOL WINAPI ImeRegisterWord(LPCTSTR lpszReading,DWORD dwStyle,LPCTSTR lpszString)  
  133. {  
  134.     return (FALSE);  
  135. }  
  136. //自定义汉字编码格式,未作处理。  
  137. BOOL WINAPI ImeUnregisterWord(LPCTSTR lpszReading,DWORD dwStyle,LPCTSTR lpszString)  
  138. {  
  139.     return (FALSE);  
  140. }  
  141. //自定义汉字编码格式,未作处理。  
  142. UINT WINAPI ImeGetRegisterWordStyle(UINT nItem,LPSTYLEBUF lpStyleBuf)  
  143. {  
  144.     return (FALSE);  
  145. }  
  146. //自定义汉字编码格式,未作处理。  
  147. UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROC lpfnRegisterWordEnumProc,  
  148.                                 LPCTSTR lpszReading,DWORD dwStyle,LPCTSTR lpszString,LPVOID lpData)  
  149. {  
  150.     return (FALSE);  
  151. }  
  152. //UI窗口过程  
  153. LRESULT CALLBACK UIWndProc(HWND   hUIWnd,UINT   uMsg,WPARAM wParam,LPARAM lParam)  
  154. {  
  155.     switch (uMsg)   
  156.     {  
  157.     case WM_CREATE:  
  158.         CreateUIWindow(hUIWnd);  
  159.         break;  
  160.     case WM_DESTROY:  
  161.         DestroyUIWindow(hUIWnd);  
  162.         break;  
  163.     case WM_IME_STARTCOMPOSITION:  
  164.         ......  
  165.     }  
  166. }  
  167. //状态窗口过程  
  168. LRESULT CALLBACK StatusWndProc(HWND hStatusWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);  
  169. //编码窗口过程  
  170. LRESULT CALLBACK CompWndProc(HWND hCompWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);  
  171. //侯选汉字窗口过程  
  172. LRESULT CALLBACK CandWndProc(HWND hCandWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);  
 

5.头文件及链接文件

记得要定义 IMM32.h 及链接文件 IMM32.lib。至于有关“ .ime”程序中必须用到的结构,大家可参考 MSDN 中的有关文档。


二、常用函数

BOOL WINAPI ImmGenerateMessage( //将汉字串法发送到与当前输入法相关联的应用软件中

HIMC hIMC

);//成功为TRUE,否则为FALSE

LRESULT WINAPI ImmRequestMessage( //向应用程序发送WM_IME_REQUEST消息

HIMC hIMC, //与当前输入法相关联的应用软件的句柄

WPARAM wParam, //与WM_IME_REQUEST相关的wP

LPARAM lParam //与WM_IME_REQUEST相关的LP

);

LPINPUTCONTEXT WINAPI ImmLockIMC( //获取当前IMC的INPUTCONTEXT结构信息,增加IMC 计数器

HIMC hIMC

);//成功返回INPUTCONTEXT 结构指针,否则为NULL

BOOL WINAPI ImmUnlockIMC( //释放IMC计数器

HIMC hIMC );//返回:如果IMC计数器被减少到0了,返回FALSE,否则为TRUE.

注意:ImmLockIMC与ImmUnlockIMC必须成对出现,必须是相同的HIMC

HIMCC WINAPI ImmGetIMCLockCount( //取计数器值

HIMC hIMC );//如果成功返回HIMC的计数器值,否则为NULL.

HIMCC WINAPI ImmCreateIMCC( //创建INPUTCONTEXT结构的一个成员

DWORD dwSize //成员的缓冲区长度

);//如果成功返回IMC的成员句柄,否则为NULL

HIMCC WINAPI ImmDestroyIMCC( //删除IMC成员缓冲区

HIMCC hIMCC

);//如果成功返回NULL,否则等于该HIMCC.

LPVOID WINAPI ImmLockIMCC( //取IMCC缓冲地址,同时使IMCC的计数器值增加

HIMCC hIMCC );

BOOL WINAPI ImmUnlockIMCC( //递减IMCC计数器

HIMCC hIMCC );//如果IMCC的计数器值为零,则返回 FALSE,否则为TRUE.

10、HIMCC WINAPI ImmReSizeIMCC( //重新设置IMC的成员的缓冲区大小

HIMCC hIMCC, //IMC的成员句柄

DWORD dwSize //新缓冲区大小

);//如果成功,返回新的HIMCC,否则为 NULL.

DWORD WINAPI ImmGetIMCCSize( //取IMC成员的缓冲区大小

HIMCC hIMCC );//返回IMC成员的缓冲区大小

12、DWORD WINAPI ImmGetIMCCLockCount( //返回IMC计数器值

HIMCC hIMCC

);//成功返回该IMCC的计数器值,否则为0

BOOL WINAPI ImmGetHotKey( //取输入法状态键,该函数供控制面板使用

DWORD dwHotKeyID,

LPUINT lpuModifiers,

LPUINT lpuVKey,

LPHKL lphKL

)

BOOL WINAPI ImmSetHotKey( //设置输入法的热键

DWORD dwHotKeyID,

UINT uModifiers,

UINT uVKey,

hKL hKL

)

HWND WINAPI ImmCreateSoftKeyboard( //产生一个软键盘

UINT uType, //软件盘上的键码含义的定义方式

UINT hOwner, //该输入法的UI窗口

int x, //x坐标

int y //y坐标

);//成功返回软键盘的窗口句柄

BOOL WINAPI ImmDestroySoftKeyboard( //销毁软键盘

HWND hSoftKbdWnd //软键盘窗口句柄

);//成功为TRUE,法哦则为FALSE.

17、BOOL WINAPI ImmShowSoftKeyboard( //显示或隐藏软键盘

HWND hSoftKbdWnd, //软键盘窗口句柄

int nCmdShow //SW_HIDE=隐藏,SW_SHOWNOACTIVATE=显示

);//如构成功返回 TRUE. 否则为 FALSE.


二、 IME  文件中的常用结构

1、IMEINFOstruct tagIMEInfo { //输入法的接口信息

DWORD dwPrivateDataSize;//用户设计的数据结构的字节数 

DWORD fdwProperty; //输入法对键盘事件的相应特性

DWORD fdwConversionCaps;//当前输入法具有的功能特性,如有软键盘、标点、中西文切换等功能 

DWORD fdwSentenceCaps; 

DWORD fdwUICaps; // 用户界面能力:支持软键盘等

DWORD fdwSCSCaps; // 用户设置编码串的能力

DWORD fdwSelectCaps; // 输入法切换时是否使用以前输入法的模式

} IIMEINFO;

2、COMPOSITIONSTR 用于编码管理

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;

3、CANDIDATEINFO 用于编码选择管理

typedef struct tagCANDIDATEINFO { 

DWORD dwSize; //数据所占内存大小

DWORD dwCount; //数据个数

DWORD dwOffset[32]; //各个编码列表的内存位置

DWORD dwPrivateSize; //自定义数据尺寸

DWORD dwPrivateOffset; //缓冲区位置

} CANDIDATEINFO;

4、GUIDELINE

typedef struct tagGUIDELINE {

DWORD dwSize;

DWORD dwLevel;

DWORD dwIndex;

DWORD dwStrLen;

DWORD dwStrOffset;

DWORD dwPrivateSize;

DWORD dwPrivateOffset; 

} GUIDELINE;

5、CANDIDATELIST 编码选择列表信息

typedef struct tagCANDIDATELIST { 

DWORD dwSize; // 用字节表示的内存大小

DWORD dwStyle; // 列表串的取值方式

DWORD dwCount; // 当前列表个数

DWORD dwSelection; // 当前选择的列表序号

DWORD dwPageStart; // 在列表窗口中所显示的列表的起始序号

DWORD dwPageSize; // 一页显示的列表个数

DWORD dwOffset[]; // 列表数据存放区地址

} CANDIDATELIST;

6、COMPOSITIONFORM 窗口位置、大小信息:

typedef tagCOMPOSITIONFORM { 

DWORD dwStyle; //管理窗口方式

POINT ptCurrentPos; //给定坐标

RECT rcArea; 

}COMPOSITIONFORM;

7、CANDIDATEFORM 列表窗口信息

typedef tagCANDIDATEFORM { 

DWORD dwIndex; //列表窗口序号

DWORD dwStyle; //属性:

POINT ptCurrentPos; //坐标位置

REC rcArea; 

} CANDIDATEFORM;

12、INPUTCONTEXT IMC 数据存放区

typedef struct tagINPUTCONTEXT { 

HWND hWnd; //使用该IMC的窗口

BOOL fOpen; //IME的打开与关闭状态

POINT ptStatusWndPos; //状态窗口的位置

POINT ptSoftKbdPos; //软键盘的位置

DWORD fdwConversion; //IME状态(活动、不活动,全角等)

DWORD fdwSentence; //编码方式

union {

 LOGFONTA A;

 LOGFONTW W;

} lfFont; //字体

COMPOSITIONFORM cfCompForm; //编码格式结构

CANDIDATEFORM cfCandForm[4]; //列表选择结构

HIMCC hCompStr;HIMCC hCandInfo;

HIMCC hGuideLine

HIMCC hPrivate; 

DWORD dwNumMsgBuf; //存放在hMsgBuf中的消息数

HIMCC hMsgBuf; //存放的消息

DWORD fdwInit //系统根据此值来初始本结构相应的信息

DWORD dwReserve[3]; //未定义

} INPUTCONTEXT;       

注:原文出处:http://wjy.hanwenhua.com/setProject.htm,本人认为文中有少许内容并不贴切,待日后法帖讨论!

分享到:
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值