首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC++

Windows IME 輸入法程式設計實戰:透過登錄檔與 API 動態切換輸入法

     編輯:VC++

前言:VC 缺乏內建 IME 控制項的解決方案

Delphi 許多控件內建 IMEMode、IMEName 等屬性,輕鬆控制輸入法行為。但 Visual C++ (MFC) 並未提供對應的封裝類別。本文示範如何透過登錄檔枚舉已安裝輸入法,再呼叫 Windows API LoadKeyboardLayout 與 ActivateKeyboardLayout 實現動態切換,並提供完整 MFC 對話框範例程式碼。

核心 API 速查表

API用途
RegOpenKey / RegQueryValueEx / RegCloseKey登錄檔讀取:枚舉已安裝/已註冊的輸入法
LoadKeyboardLayout載入指定 KLID(輸入法識別碼),回傳 HKL 輸入法句柄
ActivateKeyboardLayout啟動指定 HKL,使其對當前執行緒/進程生效

登錄檔中輸入法資訊的存放位置

1. 已安裝並預載入的輸入法(使用者層級)

路徑:HKEY_USERS\.DEFAULT\Keyboard Layout\Preload
子鍵名為序號(1, 2, 3...),值為 KLID(8 位十六進位),例如 E0040804。
前 4 碼 E004 為裝置識別碼(如智慧 ABC),後 4 碼 0804 為語言識別碼(簡體中文)。

2. 系統已註冊的輸入法完整資訊(機器層級)

路徑:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\
子鍵名即為 KLID,值包含 Layout Text(顯示名稱)、Layout File(IME DLL 檔名)等詳細資訊。

完整實作步驟與範例程式碼

步驟 1:對話框初始化時枚舉輸入法填入 ComboBox

BOOL CMyDialog::OnInitDialog() {
    CDialog::OnInitDialog();
    HKEY hKeyPreload, hKeyLayout;
    char szSubKey[16], szKLID[16];
    DWORD dwSize = 16;
    int nIndex = 0;
    CString strPreloadBase = _T(".DEFAULT\\Keyboard Layout\\Preload\\");
    
    // 遍歷 Preload 下的數字子鍵 1,2,3...
    for (int i = 1; ; ++i) {
        CString strSubKey;
        strSubKey.Format(_T("%s%d"), strPreloadBase, i);
        if (RegOpenKey(HKEY_USERS, strSubKey, &hKeyPreload) != ERROR_SUCCESS)
            break; // 無更多子鍵
        
        if (RegQueryValueEx(hKeyPreload, NULL, NULL, NULL, (LPBYTE)szKLID, &dwSize) == ERROR_SUCCESS) {
            // 到 Keyboard Layouts 讀取顯示名稱
            CString strLayoutPath = _T("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\") + CString(szKLID);
            if (RegOpenKey(HKEY_LOCAL_MACHINE, strLayoutPath, &hKeyLayout) == ERROR_SUCCESS) {
                BYTE szName[80];
                DWORD dwType = REG_SZ, dwNameSize = 80;
                if (RegQueryValueEx(hKeyLayout, _T("Layout Text"), NULL, &dwType, szName, &dwNameSize) == ERROR_SUCCESS) {
                    m_cbIME.AddString((LPCTSTR)szName); // 顯示友善名稱
                    m_arrKLID.Add(CString(szKLID));     // 陣列保存對應 KLID
                }
                RegCloseKey(hKeyLayout);
            }
        }
        RegCloseKey(hKeyPreload);
    }
    m_cbIME.SetCurSel(0);
    return TRUE;
}

步驟 2:Edit 控制項獲得焦點時啟動選定輸入法

void CMyDialog::OnSetfocusEdit() {
    int nSel = m_cbIME.GetCurSel();
    if (nSel == CB_ERR) return;
    CString strKLID = m_arrKLID[nSel];
    
    HKL hkl = LoadKeyboardLayout(strKLID, KLF_ACTIVATE);
    if (hkl) {
        ActivateKeyboardLayout(hkl, KLF_SETFORPROCESS);
    }
}

步驟 3:使用者切換 ComboBox 選項時強制 Edit 重新獲取焦點套用新輸入法

void CMyDialog::OnSelchangeComboIME() {
    m_editTarget.SetFocus(); // 觸發 EN_SETFOCUS 再次執行步驟 2
}

Windows 2000 / XP 以上版本的差異注意

Win2000 之後,HKEY_USERS\.DEFAULT\Keyboard Layout\Preload 下不再有數字子鍵,改為直接在該鍵值中以數字為名稱、KLID 為資料。枚舉時需改用 RegEnumValue 而非 RegEnumKeyEx。

總結

雖然 MFC 無內建 IME 控制項,但結合登錄檔枚舉與 LoadKeyboardLayout/ActivateKeyboardLayout 兩大核心 API,即可構建完整的動態輸入法切換功能。關鍵在於正確解析 KLID、對應顯示名稱,並在編輯控制項焦點事件中適時啟動。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved