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

C# 程式切換輸入法:指定 IME (如陳橋智能) 的完整實作

     編輯:關於C語言

前言

在 WinForms/WPF 應用中,有時需要依據欄位屬性(如中文欄位自動切換中文輸入法、英文欄位切回英數)。本文示範如何列舉系統已安裝輸入法、依名稱比對切換、處理找不到時的降級邏輯,並說明 WPF 的 InputMethod 替代方案。

WinForms 實作


using System;
using System.Linq;
using System.Windows.Forms;
using System.Globalization;

public static class InputMethodHelper
{
    /// 
    /// 依 LayoutName 關鍵字尋找並切換輸入法
    /// 
    /// 輸入法名稱關鍵字,如 "陳橋", "Microsoft Pinyin", "IME"
    /// 找不到時是否回預設輸入法
    /// 是否成功切換
    public static bool SwitchInputMethod(string keyword, bool fallbackToDefault = true)
    {
        if (string.IsNullOrWhiteSpace(keyword)) return false;

        var installed = InputLanguage.InstalledInputLanguages;
        InputLanguage target = null;

        // 1. 完全比對 LayoutName
        target = installed.Cast()
                          .FirstOrDefault(il => il.LayoutName.Equals(keyword, StringComparison.OrdinalIgnoreCase));

        // 2. 關鍵字模糊比對
        if (target == null)
            target = installed.Cast()
                              .FirstOrDefault(il => il.LayoutName.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0);

        // 3. 文化特性比對 (如 zh-TW, zh-CN)
        if (target == null && CultureInfo.GetCultures(CultureTypes.AllCultures)
                                         .Any(c => c.Name.Contains(keyword, StringComparison.OrdinalIgnoreCase)))
        {
            var ci = CultureInfo.GetCultures(CultureTypes.AllCultures)
                                .First(c => c.Name.Contains(keyword, StringComparison.OrdinalIgnoreCase));
            target = installed.Cast().FirstOrDefault(il => il.Culture.LCID == ci.LCID);
        }

        if (target != null)
        {
            InputLanguage.CurrentInputLanguage = target;
            return true;
        }

        if (fallbackToDefault)
        {
            InputLanguage.CurrentInputLanguage = InputLanguage.DefaultInputLanguage;
        }
        return false;
    }

    /// 
    /// 列印所有已安裝輸入法 (除錯用)
    /// 
    public static void PrintInstalledInputMethods()
    {
        foreach (InputLanguage il in InputLanguage.InstalledInputLanguages)
        {
            Console.WriteLine($"Culture: {il.Culture.DisplayName} ({il.Culture.Name}) | Layout: {il.LayoutName} | Handle: {il.Handle}");
        }
    }
}

// 使用範例:在 TextBox Enter/Leave 事件切換
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        txtChinese.Enter += (s, e) => InputMethodHelper.SwitchInputMethod("陳橋"); // 或 "Microsoft Pinyin"
        txtEnglish.Enter += (s, e) => InputMethodHelper.SwitchInputMethod("US");    // 美式鍵盤
    }
}

WPF 實作

WPF 採用 InputMethod 附加屬性,不直接操作 InputLanguage。







using System.Windows.Input;
InputMethod.SetPreferredImeState(txtChinese, ImeState.On);
InputMethod.SetPreferredImeConversionMode(txtChinese, ImeConversionModeValues.Native);
WPF 無法直接指定特定 IME (如陳橋),僅能開啟/關閉 IME 模式。若需強制指定,需 P/Invoke imm32.dll (ImmAssociateContextEx) 或呼叫 WinForms 邏輯 (需參考 System.Windows.Forms)。

進階:P/Invoke 強制指定 IME (Win32 API)


using System;
using System.Runtime.InteropServices;

public static class Imm32
{
    [DllImport("imm32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr ImmGetContext(IntPtr hWnd);

    [DllImport("imm32.dll", CharSet = CharSet.Auto)]
    public static extern bool ImmSetConversionStatus(IntPtr hIMC, uint fdwConversion, uint fdwSentence);

    [DllImport("imm32.dll", CharSet = CharSet.Auto)]
    public static extern bool ImmAssociateContextEx(IntPtr hWnd, IntPtr hIMC, uint dwFlags);

    [DllImport("imm32.dll", CharSet = CharSet.Auto)]
    public static extern bool ImmGetDescription(IntPtr hkl, StringBuilder lpszDescription, int uBufLen);

    public const uint IME_CMODE_NATIVE = 0x0001;
    public const uint IME_CMODE_FULLSHAPE = 0x0008;
}

// 使用:取得目標 IME 的 HKL (Keyboard Layout Handle) 並關聯
// 注意:需先列舉系統 HKL (GetKeyboardLayoutList) 比對描述
P/Invoke 複雜且易受 OS 版本影響,非必要不建議。優先使用 InputLanguage.CurrentInputLanguage 切換。

常見問題排查

現象原因解決
切換無效果目標輸入法未安裝或 LayoutName 不同呼叫 PrintInstalledInputMethods() 確認確切名稱
切換後立即跳回控制項焦點移動觸發系統自動還原在 Enter 事件切換,避免 Leave 干擾
WPF 無法指定特定 IME架構限制使用 WinForms 互通或 P/Invoke
管理員權限下失效UIPI (User Interface Privilege Isolation)避免跨權限視窗操作,或簽署應用程式

最佳實務封裝


public static class InputMethodManager
{
    private static readonly Dictionary _cache = new();

    static InputMethodManager()
    {
        foreach (InputLanguage il in InputLanguage.InstalledInputLanguages)
        {
            _cache[il.LayoutName.ToLowerInvariant()] = il;
            _cache[il.Culture.Name.ToLowerInvariant()] = il;
        }
    }

    public static bool TrySet(string identifier) // identifier: "zh-TW", "陳橋", "Microsoft Pinyin", "US"
    {
        if (_cache.TryGetValue(identifier.ToLowerInvariant(), out var lang))
        {
            InputLanguage.CurrentInputLanguage = lang;
            return true;
        }
        return false;
    }

    public static IReadOnlyList GetAvailableIdentifiers() => _cache.Keys.ToList();
}

總結

WinForms 透過 InputLanguage.CurrentInputLanguage 可完整控制輸入法切換;WPF 僅支援開關 IME 狀態。建立快取輔助類別、在控制項 Enter 事件切換、提供降級預設邏輯,即能滿足多數「中文欄位自動切中文輸入法」的實務需求。

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