在了解工作原理前,必先清楚几个概念。
以下为输入法工作原理,如果不知道工作原理,只看输入法程序,那很难理解,同时,只知道工作原理,而不清楚程序是如何实现,也无法深入理解输入法。二者相辅相成,共同参照,方可加深理解。
输入法工作原理 如下图:
以下结合IME转换接口 分别对其说明:
输入法初始化:
ImeInquire : 刚选择某输入法时,IMM调用此函数,获得输入法相关信息,并根据用户界面类UICLASSNAME,自动创建用户界面。
ImeSelect : 打开或关闭输入法时被调用,在此函数中对输入法上下文进行初始化或恢复释放
IMM将键盘消息传递给IME:
IMM 通过IME 转换接口ImeProcessKey 将键盘消息发动到IME
此函数对键盘消息进行筛选处理,用以判断此消息是发送给IME 还是直接发送给应用程序。
如果返回TRUE 则发送给IME 否则,直接发送给应用程序
IME将键盘消息转换为相应汉字:
IME 通过ImeToAsciiEx 函数来处理ImeProcessKey发送过来的键盘消息,并最终转换为输出的结果串
IME 将汉字以字符消息的形式返回给IMM:
IME将使用WM_IME_CHAR或 WM_IME_COMPOSITION/GCS_RESULT消息把组合好的字符发送给窗体中的应用程序。如果应用程序没有处理这些消息,DefWindowProc函数会把它们翻译成一条或多条WM_CHAR消息
示例:
MakeResultString 将转换结果保存在输入上下文中将
GenerateMessage 发送WM_IME_COMPOSITION/GCS_RESULT消息给应用程序,从而使得应用程序获得结果串
- BOOL MakeResultString(BOOL fFlag)
- {
- HIMC hIMC;
- LPINPUTCONTEXT lpIMC = NULL;
- LPCOMPOSITIONSTRING lpIMECompStr = NULL;
- LPTSTR lpResultStr = NULL;
- GENEMSG GnMsg = {0};
- GetIMC(&hIMC, &lpIMC);
- lpIMECompStr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
- if (fFlag)
- {
- lpResultStr = GetResultStr();
- if (!lpResultStr) return FALSE;
- _tcscpy((LPTSTR)((LPBYTE)(lpIMECompStr) + (lpIMECompStr)->dwResultStrOffset), lpResultStr);
- lpIMECompStr->dwResultStrLen = _tcslen(lpResultStr);
- }
- else
- {
- *((LPTSTR)((LPBYTE)(lpIMECompStr) + (lpIMECompStr)->dwResultStrOffset)) = _T('\0');
- lpIMECompStr->dwResultStrLen = 0;
- }
- InitBMStr();
- InitCandStrPage();
- InitCandList();
- ImmUnlockIMCC(lpIMC->hCompStr);
- GenerateMessage(WM_IME_COMPOSITION,0,GCS_RESULTSTR);
- GenerateMessage(WM_IME_ENDCOMPOSITION,0,0);
- ImmUnlockIMC(hIMC);
- return TRUE;
- }
- BOOL GenerateMessage(UINT message,WPARAM wParam,LPARAM lParam)
- {
- HIMC hIMC = {0};
- LPINPUTCONTEXT lpIMC = NULL;
- LPDWORD lpdwTransBuf = NULL;
- GetIMC(&hIMC, &lpIMC);
- if (IsWindow(lpIMC->hWnd))
- {
- // re-allocate the memory block for the message buffer.
- lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(DWORD) * 3);
- if (!lpIMC->hMsgBuf) goto Error;
- // Lock the memory for the message buffer.
- lpdwTransBuf = (LPDWORD)ImmLockIMCC(lpIMC->hMsgBuf);
- if (!lpdwTransBuf) goto Error;
- // Set the messages that the IME wants to generate.
- *(lpdwTransBuf++) = message;
- *(lpdwTransBuf++) = wParam;
- *(lpdwTransBuf++) = lParam;
- // Set the number of the messages.
- (lpIMC->dwNumMsgBuf)++;
- // Unlock the memory for the message buffer and the Input Context.
- ImmUnlockIMCC(lpIMC->hMsgBuf);
- // Call ImmGenerateMessage function.
- ImmGenerateMessage(hIMC);
- }
- Error:
- ImmUnlockIMC(hIMC);
- return TRUE;
- }
常用函数
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;