輸入法是作業系統核心元件之一,開發門檻較高且資源分散。本文整理作者實作經驗,從輸入法類型比較、IME 架構概念、安裝與除錯技巧,到核心介面(ImeInquire、ImeProcessKey、ImeToAsciiEx、UIWndProc、ImeConfigure)逐一解析,並分享實戰踩坑心得(如 IME_PROP_END_UNLOAD、dwPrivateDataSize、組合字串訊息配對、視窗 WS_DISABLE 技巧、自訂訊息衝突、多進程架構),助您快速跨越入門門檻。
IME 是 Windows 定義的標準輸入法介面規範,本質為一個 DLL,實作並匯出指定介面函式即可被系統識別為輸入法。
由 User.exe 為每個應用程式配置的記憶體控制代碼。輸入法在其中寫入編碼、候選字資料,系統再傳遞給應用程式。理解 HIMC 是處理多視窗、多執行緒輸入狀態的關鍵。
介面 UIWndProc 接收的 hUIWnd 為「僅訊息視窗」,不顯示於螢幕,作為編碼視窗、候選視窗、狀態列的擁有者,負責轉發訊息。開發者無需關心其位置,僅作為訊息管道使用。
Windows\System32。ImmInstallIME 註冊(建議寫小工具自動化,每次重新編譯後執行一次)。ImeInquire 中設定 fdwProperty |= IME_PROP_END_UNLOAD,讓輸入法隨宿主程式(如記事本)結束而卸載,否則修改程式碼後必須重開機才能重新安裝。BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPTSTR lpszUIClass, LPCTSTR lpszOption)
{
lpIMEInfo->dwPrivateDataSize = sizeof(CONTEXTPRIV); // 系統據此配置 INPUTCONTEXT.hPrivate
lpIMEInfo->fdwProperty = IME_PROP_KBD_CHAR_FIRST |
#ifdef _UNICODE
IME_PROP_UNICODE |
#endif
IME_PROP_SPECIAL_UI |
IME_PROP_END_UNLOAD; // ★關鍵:隨宿主程式卸載
lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE;
lpIMEInfo->fdwSentenceCaps = IME_SMODE_NONE;
lpIMEInfo->fdwUICaps = UI_CAP_2700;
lpIMEInfo->fdwSCSCaps = 0;
lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;
_tcscpy(lpszUIClass, CLSNAME_UI);
return TRUE;
}
重點:dwPrivateDataSize 決定 HIMC 私有資料區大小;修改此介面後需重新呼叫 ImmInstallIME 重新安裝。
系統通知輸入法被開啟或關閉,適合做資料初始化或清理。
BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT uKey, LPARAM lKeyData, CONST LPBYTE lpbKeyState)
{
// 返回 TRUE:輸入法自行處理該鍵;FALSE:交給系統處理
}
決定哪些鍵由輸入法處理(如拼音字母)、哪些交給應用程式(如功能鍵)。
最複雜也最重要的介面,負責將鍵盤輸入轉為編碼、候選字,並透過 lpdwTransKey 緩衝區回傳 WM_IME_STARTCOMPOSITION、WM_IME_COMPOSITION、WM_IME_ENDCOMPOSITION 等訊息給 UI 視窗或應用程式。
組合字串訊息配對原則:必須在開始輸入編碼時發送 WM_IME_STARTCOMPOSITION,結束時發送 WM_IME_ENDCOMPOSITION,兩者成對出現。若僅在確定上螢幕時才連發三個訊息,會導致某些應用程式(如遨遊瀏覽器位址列)因攔截控制鍵(Backspace)而誤刪編輯器文字而非編碼視窗內容。
LRESULT WINAPI UIWndProc(HWND hUIWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// 處理編碼視窗、候選視窗、狀態列的顯示/隱藏/更新/繪製
}
所有 UI 相關訊息(建立、銷毀、繪製、滑鼠、鍵盤)皆經由此處分派。
使用者在控制台點選「內容」時觸發,顯示輸入法專屬設定視窗。
| 議題 | 問題 | 解決方案 |
|---|---|---|
視窗 WS_DISABLE |
輸入法視窗若無 WS_DISABLE,啟動時會搶走輸入焦點。 |
建立視窗時加 WS_DISABLE;滑鼠訊息改用 WM_SETCURSOR 攔截並 SetCapture 取得。 |
| 單視窗 vs. 多視窗 | 編碼/候選視窗合併或分離? | 無本質差異。遊戲等 IME-Aware 應用需依其視窗繪製,一般應用可合併簡化。 |
自訂訊息 IMN_PRIVATE |
以為可像 WM_USER 遞增 ID,實則易與系統保留值衝突。 |
僅用一個 IMN_PRIVATE,透過 LPARAM 區分子類型。 |
| 除錯輸出 | 不使用 MFC 時無 TRACE。 |
用 OutputDebugString 封裝 Helper_Trace。 |
| 多進程架構(如拼音加加) | IME DLL 為殼心,核心邏輯在服務進程,透過記憶體映射檔 + 訊息通訊。 | 參考「自由拼音」或作者作品《啟程輸入之星》原始碼。 |
輸入法程式設計指南輸入法開發看似神秘,實則遵循明確的介面規範。掌握核心介面流程、善用除錯技巧、理解 HIMC/UIWnd 機制,並參考成熟開源專案,即可逐步建構屬於自己的輸入法。歡迎交流指正。
本文配套原始碼提供最基礎 IME 框架,去除雜訊,適合初學者快速上手。