很多C#开发者在开发桌面应用时,会有集成自定义输入法功能的需求,比如实现特定场景的快捷输入、行业专用词库输入等。下面我们就基于WinForms框架,分享一个基础的输入法实现实例,涵盖核心功能的代码逻辑。

核心实现思路
实现输入法功能主要需要解决三个核心问题:监听全局或应用内的键盘输入、维护候选词列表并展示、将选中的候选词上屏到目标输入框。我们这里先实现应用内的输入法功能,后续可以扩展为全局输入法。
1. 键盘事件监听
首先需要监听键盘的按键事件,捕获用户输入的拼音或编码,这里我们使用KeyDown事件来处理按键输入,过滤掉功能键,只处理字母和数字等输入内容。
2. 候选词管理
需要维护一个候选词列表,这里为了简化,我们先用一个静态的字典模拟词库,实际开发中可以替换为本地词库或网络词库查询逻辑。
3. 候选词展示与上屏
用一个浮动窗口展示候选词,用户通过数字键选择对应的候选词,然后将选中的词输出到当前获得焦点的输入框中。
完整实例代码
下面是完整的WinForms项目代码,你可以直接新建WinForms项目,替换Form1的代码运行查看效果。
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace CustomInputMethodDemo
{
public partial class Form1 : Form
{
// 模拟词库,键为输入的拼音,值为对应的候选词列表
private readonly Dictionary<string, List<string>> _wordDict = new Dictionary<string, List<string>>
{
{"wo", new List<string> {"我", "窝", "沃", "卧"} },
{"ai", new List<string> {"爱", "哎", "唉", "矮"} },
{"ni", new List<string> {"你", "尼", "泥", "倪"} },
{"hao", new List<string> {"好", "号", "毫", "豪"} }
};
// 当前输入的编码字符串
private string _currentInput = "";
// 候选词窗口
private Form _candidateForm;
// 候选词按钮列表
private List<Button> _candidateButtons = new List<Button>();
// 获取当前焦点控件的API
[DllImport("user32.dll")]
private static extern IntPtr GetFocus();
public Form1()
{
InitializeComponent();
InitUI();
InitCandidateForm();
// 监听窗体的键盘事件
this.KeyDown += Form1_KeyDown;
this.KeyPreview = true;
}
/// <summary>
/// 初始化主界面UI
/// </summary>
private void InitUI()
{
this.Text = "C#自定义输入法示例";
this.Size = new Size(600, 400);
TextBox inputBox = new TextBox();
inputBox.Name = "inputBox";
inputBox.Location = new Point(50, 50);
inputBox.Size = new Size(300, 25);
this.Controls.Add(inputBox);
Label tipLabel = new Label();
tipLabel.Text = "在输入框中输入拼音,按空格查询候选词,数字键1-4选择上屏";
tipLabel.Location = new Point(50, 20);
tipLabel.Size = new Size(400, 20);
this.Controls.Add(tipLabel);
}
/// <summary>
/// 初始化候选词窗口
/// </summary>
private void InitCandidateForm()
{
_candidateForm = new Form();
_candidateForm.FormBorderStyle = FormBorderStyle.None;
_candidateForm.StartPosition = FormStartPosition.Manual;
_candidateForm.Size = new Size(200, 30);
_candidateForm.BackColor = Color.LightGray;
_candidateForm.TopMost = true;
_candidateForm.Visible = false;
// 创建4个候选词按钮
for (int i = 0; i < 4; i++)
{
Button btn = new Button();
btn.Size = new Size(45, 25);
btn.Location = new Point(i * 50, 2);
btn.Tag = i;
btn.Click += CandidateBtn_Click;
_candidateButtons.Add(btn);
_candidateForm.Controls.Add(btn);
}
}
/// <summary>
/// 候选词按钮点击事件,将选中的词上屏
/// </summary>
private void CandidateBtn_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
if (btn != null && !string.IsNullOrEmpty(btn.Text))
{
string selectedWord = btn.Text;
InputSelectedWord(selectedWord);
}
}
/// <summary>
/// 键盘事件处理
/// </summary>
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
// 处理字母输入,拼接到当前输入字符串
if (e.KeyCode >= Keys.A && e.KeyCode <= Keys.Z)
{
_currentInput += e.KeyCode.ToString().ToLower();
e.Handled = true;
UpdateCandidateForm();
}
// 处理退格键,删除最后一个字符
else if (e.KeyCode == Keys.Back && _currentInput.Length > 0)
{
_currentInput = _currentInput.Substring(0, _currentInput.Length - 1);
e.Handled = true;
UpdateCandidateForm();
}
// 处理空格键,查询候选词
else if (e.KeyCode == Keys.Space)
{
UpdateCandidateForm();
e.Handled = true;
}
// 处理数字键1-4,选择对应的候选词上屏
else if (e.KeyCode >= Keys.D1 && e.KeyCode <= Keys.D4)
{
int index = e.KeyCode - Keys.D1;
if (index < _candidateButtons.Count && !string.IsNullOrEmpty(_candidateButtons[index].Text))
{
InputSelectedWord(_candidateButtons[index].Text);
e.Handled = true;
}
}
// 处理ESC键,清空输入并隐藏候选词窗口
else if (e.KeyCode == Keys.Escape)
{
_currentInput = "";
_candidateForm.Visible = false;
e.Handled = true;
}
}
/// <summary>
/// 更新候选词窗口的内容
/// </summary>
private void UpdateCandidateForm()
{
if (string.IsNullOrEmpty(_currentInput))
{
_candidateForm.Visible = false;
return;
}
// 查询词库获取候选词
List<string> candidates = null;
if (_wordDict.TryGetValue(_currentInput, out candidates))
{
// 更新候选词按钮文本
for (int i = 0; i < _candidateButtons.Count; i++)
{
if (i < candidates.Count)
{
_candidateButtons[i].Text = candidates[i];
}
else
{
_candidateButtons[i].Text = "";
}
}
// 设置候选词窗口位置,跟随当前焦点控件
Control focusedControl = GetFocusedControl();
if (focusedControl != null)
{
Point controlPos = focusedControl.PointToScreen(new Point(0, focusedControl.Height));
_candidateForm.Location = controlPos;
}
_candidateForm.Visible = true;
}
else
{
// 没有对应候选词,隐藏窗口
_candidateForm.Visible = false;
}
}
/// <summary>
/// 获取当前获得焦点的控件
/// </summary>
private Control GetFocusedControl()
{
IntPtr hWnd = GetFocus();
if (hWnd != IntPtr.Zero)
{
return Control.FromHandle(hWnd);
}
return null;
}
/// <summary>
/// 将选中的词输入到当前焦点控件
/// </summary>
private void InputSelectedWord(string word)
{
Control focusedControl = GetFocusedControl();
if (focusedControl is TextBox textBox)
{
int selectionStart = textBox.SelectionStart;
textBox.Text = textBox.Text.Insert(selectionStart, word);
textBox.SelectionStart = selectionStart + word.Length;
}
// 清空当前输入,隐藏候选词窗口
_currentInput = "";
_candidateForm.Visible = false;
}
}
}代码说明
上面的代码实现了一个最基础的拼音输入法Demo,启动后可以在输入框中输入wo、ai等拼音,按空格会弹出候选词窗口,再按数字键1-4就能将对应的汉字上屏到输入框中。如果需要扩展为全局输入法,还需要使用全局键盘钩子来监听所有应用的键盘输入,同时处理不同应用的文本上屏逻辑,这里只是提供了核心的实现思路。
实际开发中你可以替换词库为更完整的拼音词库,还可以加入输入编码联想、候选词翻页、中英文切换等功能,逐步完善输入法的使用体验。