自然語言處理的輸入法作業(yè)成品沒有做出來,但不想再在蛋疼的Win32上面耗費(fèi)時間了缰盏,整理文檔氓癌,記錄一下心得,新手再來研究也不會迷路太遠(yuǎn)吨凑。
- IME簡介2. IME結(jié)構(gòu)3. IME調(diào)試環(huán)境配置及安裝3.1. 配置步驟3.2. 配置說明及注意事項(xiàng)3.3. IME安裝及卸載4. IME編程心得4.1. 準(zhǔn)備工作4.2. IME數(shù)據(jù)結(jié)構(gòu)介紹4.3. IME接口調(diào)用順序4.4. 感想
1 IME簡介
什么是IME (Input Method Editors)?廣義上講,IME是微軟提供的Windows平臺的一套輸入法編程規(guī)范鸵钝,依照這套規(guī)范(框架)糙臼,你不需要處理太多輸入法特性相關(guān)的操作(光標(biāo)跟隨,輸入捕獲恩商,字碼轉(zhuǎn)換后輸出到應(yīng)用程序等)变逃,你只需要使用IME規(guī)范里面提供的工具函數(shù)(imm32庫),實(shí)現(xiàn)規(guī)范所指定必須導(dǎo)出的接口即可怠堪。實(shí)際上你要做的就是寫一個導(dǎo)出函數(shù)包含IME規(guī)范規(guī)定的接口的dll揽乱,所以,狹義上講IME就是你寫的這個dll粟矿。
IME源于Windows 95和Windows NT 4.0時代凰棉,用于統(tǒng)一Windows系統(tǒng)輸入法編程規(guī)范,隨著Windows系統(tǒng)版本更新?lián)Q代陌粹,IME的結(jié)構(gòu)基本沒有改變渊啰。作者所能找到的最新IME官方文檔為Windows 98/Windows 2000版,原始文檔位于Windows98DDK內(nèi)(《Win32 Multilingual IME Overview for IME Development》和《Win32 Multilingual IME Application Programming Interface》)申屹。
進(jìn)行Windows輸入法編程必須使用IME方式,否則你必須自己解決前文所述諸如光標(biāo)跟隨隧膏,消息截獲(通常會被殺毒軟件視為病毒行為)等輸入法特性問題哗讥。實(shí)際上使用IME方式也不必完全遵循IME框架的規(guī)定實(shí)現(xiàn)完全的IME方式輸入法,開發(fā)人員完全可以只把IME當(dāng)做一個轉(zhuǎn)換接口——只實(shí)現(xiàn)其中幾個重要的接口函數(shù)胞枕,收發(fā)消息杆煞,然后講包括輸入法邏輯的實(shí)現(xiàn)全部交給自己的庫。所以無論從哪方面講腐泻,要實(shí)現(xiàn)Windows輸入法編程必須學(xué)會使用IME决乎。
2 IME結(jié)構(gòu)
如前文所述,狹義IME開發(fā)就是實(shí)現(xiàn)類似“輸入法名字.ime”這樣一個動態(tài)庫(編譯的時候通常將.dll后綴改為.ime后綴)派桩。這個庫需要導(dǎo)出如下15個接口函數(shù):
ImeConversionList
ImeConfigure
ImeDestroy
ImeEscape
ImeInquire
ImeProcessKey
ImeSelect
ImeSetActiveContext
ImeSetCompositionString
ImeToAsciiEx
NotifyIME
ImeRegisterWord
ImeUnregisterWord
ImeGetRegisterWordStyle
ImeEnumRegisterWord
而這些函數(shù)中很多都是不重要的构诚,進(jìn)行編程的時候可以不去具體實(shí)現(xiàn)。
注意:如果你查看別人的IME源碼铆惑,你會發(fā)現(xiàn)他們還導(dǎo)出了UIWndProc, StatusWndProc, CompWndProc, CandWndProc四個函數(shù)范嘱,這四個函數(shù)其實(shí)不是IME規(guī)定需要導(dǎo)出的接口函數(shù),而是四個窗口過程函數(shù)员魏,為回調(diào)函數(shù)丑蛤。其中UIWndProc是輸入法主窗口的窗口過程函數(shù),實(shí)際上是一個沒有界面的空窗口撕阎,StatusWndProc, CompWndProc, CandWndProc分別為狀態(tài)窗口受裹,輸入窗口,候選碼窗口的窗口過程函數(shù)虏束。源碼的作者們通常在動態(tài)庫初始化的時候注冊這四個窗口過程函數(shù)所屬的窗口類棉饶,由于這些窗口是非模態(tài)窗口厦章,與模態(tài)窗口不同,它們的消息必須經(jīng)過主程序的消息循環(huán)砰盐,所以如果不導(dǎo)出其窗口過程函數(shù)闷袒,上層IME框架無法將屬于這些窗口的消息發(fā)送到這些窗口過程函數(shù)處理。例如搜狗輸入法由于不是采用WIN32窗口類方式實(shí)現(xiàn)圖形界面岩梳,所以沒有上述到處函數(shù)囊骤,只有標(biāo)準(zhǔn)的15個IME導(dǎo)出函數(shù)。如果你熟悉WIN32編程和Windows消息循環(huán)機(jī)制就明白我在說什么了冀值。
要實(shí)現(xiàn)這些IME規(guī)范規(guī)定的接口函數(shù)也物,必須用到IMM (Input Method Manager)庫,位于system32目錄的imm32.dll列疗,這個庫提供了訪問控制IME內(nèi)部結(jié)構(gòu)的方法滑蚯,這些方法蓋含imm ui functions, imm support functions, himc and himcc managerment functions, ime hot keys and hot key functions, imm soft keyboard functions五個部分,函數(shù)均以Imm開頭抵栈。與imm32.dll配套的頭文件和lib庫文件為imm.h和imm32.lib告材,在Win98DDK中可以找到(名字不是這個名字,需要重命名)古劲,或者直接從別人的源碼里面找到斥赋。另外imm.h里面還定義了一些IME的結(jié)構(gòu)體,這些結(jié)構(gòu)體在IME編程中必須用到产艾,具體介紹參考《Win32 Multilingual IME Application Programming Interface》疤剑。
3 IME調(diào)試環(huán)境配置及安裝
構(gòu)建IME文件結(jié)構(gòu)我們不必從零開始,可以在別人的源碼上進(jìn)行修改闷堡,這里以啟程的示例源碼為例(《淺談輸入法編程》http://www.setoutsoft.cn/Html/?256.html源碼imesample.rar)隘膘,該源碼結(jié)構(gòu)清晰簡潔。
3.1 配置步驟
第一步:下載源碼解壓杠览。在解壓目錄(假定名為imesample)發(fā)現(xiàn)該項(xiàng)目是VC++6.0項(xiàng)目弯菊,如果你的IDE是Visual Studio就需要進(jìn)行格式轉(zhuǎn)換。直接雙擊imesample.dsw轉(zhuǎn)換后就得到了自己的VS解決方案imesample.sln(我的IDE是VS2012)倦零。
第二步:配置IDE误续。編譯上述源碼,發(fā)現(xiàn)170個錯誤扫茅,是沒有配置imm.h和imm32.lib路徑所致蹋嵌。在項(xiàng)目屬性->VC++目錄->包含目錄下面添加源碼文件夾下的IMM文件夾路徑(包含imm.h和imm32.lib)。編譯成功葫隙。
第三步:imesample.ime安裝程序制作栽烂。創(chuàng)建Win32控制臺應(yīng)用程序命名為IMEInstaller,將imm.h和imm32.lib拷貝到該工程目錄下,修改主函數(shù)代碼為:
// IMEInstaller.cpp : 定義控制臺應(yīng)用程序的入口點(diǎn)腺办。//#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("注冊輸入法失敗焰手,請注銷(或重啟)計(jì)算機(jī)再試驗(yàn)!\n"); } else { printf("注冊輸入法成功怀喉!\n"); } printf("按任意鍵退出!\n"); getchar(); return 0;}
主要是添加Windows.h和Imm.h頭文件(順序不能顛倒书妻,因?yàn)閕mm.h需要依賴前一個文件的定義)和引用imm32.lib,從而使用ImmInstallIME函數(shù)注冊輸入法躬拢。
第四步:安裝imesample.ime躲履。編譯上一步的安裝程序,得到“IMEInstaller.exe”可執(zhí)行程序聊闯,將其拷貝到imesample工程編譯結(jié)果imesample.dll所在目錄工猜,將imesample.dll重命名為imesample.ime,然后運(yùn)行IMEInstaller.exe菱蔬,如果顯示注冊成功的結(jié)果則安裝成功篷帅,你能在輸入法選擇里面看到你剛注冊的輸入法了,如下圖中“我的輸入法”拴泌。
如果注冊失敗魏身,重啟計(jì)算機(jī)也無法解決,原因有幾種可能蚪腐,在后面的說明中解釋叠骑。
第五步:測試剛才注冊的輸入法。打開記事本削茁,如果輸入法選擇菜單項(xiàng)的圖標(biāo)無法顯示,則表示此應(yīng)用中無法加載對應(yīng)輸入法的庫文件掉房,此輸入法無法使用(可能跟編譯版本或者系統(tǒng)有關(guān)茧跋,我的是WIN7 64位系統(tǒng)),如下圖卓囚。
但我的UltraEdit內(nèi)可以正常使用新裝的輸入法瘾杭,如下圖。記錄下一個可以正常使用新輸入法應(yīng)用程序的路徑哪亿,例如我的UltraEdit路徑為:"E:\Program Files (x86)\IDM Computer Solutions\UltraEdit\Uedit32.exe"粥烁。
第六步:配置調(diào)試程序。打開imesample工程蝇棉,找到項(xiàng)目屬性->調(diào)試->命令項(xiàng)讨阻,將上一步記下的調(diào)試程序路徑填入其中,如下圖篡殷。
確認(rèn)修改后钝吮,就可以調(diào)試了。打開源碼內(nèi)的imm.c文件,找到ImeToAsciiEx函數(shù)奇瘦,在其內(nèi)設(shè)置一個斷點(diǎn)棘催。按F5,IDE會啟動你設(shè)置的調(diào)試程序耳标,將輸入法切換到“我的輸入法”醇坝,輸入字母會發(fā)現(xiàn)IDE到達(dá)斷點(diǎn)處,調(diào)試成功次坡。
以后修改代碼呼猪,直接調(diào)試即為最新代碼效果(系統(tǒng)能在你的工程目錄下找到最新版本dll并加載?非也贸毕,看后文解釋)郑叠。
3.2 配置說明及注意事項(xiàng)
下面來分析一下上述步驟的過程及原理。
本來的流程應(yīng)該是這樣的:
編譯生成imesample.ime(假設(shè)直接生成的就是.ime后綴的文件)
然后將imesample.ime拷貝到C:\Windows\System32\目錄(如果你是64位系統(tǒng)明棍,必須拷貝到SysWOW64目錄下乡革,因?yàn)?4位系統(tǒng)只從SysWOW64中尋找輸入法庫文件)
用ImmInstallIME函數(shù)注冊輸入法時,必須保證SysWOW64和注冊函數(shù)所在目錄都有imesample.ime庫文件摊腋,否則無法注冊成功沸版。可以重復(fù)注冊多次兴蒸,但只在注冊表添加一條記錄视粮。
進(jìn)行調(diào)試的時候,系統(tǒng)使用的是System32(64位系統(tǒng)為SysWOW64)下的imesample.ime庫文件橙凳,所以每次修改代碼編譯后都必須將新版imesample.ime拷貝到System32 (SysWOW64)下才可執(zhí)行調(diào)試蕾殴,否則斷點(diǎn)為失效狀態(tài)。
而實(shí)際上我們并沒有復(fù)制imesample.ime到System32 (SysWOW64)啊岛啸,原來是作者在工程中做了一個小動作——加入了后期生成時間命令行钓觉。即打開工程,工程屬性->生成事件->后期生成事件->命令行坚踩,可以發(fā)現(xiàn)多了一條命令”copy .\debug\imesample.dll C:\Windows\system32\imesample.ime”荡灾。
這條命令在每次編譯之后都會執(zhí)行一次,將生成的dll重命名為ime復(fù)制到系統(tǒng)文件夾中瞬铸。如果你是64位系統(tǒng)也不必修改其中的system32文件夾為SysWOW64批幌,因?yàn)樵趫?zhí)行命令時會自動修改為SysWOW64去執(zhí)行。
當(dāng)某個應(yīng)用正在使用輸入法時嗓节,會動態(tài)加載輸入法的庫文件荧缘,其庫文件被鎖定無法修改。所以拦宣,如果在編譯時出錯胜宇,錯誤指向上述copy命令耀怜,則需要關(guān)閉使用該輸入法的進(jìn)程才行。另外桐愉,IME有一種使輸入法啟動就不再退出的機(jī)制财破,需要在ImeInquire內(nèi)設(shè)置不采用這種機(jī)制,否則無法調(diào)試(詳情見啟程作者描述)从诲。
配置步驟第二步的改進(jìn):工程屬性->常規(guī)->目標(biāo)文件擴(kuò)展名左痢,將dll改為ime,這樣每次編譯就直接生成.ime文件了系洛,修改后還需要將上述copy命令行里的imesample.dll改為imesample.ime俊性。
3.3 IME安裝及卸載
上一節(jié)介紹了使用imm32.dll內(nèi)的ImmInstallIME函數(shù)安裝輸入法的方法,實(shí)際上這個函數(shù)只是在注冊表內(nèi)添加了兩條記錄描扯。
第一條記錄位于HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\在展開項(xiàng)中定页,以0804結(jié)尾的是簡體中文輸入法項(xiàng)目,一般新注冊的輸入法都在最后面绽诚,如圖典徊,我們注冊的輸入法注冊表編號為E02C0804。
另外一條記錄位于HKEY_CURRENT_USER\Keyboard Layout\Preload下恩够,表示當(dāng)前輸入法選擇菜單中列出的輸入法列表卒落,如下圖。
所以蜂桶,輸入法的卸載就是安裝的逆過程:刪除上述兩條注冊表項(xiàng)目儡毕,然后刪除System32 (SysWOW64)下的ime庫文件即可。
輸入法注冊失敗有幾種可能原因扑媚,爭對啟程輸入法的注冊腰湾,如果失敗,第一是System32 (SysWOW64)和安裝程序當(dāng)前目錄下沒有對應(yīng)的ime庫文件疆股,第二是ime庫文件編譯問題檐盟,需要重新編譯一下,第三是注冊過程被殺毒軟件攔截(在第一條注冊表內(nèi)會出現(xiàn)空的注冊表項(xiàng))押桃。
如果是自己編寫空殼輸入法,則可能還會出現(xiàn)其他一些問題导犹,如導(dǎo)出庫文件名與def定義不一致唱凯,資源信息為設(shè)置成輸入法信息等,詳情見《Win下的輸入法(IME)編程(1)》和《Win下的輸入法(IME)編程(2)》谎痢。
4 IME編程心得
本文中提到的很多別人的文檔都記錄了自己進(jìn)行IME編程的一些心得體會磕昼,在這里我就不作額外介紹了,只是做一下整理和補(bǔ)充节猿。
4.1 準(zhǔn)備工作
首先應(yīng)該確認(rèn)手頭有《Win32 Multilingual IME Overview for IME Development》和《Win32 Multilingual IME Application Programming Interface》兩份原始文檔的打印版票从,因?yàn)殡S時可能去查閱上面的信息資料漫雕,在我寫這篇介紹文的時候,MSDN上沒有跟多的輸入法編程相關(guān)資料(以前有峰鄙,但是現(xiàn)在無法在MSDN上查閱到了)浸间,所以面對資料的匱乏,只能從網(wǎng)絡(luò)上依靠關(guān)鍵詞尋求一些幫助信息吟榴,或者閱讀別人的源碼魁蒜。
然后,通過上面的資料你應(yīng)該能了解IME框架的三大部分知識(我理解的三大部分)吩翻。第一是ime15個導(dǎo)出函數(shù)中重要的幾個導(dǎo)出函數(shù)功能(參考《我的win32 輸入法編程心得》https://code.google.com/p/windows-config/wiki/Win32IME)兜看;第二是了解imm眾多函數(shù)中重要幾個的功能,例如ImmLockIMC, ImmUnlockIMC, ImmLockIMCC, ImmUnlockIMCC等(參考《輸入法(IME)實(shí)現(xiàn)原理》http://blog.sina.com.cn/s/blog_56a388c20100004u.html)狭瞎;第三是了解IME框架內(nèi)的主要幾個結(jié)構(gòu)體细移,IME的所有信息都保存在這些結(jié)構(gòu)體中,只有理解了它的結(jié)構(gòu)才能自如地控制IME存取數(shù)據(jù)熊锭。
4.2 IME數(shù)據(jù)結(jié)構(gòu)介紹
我要重點(diǎn)介紹的是tagINPUTCONTEXT, tagCOMPOSITIONSTR, tagCANDIDATEINFO和tagCANDIDATELIST四個結(jié)構(gòu)體弧轧,他們具體的參數(shù)含義可以參考前文所述各文檔。
tagINPUTCONTEXT是IME最重要的內(nèi)部數(shù)據(jù)結(jié)構(gòu)球涛,存儲輸入上下文數(shù)據(jù)劣针,定義如下:
typedef struct tagINPUTCONTEXT {
HWND hWnd;
BOOL fOpen;
POINT ptStatusWndPos;
POINT ptSoftKbdPos;
DWORD fdwConversion;
DWORD fdwSentence;
union {
LOGFONTA A;
LOGFONTW W;
} lfFont;
COMPOSITIONFORM cfCompForm;
CANDIDATEFORM cfCandForm[4];
HIMCC hCompStr;
HIMCC hCandInfo;
HIMCC hGuideLine
HIMCC hPrivate;
DWORD dwNumMsgBuf;
HIMCC hMsgBuf;
DWORD fdwInit
DWORD dwReserve[3];
} INPUTCONTEXT;
可以認(rèn)為它是IME內(nèi)部數(shù)據(jù)的根節(jié)點(diǎn),通過它可以讀寫IME內(nèi)部所有信息亿扁,它由HIMC句柄表示捺典,可以通過LPINPUTCONTEXT lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC);的形式通過HIMC句柄獲取該結(jié)構(gòu)體。這里要提到的是hCompStr和hCandInfo兩個變量从祝,他們都是由HIMCC句柄表示襟己,hCompStr負(fù)責(zé)用戶輸入字符串的信息,hCandInfo負(fù)責(zé)候選碼部分的信息牍陌,將在后面介紹擎浴。
tagCOMPOSITIONSTR是負(fù)責(zé)管理用戶輸入字符串信息的結(jié)構(gòu)體,為tagINPUTCONTEXT的子節(jié)點(diǎn)毒涧,定義如下:
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;
該結(jié)構(gòu)體可以通過LPCOMPOSITIONSTRING lpCompStr = (LPCOMPOSITIONSTRING) ImmLockIMCC(lpIMC->hCompStr)的方式從HIMCC句柄中取得贮预。其中dwCompStrLen和dwCompStrOffset分別表示用戶輸入字符串的長度和偏移量(即lpCompStr首地址+ dwCompStrOffset值指向的內(nèi)存地址為用戶輸入字符串存放位置的首地址)。
tagCANDIDATEINFO是負(fù)責(zé)管理候選碼信息的結(jié)構(gòu)體契讲,為tagINPUTCONTEXT的子節(jié)點(diǎn)仿吞,定義如下:
typedef struct tagCANDIDATEINFO {
DWORD dwSize;
DWORD dwCount;
DWORD dwOffset[32];
DWORD dwPrivateSize;
DWORD dwPrivateOffset;
} CANDIDATEINFO;
該結(jié)構(gòu)體可以通過LPCANDIDATEINFO lpCandInfo = (LPCANDIDATEINFO) ImmLockIMCC(lpIMC->hCandInfo)的方式從HIMCC句柄中取得。其中dwCount和dwOffset[32]分別表示候選碼表的個數(shù)和碼表內(nèi)存位置的偏移量捡偏,即通過lpCandInfo首地址+dwOffset[i]就能得到碼表tagCANDIDATELIST的首地址唤冈。
tagCANDIDATELIST用于存儲碼表數(shù)據(jù),是上面tagCANDIDATEINFO的子節(jié)點(diǎn)银伟,定義如下:
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 dwPageStart; // index of the first candidate string show in the candidate window. It maybe varies with page up or page down key.
DWORD dwPageSize; // the preference number of the candidate strings shows in one page.
DWORD dwOffset[]; // the start positions of the first candidate strings. Start positions of other (2nd, 3rd, ..) candidate strings are appened after this field. IME can do this by reallocating the hCandInfo memory handle. So IME can access dwOffset[2] (3rd candidate string) or dwOffset[5] (6st candidate string).
// TCHAR chCandidateStr[]; // the array of the candidate strings.
} CANDIDATELIST;
該結(jié)構(gòu)體存儲了一張候選碼表的字符串信息你虹,dwCount為候選碼個數(shù)绘搞,dwOffset[i]為第i個候選碼的首地址偏移量,同樣通過偏移量加結(jié)構(gòu)體首地址的方式可以定位到候選碼字符串的首地址傅物。
通過上述結(jié)構(gòu)體夯辖,已經(jīng)可以在ImeToAsciiEx函數(shù)內(nèi)做字碼轉(zhuǎn)換的操作了(主要是存取用戶輸入字符和修改轉(zhuǎn)換后的候選碼表),然后在用戶輸入窗口和候選碼窗口分別從上述結(jié)構(gòu)體中取出對應(yīng)字符串顯示出來挟伙。
4.3 IME接口調(diào)用順序
測試切換到“我的輸入法”輸入兩個字符楼雹,然后切換出“我的輸入法”,發(fā)現(xiàn)IME接口函數(shù)調(diào)用順序大致如下:ImeInquire, ImeSelect, UIWndProc, StatusWndProc, ImeProcessKey, ImeToAsciiEx, CompWndProc, CandWndProc, UIWndProc, NotifyIME, UIWndProc, CompWndProc, CandWndProc, ImeProcessKey, ImeToAsciiEx, NotifyIME, UIWndProc, NotifyIME, ImeProcessKey, ImeProcessKey, NotifyIME, StatusWndProc, UIWndProc, CompWndProc, CandWndProc, StatusWndProc, UIWndProc, ImeSelect尖阔。
其中ImeInquire是最先被調(diào)用的函數(shù)贮缅,當(dāng)應(yīng)用程序第一次切換到“我的輸入法”時會調(diào)用該函數(shù)進(jìn)行一些初始化操作,應(yīng)用程序多次切換輸入法均不會再調(diào)用該函數(shù)介却。ImeSelect是當(dāng)用戶切換入“我的輸入法”或者切換出“我的輸入法”時調(diào)用的谴供。ImeProcessKey是當(dāng)用戶發(fā)生一次按鍵時調(diào)用,開發(fā)人員可以獲取按鍵信息齿坷,用于判斷按鍵信息是否需要輸入法來處理桂肌,如果需要則返回true,截獲按鍵信息交給ImeToAsciiEx函數(shù)處理永淌。NotifyIME是應(yīng)用程序與輸入法交互的函數(shù)崎场,可以不用理會。UIWndProc遂蛀,StatusWndProc谭跨, CompWndProc, CandWndProc四個函數(shù)之前已經(jīng)介紹了李滴,分別是主窗口螃宙,狀態(tài)窗口,用戶輸入字符串窗口所坯,候選碼窗口四個窗口類的窗口過程函數(shù)谆扎,如果你使用Win32的窗口類來構(gòu)建自己的窗口,則顯示數(shù)據(jù)的任務(wù)在這些回調(diào)函數(shù)內(nèi)編寫芹助,弱否堂湖,則不必理會。所以状土,編寫IME无蜂,大部分任務(wù)就是編寫好ImeProcessKey和ImeToAsciiEx兩個函數(shù),如果不是編寫完全符合IME規(guī)范的輸入法声诸,只需要注意幾個重要函數(shù)即可。
4.4 感想
IME的框架體系還算清晰退盯,但開發(fā)文檔匱乏彼乌,沒有能夠詳細(xì)介紹IME開發(fā)的資料泻肯,進(jìn)行IME開發(fā)最大的難處就是對這些結(jié)構(gòu)體的操作了,沒有比較清晰的范例可以拿來作參考慰照。特別對于不熟悉WIN32API和Windows內(nèi)部消息循環(huán)機(jī)制的開發(fā)人員灶挟,涉及到這種用C語言對結(jié)構(gòu)體內(nèi)存直接做操作的細(xì)節(jié)處,要正確進(jìn)行IME開發(fā)是難上加難毒租。
實(shí)際上稚铣,如果你不是希望編寫完全I(xiàn)ME規(guī)范的輸入法,有幾種方式可以適度地脫離WIN32API的苦海:
定義自己的結(jié)構(gòu)體墅垮。IME開發(fā)文檔定義了眾多復(fù)雜的結(jié)構(gòu)體惕医,這些結(jié)構(gòu)體無非是為了組織一套IME編碼規(guī)范,依照這套規(guī)范你可以不用太關(guān)注過多的IME內(nèi)部細(xì)節(jié)算色。而實(shí)際上抬伺,如果你只希望用到其中一部分特性,可以通過自定義結(jié)構(gòu)體的方式灾梦,強(qiáng)制將IME內(nèi)部結(jié)構(gòu)體轉(zhuǎn)換為自己的方便操作的結(jié)構(gòu)體峡钓,加速開發(fā),自由拼音輸入法即是如此若河。
IME+外掛dll方式能岩。這種方式將IME作為一個與Windows系統(tǒng)溝通的橋梁,而輸入法邏輯完全由外部dll實(shí)現(xiàn)萧福,最大的好處就是可以利用現(xiàn)今高效的開發(fā)語言和工具進(jìn)行開發(fā)拉鹃。搜狗拼音輸入法即是如此,它的ime只有15個標(biāo)準(zhǔn)導(dǎo)出函數(shù)统锤,因此其窗口過程應(yīng)該是外包給外部邏輯去處理毛俏。但要實(shí)現(xiàn)這種方式的前提是對15個導(dǎo)出函數(shù)有充分理解,其中某些會要求填充一些數(shù)據(jù)饲窿。雖然沒有親自實(shí)現(xiàn)煌寇,但個人認(rèn)為可以將IME導(dǎo)出函數(shù)包裝在C++工程內(nèi),然后實(shí)現(xiàn)與C#庫的通訊逾雄,以ImeToAsciiEx作為橋梁阀溶,將輸入法的界面邏輯完全交給C#工程去處理。
最后鸦泳,IME輸入法編程不是一朝一夕能夠掌握银锻,需要具備一定的WIN32編程基礎(chǔ)才行,特別是在這種資料匱乏的前提下做鹰。