C# 切换(指定)输入法——Windows10,11

本文介绍了如何通过C#编程在Windows10/11中操作注册表和API实现自动切换指定输入法,包括设置默认输入法的逻辑、具体代码示例以及遇到的两个主要问题。作者分享了部分解决方案和后续改进的方向。
摘要由CSDN通过智能技术生成

一、前言:

    自动切换到指定输入法,虽然是个小功能,但对于程序的友好体验,却不是一个小问题。

   尤其是文字工作者,体验感非常不爽!

    言归正传!

    由于Windows10,11输入法框架的原因,C#想要做到切换指定的输入法,直接操作是做不到的。

    故而,我选择了取巧的方式,来达到这一目的。

二、编程逻辑:

    1.通过C#操作注册表,将指定的输入法,在程序打开时,设置成为默认的输入法。

     2.调用API,将程序当前的输入法,切换到默许输入法。

三、编程代码:

using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp7
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

        [DllImport("kernel32.dll")]
        public static extern uint GetCurrentThreadId();

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetKeyboardLayout(uint idThread);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr LoadKeyboardLayout(string pwszKLID, uint Flags);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetConsoleWindow();
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SetForegroundWindow(IntPtr intPtr);

        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        public const uint WM_INPUTLANGCHANGEREQUEST = 0x0050;
        public const uint KLF_ACTIVATE = 1;
        const int WM_KEYDOWN = 0x100; // Key down message
        const int WM_CHAR = 0x102;


        private void Form1_Load(object sender, EventArgs e)
        {
            #region 设置搜狗五笔输入为系统默认输入法-第三版
            RegistryKey Key = Registry.CurrentUser;
            //打开注册表输入法项
            RegistryKey keySoft = Key.OpenSubKey("SOFTWARE\\Microsoft\\CTF\\SortOrder\\AssemblyItem\\0x00000804\\{34745C63-B2F0-4784-8B67-5E12C8701A31}", true);
            string[] arrNames = keySoft.GetSubKeyNames();//获取系统安装的输入数组

            string[] clsids = new string[arrNames.Length];//创建 CLSID 数组,用于存储其值
            string[] profiles = new string[arrNames.Length];//创建 Profile 数组,用于存储其值
            int[] keyBoards = new int[arrNames.Length];//创建 KeyboardLayout 数组,用于存储其值
            string[] fmainPaths = new string[arrNames.Length];//创建注册表中,输入法的完整路径数组

            //输入法主要路径
            string mainPath = "SOFTWARE\\Microsoft\\CTF\\SortOrder\\AssemblyItem\\0x00000804\\{34745C63-B2F0-4784-8B67-5E12C8701A31}\\";
            string clsValue = "{E7EA138F-69F8-11D7-A6EA-00065B844310}";//【搜狗五笔输入法】的CLSID值
            string swpValue = "{E7EA1390-69F8-11D7-A6EA-00065B844311}";//【搜狗五笔输入法】的 Profile 值
            string defAssPath = "SOFTWARE\\Microsoft\\CTF\\Assemblies\\0x00000804\\{34745C63-B2F0-4784-8B67-5E12C8701A31}";
            int layNum = 134481924;

            //获得所有输入法的 CLSID值、Profile值、KeyboardLayout值,及完整路径,并将其存储到相应数组中
            for (int f = 0; f < arrNames.Length; f++)
            {
                fmainPaths[f] = mainPath + arrNames[f];//完整路径值获取、储存

                RegistryKey ckey = Key.OpenSubKey(fmainPaths[f], true);

                clsids[f] = ckey.GetValue("CLSID").ToString();// CLSID 值获取、储存
                profiles[f] = ckey.GetValue("Profile").ToString();// Profile 值获取、储存
                keyBoards[f] = int.Parse(ckey.GetValue("KeyboardLayout").ToString());// KeyboardLayout 值获取、储存
                ckey.Close();
            }

            int pID = 0;//【搜狗五笔输入法】索引变量

            //依据【搜狗五笔输入法】的 Profile 值进行判断,得到【搜狗五笔输入法】在系统输入法菜单中的索引值
            for (int p = 0; p < profiles.Length; p++)
            {
                if (profiles[p] == swpValue)
                {
                    pID = p;
                    Console.WriteLine(pID);//输入出搜狗五笔输入法,在任务栏中的位置
                    break;
                }
            }

            if (pID != 0)//【搜狗五笔输入法】在系统输入法菜单中,不为默认输入法时执行
            {
                RegistryKey defKey = Key.CreateSubKey(fmainPaths[0], RegistryKeyPermissionCheck.ReadWriteSubTree);//默认值操作
                RegistryKey defAssKey = Key.CreateSubKey(defAssPath, RegistryKeyPermissionCheck.ReadWriteSubTree);

                //defKey.SetValue("CLSID", clsids[pID]);
                //defKey.SetValue("Profile", profiles[pID]);
                defKey.SetValue("CLSID", clsValue);//将【搜狗五笔输入法】CLSID 值,写入到默认输入法栏
                defKey.SetValue("Profile", swpValue);//将【搜狗五笔输入法】Profile 值,写入到默认输入法栏
                defKey.SetValue("KeyboardLayout", keyBoards[pID], RegistryValueKind.DWord);//将【搜狗五笔输入法】KeyboardLayout 值,写入到默认输入法栏
                defAssKey.SetValue("Default", clsValue);
                defAssKey.SetValue("Profile", swpValue);
                defAssKey.SetValue("KeyboardLayout", layNum, RegistryValueKind.DWord);
                defAssKey.Close();
                defKey.Close();

                RegistryKey renKey = Key.CreateSubKey(fmainPaths[pID], RegistryKeyPermissionCheck.ReadWriteSubTree);//更新值

                //将原输入法的CLSID、Profile、KeyboardLayout 值,更新到原【搜狗五笔输入法】在系统输入法菜单中,相应的位置。
                renKey.SetValue("KeyboardLayout", keyBoards[0], RegistryValueKind.DWord);
                renKey.SetValue("CLSID", clsids[0]);
                renKey.SetValue("Profile", profiles[0]);

                renKey.Close();
                Key.Close();
                Console.WriteLine("运行到这里了!+1");

                //以下程序仅供思路参考!不建议使用!
                /*
                #region 切换搜狗五笔输入法
                // 获取搜狗输入法的键盘布局ID
                string sogouKLID = "134481924"; // 搜狗输入法的键盘布局ID

                // 获取当前前台窗口句柄
                IntPtr foregroundWindow = GetForegroundWindow();

                // 获取前台窗口所属进程ID
                GetWindowThreadProcessId(foregroundWindow, out uint processId);

                // 获取当前线程ID
                uint currentThreadId = GetCurrentThreadId();

                // 获取当前线程的键盘布局
                IntPtr currentLayout = GetKeyboardLayout(currentThreadId);
                Console.WriteLine(currentLayout.ToString());

                // 如果当前键盘布局不是搜狗输入法,则切换到搜狗输入法
                if (currentLayout.ToString() != sogouKLID)
                {
                    // 加载搜狗输入法的键盘布局
                    IntPtr sogouLayout = LoadKeyboardLayout(sogouKLID, KLF_ACTIVATE);

                    // 发送切换输入法的消息
                    PostMessage(foregroundWindow, WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, sogouLayout);
                }
                #endregion

                */
            }
            if (pID == 0)//【搜狗五笔输入法】在系统输入法菜单中,为默认输入法时不执行
            {
                Console.WriteLine("运行到这里了!");
                Key.Close();
                
            }
            #endregion
        }

        private void richTextBox1_Enter(object sender, EventArgs e)
        {
            //以下的代码有些鸡肋,目前还没有想到解决办法,先暂时保留!
            /*
            InputLanguage currentInputLanguage = InputLanguage.CurrentInputLanguage;
            Console.WriteLine(currentInputLanguage.LayoutName);
            if (currentInputLanguage.LayoutName != "Chinese")//通过输入法的名字进行判断,不可取!替代方案为GUID(暂时思绪)
            {
                //IntPtr targetHwnd= GetForegroundWindow(); // GetConsoleWindow()函数获取控制台窗口句柄
                IntPtr targetHwnd = FindWindow(null, "Form1");
                if (targetHwnd != IntPtr.Zero)
                {
                    SendKeys.SendWait("%+Shift");
                    Thread.Sleep(200); // 等待操作系统处理消息
                    SendKeys.SendWait("%+Shift");
                    Console.WriteLine("当前输入模式为中文");
                }
            }*/
        }
    }
}

以上的代码,在windows10、11,均可以将搜狗五笔输入法,设置成为默认输入法。

接下来的代码,是调用API,切换到默认输入法:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp7
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }
        // 导入user32.dll库文件
        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetForegroundWindow();
        const int WM_INPUTLANGCHANGEREQUEST = 0x50;
        const int INPUTLANGCHANGE_FORWARD = 1;
        private void Form2_Load(object sender, EventArgs e)
        {
            IntPtr activeWindowHandle = GetForegroundWindow();

            if (activeWindowHandle != IntPtr.Zero)
            {
                // 发送消息通知系统要求更改输入语言
                SendMessage(activeWindowHandle, WM_INPUTLANGCHANGEREQUEST, new IntPtr(INPUTLANGCHANGE_FORWARD), IntPtr.Zero);

                Console.WriteLine("已成功将当前输入法切换至默认输入法");
            }
            else
            {
                Console.WriteLine("无法确定当前活动窗口的句柄");
            }
        }
    }
}

第二篇代码,来自于百度AI,CSDN-AI,A小快,三个AI整理而来,可以作为单独的代码使用,不用与第一篇代码融合。

三、BUG整理:

1.第一篇代码,与第二篇代码,虽然可以融合在一起。但始终有两个BUG去不掉。

这个输入状态,是我想要的,可实际上却是下面的状态:

程序打开时,出现这个状态,我就要切换一下,有点不合初衷。

2.第二BUG,便是英文状态,即下图:

四、总结:

    可以看出来,我的思路,虽然有一定的可行性,但其中还有几个关键点,需要突破。虽然这样的代码发出来,多少有些不负责。但考虑到,我的错误之处,也是有一定的参考价值,还是将其发出来,给你的成功路上,添上一块垫脚石。

     目前,我使用的方法,是第二篇代码,虽然也有些问题,但还是勉强能用。

     后续的思路,仍在完善之中!

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C# 中,要切换系统的输入法,可以使用 `System.Windows.Forms.InputLanguage` 类来实现。您可以使用 `InputLanguage.CurrentInputLanguage` 属性获取当前系统的输入法,然后使用 `InputLanguage.InstalledInputLanguages` 属性获取所有可用的输入法列表。 以下是一个示例代码,演示如何切换系统的英文输入法并执行完逻辑后切换回原有输入法: ```csharp using System; using System.Windows.Forms; class Program { static void Main() { // 获取当前输入法 InputLanguage originalInputLanguage = InputLanguage.CurrentInputLanguage; try { // 切换到英文输入法 InputLanguage englishInputLanguage = GetEnglishInputLanguage(); InputLanguage.CurrentInputLanguage = englishInputLanguage; // 执行逻辑 Console.WriteLine("当前输入法:{0}", InputLanguage.CurrentInputLanguage.Culture.DisplayName); Console.WriteLine("执行逻辑..."); // 等待一段时间,以便观察效果 System.Threading.Thread.Sleep(2000); } finally { // 切换回原有输入法 InputLanguage.CurrentInputLanguage = originalInputLanguage; } Console.WriteLine("当前输入法:{0}", InputLanguage.CurrentInputLanguage.Culture.DisplayName); Console.WriteLine("逻辑执行完毕。"); // 等待用户按下任意键终止程序 Console.ReadKey(); } static InputLanguage GetEnglishInputLanguage() { foreach (InputLanguage inputLanguage in InputLanguage.InstalledInputLanguages) { if (inputLanguage.Culture.TwoLetterISOLanguageName.Equals("en")) { return inputLanguage; } } throw new NotSupportedException("English input language not found."); } } ``` 在上述示例中,我们首先保存了当前的输入法到 `originalInputLanguage` 变量中。然后使用 `GetEnglishInputLanguage` 方法获取英文输入法,并将其赋值给 `InputLanguage.CurrentInputLanguage` 来切换到英文输入法。 在执行完逻辑后,无论是否发生异常,我们都会切换回原有的输入法,以确保系统状态的恢复。 希望这个示例对您有所帮助。如果您还有其他问题,请随时提问!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值