以下內容摘自http://msdn.microsoft.com/zh-cn/goglobal/bb688135.aspx
在 Win32 中處理輸入語言的方法
Microsoft Developer Network (MSDN) 文檔(位於 http://msdn.microsoft.com)和編程 API 用一種名為“輸入法區域設置標識符”的變量類型代表輸入語言,它在先前的文檔中被稱為“鍵盤布局處理”(HKL) 並且現在仍被用作類型標識符。HKL 是一種古老的名稱,當時只能從鍵盤進行輸入。輸入法區域設置標識符名稱是一個 32 位的值,它由語言標識符(低 WORD)和設備標識符(高 WORD)的十六進制值組成。(參見下方的圖 7。)例如,美國英語的語言標識符為 0x0409,因此美國英語主布局被命名為 "00000409"。美國英語布局的變體(例如 Dvorak 布局)被命名為 "00010409"、"00020409" 等。設備標識符並不僅限於鍵盤和 IME;現在可通過一些較復雜的機制(例如語音和文字識別引擎)來輸入數據。例如,在 Windows XP 中作為一種系統服務提供的 Microsoft Windows Text Services Framework (TSF),它可以實現與來源無關的高級文字輸入。(有關 TSF 的更多信息,請參閱 Text Services Framework)。

圖 7:代表輸入語言的 HKL 變量。
處理輸入語言最簡單的方式是在需要用戶輸入的所有場合都使用操作系統提供的標准控件。例如,通過使用 Unicode 編輯控件或 Rich edit 控件,可以使應用程序能夠處理多種語言的文字輸入。操作系統會以一種對應用程序透明的方式自動處理輸入語言。文字 API 使用的是一種標准的多行編輯控件,它可以避免處理輸入語言時的麻煩。
對於一些需要完全控制輸入語言處理方式的高級應用程序(例如文本編輯器),它們應該監視(並能夠響應)用戶的改動。當用戶通過單擊任務欄上的語言指示符或按下“左邊 Alt+Shift”鍵來選擇某種輸入語言時,輸入語言不會自動改變 – 兩個操作都會生成一個活動的應用程序必須接受或拒絕的請求。為了響應熱鍵組合或鼠標單擊任務欄上的語言指示符后產生的事件,系統會向焦點窗口發送一個 WM_INPUTLANGCHANGEREQUEST 消息,如下圖所示。如果應用程序接受該消息並將其傳遞給DefWindowProc,系統將啟動切換輸入語言的操作並發送一個 WM_INPUTLANGCHANGE 消息。如果輸入法是 Text Services Framework (TSF) 的一部分,則此過程會略有不同,這時只發送 WM_INPUTLANGCHANGE。當系統成功完成改變后,會生成一個 WM_INPUTLANGCHANGE 消息。WM_INPUTLANGCHANGE 消息的 lParam 變量包含新輸入語言的輸入法區域設置標識符(即 HKL)。

圖 8:WM_INPUTLANGCHANGEREQUEST 和 WM_INPUTLANGCHANGE 消息傳播流程圖。
不支持多語言的應用程序會拒絕 WM_INPUTLANGCHANGEREQUEST 消息。它可能會拒絕任何或全部 WM_INPUTLANGCHANGEREQUEST 消息,也可能會先執行一些測試。例如,此消息的 wParam 變量是一個 Boolean 值 bLangInSystemCharset,它將指出請求的輸入語言是否能夠在當前的系統區域設置中呈現出來。在處理 Unicode 應用程序時呈現輸入語言並不麻煩,但是,非 Unicode 應用程序應該監視此值(實際上也是如此),否則它們會顯示錯誤的字符。
與生成 WM_INPUTLANGCHANGEREQUEST 消息來響應用戶請求的系統類似,應用程序也會通過調用 ActivateKeyboardLayout API 來啟動改變輸入語言的操作。如果用戶編輯包含拉丁文和希臘文的文檔,當用戶將插入點從拉丁文字移動到希臘文字時,將會自動激活希臘文輸入法。(參見下方的表 4。)同樣,當此用戶將插入點移回拉丁文字時,應用程序將激活默認的基於拉丁文的輸入法。

圖 9:當光標被定位到希臘文文本流中時,活動的鍵盤布局會切換到希臘文。
處理輸入法的其他 Win32 API 如下方的表 4 所示:

表 4
在設計允許用戶切換鍵盤布局的功能時,要清楚由於不同布局的鍵盤上字母排列各不相同,因此用來生成快捷鍵組合的按鍵可能也會有所變化。例如,法語鍵盤默認為 AZERTY 布局,而英語布局采用 QWERTY 映射。因此,建議您在快捷鍵組合中使用數字和功能鍵(F4、F5 等),而不要使用字母。
除了使您的應用程序能夠處理各種輸入語言外,您還需要使其能夠支持 IME。(請注意,如果您使用標准 API 進行輸入,您的應用程序將會自動處理 IME。)通過啟用 IME 支持,您的用戶將可以輸入象形文字,例如,從各種東亞書寫系統輸入。以下各節將探究 IME 的用途,並提供支持 IME 的最佳實際示例和技術解決方案。
IME 系統的工作方式
Windows 2000 和 Windows XP 中的 IME 模塊適合於向應用程序傳遞用戶輸入信息的大型機制,而且像其他輸入法一樣,最簡單、最安全的輸入內容處理方式是使用標准系統控件,例如編輯字段和 Rich edit 控件等。如果您不是要編寫 IME 軟件包或自定義自己的 IME 用戶界面 (UI),您可以使用標准輸入 API,它可以為您處理 IME 的所有復雜情況。
對某種輸入語言來說,是使用 IME 還是使用鍵盤來輸入對用戶而言都完全透明。無論用戶是切換 IME 還是西方鍵盤布局,過程都完全相同。這兩種操作都是通過單擊任務欄上的語言指示符或輸入某個快捷鍵組合來完成。而且,應用程序不關心使用的輸入法,因為切換 IME 與切換鍵盤布局會生成同樣的消息:WM_INPUTLANGCHANGEREQUEST(如果 IME 不是 TSF 的一部分)和 WM_INPUTLANGCHANGE。應用程序可通過調用 ActivateKeyboardLayout 來激活特定的 IME。IMM 可以作為中介來管理 IME 與應用程序之間的通信。當用戶使用 IME 鍵入信息時,每個按鍵都發出一條帶有 GCS_COMPSTR 標記的 WM_IME_COMPOSITION 消息,指出合成字符串有更新。消息的 WPARAM 值將返回字符串的第一個字符,其余字符可以通過帶有相同 GCS_COMPSTR 標記的 ImmGetCompositionString API 進行檢索。然后當用戶按下 Enter 鍵或單擊某個字符在文檔中放置它時,默認情況下,IME 會發出一條帶有 GCS_RESULTSTR 標記的 WM_IME_COMPOSITION 消息。(您可以使用相同的 API 和 GCS_RESULTSTR 標記來檢索提交的字符串。)如果后面的 WM_IME_COMPOSITION 消息被發送到 DefWindowProc,則對於所提交字符串中的每個字符,它都會發出一條包含實際字符的 WM_IME_CHAR 消息。對於非 Unicode 窗口,如果 WM_IME_CHAR 消息包括一個雙字節字符並且應用程序將此消息傳遞給 DefWindowProc,則 IME 會將此消息轉換為兩條 WM_CHAR 消息,每條包含雙字節字符中的一個字節。如果應用程序略過任何一條消息,則它將由應用程序的 DefWindowProc 函數進行處理,此函數會通知 IMM 該消息被忽略。IME 然后會通過多個 WM_CHAR 消息逐字節重新發送字符或字符串。對於 Unicode 窗口,WM_IME_CHAR 和 WM_CHAR 是相同的。
以下各節將討論對於 Windows 中所運行應用程序的三個離散的 IME 支持級別:不支持、部分支持和完全自定義的支持。應用程序可以小規模自定義 IME 支持(例如通過重新定位窗口),也可以徹底改變 IME UI 的外觀。
無 IME 支持:不識別 IME 的應用程序通常會忽略所有特定於 IME 的 Windows 消息。大多數針對單字節語言的應用程序不能識別 IME。
不識別 IME 的應用程序會通過預定義的全局類(對應被稱為 "IME")來繼承活動 IME 的默認 UI。這一全局類具有與基於 Windows 的任何其他常用控件相同的特性。對於每個線程而言,Windows 2000 和 Windows XP 都會根據 IME 全局類自動創建一個窗口,所有不識別 IME 的線程窗口都會共用此默認的 IME 窗口。不識別 IME 的應用程序將關於 IME 的消息傳遞給 DefWindowProc 函數時,DefWindowProc 會將其發送到默認 IME 窗口。
部分 IME 支持:識別 IME 的應用程序可以創建其自己的 IME 窗口。部分支持 IME 的應用程序可以使用此應用程序 IME 窗口來控制特定的 IME 行為。例如,通過調用函數 ImmIsUIMessage,應用程序可以將與 IME 的 UI 相關的消息傳遞給應用程序的 IME 窗口,應用程序可以在這里處理這些消息。下列代碼(包括適當的錯誤處理和可能更多已處理的消息)會出現在應用程序的 IME 窗口的窗口過程中:
HIMC hIMC; LPVOID lpBufResult; COMPOSITIONFORM cf; DWORD dwBufLen; if (ImmIsUIMessage(hIMEWnd, uMsg, wParam, lParam) == TRUE) { switch(uMsg) { case WM_IME_COMPOSITION: if (lParam & GCS_RESULTSTR { hIMC = ImmGetContext(hWnd); dwBufLen = ImmGetCompositionString(hIMC, GCS_RESULTSTR, NULL, NULL) + sizeof(TCHAR); lpBufResult =?malloc(dwBufLen); if(ImmGetCompositionString(hIMC, GCS_RESULTSTR, lpBufResult, dwBufLen) > 0) { // ... // process the text in lpBufResult // ... } else // a negative error value was returned { // ... // handle an error // ... } free(lpBufResult); ImmReleaseContext(hWnd, hIMC); } break; } } return 0; }
同樣的窗口過程可能會調用 SendMessage 來重新配置狀態、復合或候選窗口,或打開、關閉狀態窗口。
SendMessage(hIMEWnd, WM_IME_CONTROL,
IMC_SETCOMPOSITIONWINDOW, "cf);
允許應用程序變更窗口位置或屬性的其他 API 函數包括ImmSetCandidateWindow、ImmSetCompositionFont、ImmSet-CompositionString、ImmSetCompositionWindow 以及 ImmSetStatusWindowPos。包含部分 IME 支持的應用程序可使用這些函數來設置 IME UI 窗口的樣式和位置,但是 IME 動態鏈接庫 (DLL) 仍負責繪制這些窗口 – IME UI 的常規外觀將保持不變。
完全 IME 支持則截然不同,完全識別 IME 的應用程序將接管通過 IME DLL 繪制 IME 窗口(狀態、復合以及候選窗口)的工作。此類應用程序可以完全自定義這些窗口的外觀,包括確定其屏幕位置以及選擇使用哪些字體和字體樣式來顯示窗口中的字符。對於文字處理程序以及主要功能是文字處理的類似程序,這會使它們從流暢的 IME 交互以及創建“自然的”用戶交互界面中受益,因此顯得特別方便和有效。IME DLL 仍將決定在 IME 復合窗口和候選窗口中顯示的字符,並且它還會運用算法來猜測字符並在 IME 字典中查找它們。FULLIME 是一個自定義 IME UI 的示例,可以在 Microsoft Windows Platform SDK 中找到它,網址為http://msdn.microsoft.com。
完全識別 IME 的應用程序將通過下列方式捕獲與 IME 相關的消息
- 它們調用 GetMessage 來檢索中間 IME 消息。
- 它們在應用程序 WindowProc 中處理這些消息。
- 它們調用 TranslateMessage(IMM 的一部分)將消息傳遞到 IME DLL。像鍵盤驅動程序一樣,IME 也需要同步靜止鍵。請記住,如果使用標准輸入調用(例如對 Rich Edit 控件的調用),部分 IME 支持可為您處理一切問題。
您已確信您的應用程序可以處理不同的輸入語言和方法。確保您的應用程序可以支持多語言輸入、輸出以及顯示的另一項任務是滿足復雜腳本提出的固有要求。在隨后的各節中,您將會看到與復雜腳本相關聯的各種語言特點,並將了解到 Windows 對處理復雜腳本所提供的支持。
