输入法(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”中的函数,以下为函数的名称和原形,部分函数给出了原函数,

希望对你能有所帮助。

 

//初始化输入法函数
BOOL WINAPI ImeInquire(LPIMEINFO lpImeInfo,LPTSTR lpszWndCls,DWORD lpszOptions)
{
	if (!lpImeInfo)
		return (FALSE);
	lpImeInfo->dwPrivateDataSize = sizeof(PRIVCONTEXT);
	lpImeInfo->fdwProperty = IME_PROP_KBD_CHAR_FIRST | IME_PROP_CANDLIST_START_FROM_1 | IME_PROP_IGNORE_UPKEYS;
	lpImeInfo->fdwConversionCaps = IME_CMODE_NATIVE|IME_CMODE_NATIVE|IME_CMODE_FULLSHAPE|IME_CMODE_CHARCODE | IME_CMODE_SOFTKBD | IME_CMODE_NOCONVERSION;
	lpImeInfo->fdwSentenceCaps = 0;
	lpImeInfo->fdwUICaps = UI_CAP_ROT90 | UI_CAP_SOFTKBD;
	lpImeInfo->fdwSCSCaps = SCS_CAP_COMPSTR | SCS_CAP_MAKEREAD;
	lpImeInfo->fdwSelectCaps = (DWORD)0;
	lstrcpy(lpszWndCls, (LPTSTR)szUIClassName);
	return (TRUE);
}      

//自定义汉字编码格式,未作处理。
DWORD WINAPI ImeConversionList(HIMC hIMC,LPCTSTR lpszSrc,DWORD uBufLen,UINT uFlag)
{
	return (0);
}
//设置输入法状态函数,如光标跟随等
BOOL WINAPI ImeConfigure(HKL hKL,HWND hAppWnd,DWORD dwMode,LPVOID  lpData)
{
	switch (dwMode) 
	{
	case IME_CONFIG_GENERAL:
		DialogBox(hInst, MAKEINTRESOURCE(SETIME), (HWND)hAppWnd, (DLGPROC)ImeSetDlgProc);
		break;
	default:
		return (FALSE);
		break;
	}
	return (TRUE);
}
//退出
BOOL WINAPI ImeDestroy(UINT uReserved)
{
	if (uReserved) 
		return (FALSE); 
	return (TRUE);
} 

//应用接口函数
LRESULT WINAPI ImeEscape(HIMC hIMC,UINT uSubFunc,LPVOID lpData)
{
	LRESULT lRet;
	switch (uSubFunc) 
	{
	case IME_ESC_QUERY_SUPPORT:
		if ( lpData == NULL )
			return FALSE;
		switch (*(LPUINT)lpData)
		{
		case IME_ESC_QUERY_SUPPORT:
		case IME_ESC_MAX_KEY:
		case IME_ESC_IME_NAME:
		case IME_ESC_GETHELPFILENAME:
			return (TRUE);
		case IME_ESC_SEQUENCE_TO_INTERNAL:
		case IME_ESC_GET_EUDC_DICTIONARY:
		case IME_ESC_SET_EUDC_DICTIONARY:
		case IME_INPUTKEYTOSEQUENCE:
			return (FALSE);         
		default:
			return (FALSE);
		}
		break;
	case IME_ESC_SEQUENCE_TO_INTERNAL:
	case IME_ESC_GET_EUDC_DICTIONARY:
	case IME_ESC_SET_EUDC_DICTIONARY:
	case IME_INPUTKEYTOSEQUENCE:
		return (FALSE);
	case IME_ESC_MAX_KEY:
		return ((WORD) 4);
	case IME_ESC_GETHELPFILENAME:
		{
			TCHAR szIMEGUDHlpName[MAXSTRLEN];
			if (lpData == NULL )
				return FALSE;
			szIMEGUDHlpName[0] = 0;
			GetWindowsDirectory((LPTSTR)szIMEGUDHlpName, MAXSTRLEN);
			lstrcat((LPTSTR)szIMEGUDHlpName, TEXT("file://HELP//3JaJa.hlp"));
			lstrcpy((char*)lpData, (char*)szIMEGUDHlpName);
			return TRUE;
		}
	default:
		return (FALSE);
	}
	return (lRet);
} 

//启动输入法设置功能
BOOL WINAPI ImeSelect(HIMC hIMC,BOOL fSelect)
{
	LPINPUTCONTEXT lpIMC;
	BOOL           fRet;
	if (!hIMC) 
		return (FALSE);
	lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
	if (!lpIMC) 
		return (FALSE);
	fRet = Select(hIMC, lpIMC, fSelect);
	ImmUnlockIMC(hIMC);
	return (fRet);
}
//设置输入活动状态
BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fOn)
{
	if (fOn&&hIMC) 
	{
		LPINPUTCONTEXT lpIMC;
		lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);
		if (!lpIMC) 
			return (FALSE);
		InitContext(lpIMC);
		ImmUnlockIMC(hIMC);
	}
	return (TRUE);
}
//用户按键处理函数,例如中英文状态,返回 FALSE 为英文状态,按键不作处理。
BOOL WINAPI ImeProcessKey(HIMC hIMC,UINT uVirtKey,LPARAM lParam,CONST LPBYTE lpbKeyState);

//输入法编码字符处理。
BOOL WINAPI ImeSetCompositionString(HIMC hIMC,DWORD dwIndex,LPVOID lpComp,DWORD dwCompLen,LPVOID lpRead,DWORD  dwReadLen);
//将用户按键转换为汉字编码
UINT WINAPI ImeToAsciiEx(UINT uVirtKey,UINT uScanCode,CONST LPBYTE lpbKeyState,LPTRANSMSGLIST lpTransBuf,UINT fuState,HIMC hIMC)           

//处理IME消息函数
BOOL WINAPI NotifyIME(HIMC hIMC,DWORD dwAction,DWORD dwIndex,DWORD dwValue);     
//自定义汉字编码格式,未作处理。
BOOL WINAPI ImeRegisterWord(LPCTSTR lpszReading,DWORD dwStyle,LPCTSTR lpszString)
{
	return (FALSE);
}
//自定义汉字编码格式,未作处理。
BOOL WINAPI ImeUnregisterWord(LPCTSTR lpszReading,DWORD dwStyle,LPCTSTR lpszString)
{
	return (FALSE);
}
//自定义汉字编码格式,未作处理。
UINT WINAPI ImeGetRegisterWordStyle(UINT nItem,LPSTYLEBUF lpStyleBuf)
{
	return (FALSE);
}
//自定义汉字编码格式,未作处理。
UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROC lpfnRegisterWordEnumProc,
								LPCTSTR lpszReading,DWORD dwStyle,LPCTSTR lpszString,LPVOID lpData)
{
	return (FALSE);
}
//UI窗口过程
LRESULT CALLBACK UIWndProc(HWND   hUIWnd,UINT   uMsg,WPARAM wParam,LPARAM lParam)
{
	switch (uMsg) 
	{
	case WM_CREATE:
		CreateUIWindow(hUIWnd);
		break;
	case WM_DESTROY:
		DestroyUIWindow(hUIWnd);
		break;
	case WM_IME_STARTCOMPOSITION:
		......
	}
}
//状态窗口过程
LRESULT CALLBACK StatusWndProc(HWND hStatusWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
//编码窗口过程
LRESULT CALLBACK CompWndProc(HWND hCompWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
//侯选汉字窗口过程
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,本人认为文中有少许内容并不贴切,待日后法帖讨论!

你可能感兴趣的:(设计模式,数据结构,UI,windows,活动)