一、前言:
自动切换到指定输入法,虽然是个小功能,但对于程序的友好体验,却不是一个小问题。
尤其是文字工作者,体验感非常不爽!
言归正传!
由于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,便是英文状态,即下图: