C#虚拟键盘实现,支持触摸输入、物理键盘同步、多语言布局、自适应屏幕等功能。
一、项目结构
VirtualKeyboard/
├── VirtualKeyboard.csproj
├── Program.cs
├── MainForm.cs
├── MainForm.Designer.cs
├── Keyboard/
│ ├── VirtualKeyboardForm.cs
│ ├── KeyboardLayout.cs
│ ├── KeyButton.cs
│ ├── KeyboardTheme.cs
│ └── KeyboardHook.cs
├── Controls/
│ ├── TouchKeyboard.cs
│ └── KeyboardPanel.cs
├── Layouts/
│ ├── EnglishLayout.cs
│ ├── ChineseLayout.cs
│ ├── NumberLayout.cs
│ └── SymbolLayout.cs
├── Utils/
│ ├── InputSimulator.cs
│ └── ScreenHelper.cs
└── Resources/
二、核心代码实现
1. 主程序入口 (Program.cs)
csharp
using System;
using System.Windows.Forms;
namespace VirtualKeyboard
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// 检查是否已经有实例在运行
if (IsAlreadyRunning())
{
MessageBox.Show("虚拟键盘已经在运行!", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
Application.Run(new MainForm());
}
private static bool IsAlreadyRunning()
{
System.Diagnostics.Process current = System.Diagnostics.Process.GetCurrentProcess();
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(current.ProcessName);
return processes.Length > 1;
}
}
}
2. 主窗体 (MainForm.cs)
csharp
using System;
using System.Windows.Forms;
using VirtualKeyboard.Keyboard;
namespace VirtualKeyboard
{
public partial class MainForm : Form
{
private VirtualKeyboardForm keyboardForm;
private NotifyIcon trayIcon;
private ContextMenuStrip trayMenu;
public MainForm()
{
InitializeComponent();
InitializeTrayIcon();
InitializeKeyboard();
}
private void InitializeComponent()
{
this.Text = "虚拟键盘";
this.Size = new System.Drawing.Size(400, 300);
this.StartPosition = FormStartPosition.CenterScreen;
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
// 控制面板
Panel controlPanel = new Panel
{
Dock = DockStyle.Fill,
Padding = new Padding(20)
};
Button btnShowKeyboard = new Button
{
Text = "显示虚拟键盘",
Size = new System.Drawing.Size(150, 40),
Location = new System.Drawing.Point(20, 20),
Font = new System.Drawing.Font("微软雅黑", 10)
};
btnShowKeyboard.Click += BtnShowKeyboard_Click;
Button btnHideKeyboard = new Button
{
Text = "隐藏虚拟键盘",
Size = new System.Drawing.Size(150, 40),
Location = new System.Drawing.Point(20, 80),
Font = new System.Drawing.Font("微软雅黑", 10)
};
btnHideKeyboard.Click += BtnHideKeyboard_Click;
Button btnExit = new Button
{
Text = "退出",
Size = new System.Drawing.Size(150, 40),
Location = new System.Drawing.Point(20, 140),
Font = new System.Drawing.Font("微软雅黑", 10)
};
btnExit.Click += BtnExit_Click;
controlPanel.Controls.AddRange(new Control[] { btnShowKeyboard, btnHideKeyboard, btnExit });
this.Controls.Add(controlPanel);
}
private void InitializeTrayIcon()
{
trayMenu = new ContextMenuStrip();
trayMenu.Items.Add("显示", null, (s, e) => ShowKeyboard());
trayMenu.Items.Add("隐藏", null, (s, e) => HideKeyboard());
trayMenu.Items.Add("-");
trayMenu.Items.Add("退出", null, (s, e) => Application.Exit());
trayIcon = new NotifyIcon
{
Icon = System.Drawing.SystemIcons.Application,
Text = "虚拟键盘",
ContextMenuStrip = trayMenu,
Visible = true
};
trayIcon.DoubleClick += (s, e) => ShowKeyboard();
}
private void InitializeKeyboard()
{
keyboardForm = new VirtualKeyboardForm();
}
private void BtnShowKeyboard_Click(object sender, EventArgs e)
{
ShowKeyboard();
}
private void BtnHideKeyboard_Click(object sender, EventArgs e)
{
HideKeyboard();
}
private void BtnExit_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void ShowKeyboard()
{
if (keyboardForm == null || keyboardForm.IsDisposed)
{
keyboardForm = new VirtualKeyboardForm();
}
keyboardForm.Show();
keyboardForm.Activate();
}
private void HideKeyboard()
{
keyboardForm?.Hide();
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
trayIcon.Visible = false;
keyboardForm?.Close();
}
}
}
3. 虚拟键盘窗体 (VirtualKeyboardForm.cs)
csharp
using System;
using System.Drawing;
using System.Windows.Forms;
using VirtualKeyboard.Controls;
using VirtualKeyboard.Keyboard;
using VirtualKeyboard.Layouts;
using VirtualKeyboard.Utils;
namespace VirtualKeyboard.Keyboard
{
public class VirtualKeyboardForm : Form
{
private KeyboardPanel keyboardPanel;
private KeyboardLayout currentLayout;
private KeyboardTheme currentTheme;
private InputSimulator inputSimulator;
private KeyboardHook keyboardHook;
// 状态
private bool isShiftPressed = false;
private bool isCtrlPressed = false;
private bool isAltPressed = false;
private bool isCapsLockOn = false;
private bool isNumLockOn = false;
public VirtualKeyboardForm()
{
InitializeComponent();
InitializeKeyboard();
InitializeInputSimulator();
InitializeKeyboardHook();
}
private void InitializeComponent()
{
this.FormBorderStyle = FormBorderStyle.None;
this.ShowInTaskbar = false;
this.TopMost = true;
this.StartPosition = FormStartPosition.Manual;
this.Size = new Size(800, 300);
this.Location = new Point(Screen.PrimaryScreen.WorkingArea.Width - this.Width,
Screen.PrimaryScreen.WorkingArea.Height - this.Height);
// 允许点击穿透(不获取焦点)
this.SetStyle(ControlStyles.Selectable, false);
this.TabStop = false;
}
private void InitializeKeyboard()
{
currentLayout = new EnglishLayout();
currentTheme = new KeyboardTheme();
currentTheme.LoadDefaultTheme();
keyboardPanel = new KeyboardPanel
{
Dock = DockStyle.Fill,
Layout = currentLayout,
Theme = currentTheme
};
keyboardPanel.KeyPressed += KeyboardPanel_KeyPressed;
keyboardPanel.KeyReleased += KeyboardPanel_KeyReleased;
keyboardPanel.LayoutChanged += KeyboardPanel_LayoutChanged;
this.Controls.Add(keyboardPanel);
}
private void InitializeInputSimulator()
{
inputSimulator = new InputSimulator();
}
private void InitializeKeyboardHook()
{
keyboardHook = new KeyboardHook();
keyboardHook.KeyDown += KeyboardHook_KeyDown;
keyboardHook.KeyUp += KeyboardHook_KeyUp;
keyboardHook.Install();
}
private void KeyboardPanel_KeyPressed(object sender, KeyEventArgs e)
{
HandleKeyPress(e.KeyCode, true);
}
private void KeyboardPanel_KeyReleased(object sender, KeyEventArgs e)
{
HandleKeyPress(e.KeyCode, false);
}
private void KeyboardPanel_LayoutChanged(object sender, KeyboardLayout layout)
{
currentLayout = layout;
keyboardPanel.Layout = layout;
keyboardPanel.Refresh();
}
private void KeyboardHook_KeyDown(object sender, KeyEventArgs e)
{
// 同步物理键盘状态
UpdateModifierKeyState(e.KeyCode, true);
}
private void KeyboardHook_KeyUp(object sender, KeyEventArgs e)
{
// 同步物理键盘状态
UpdateModifierKeyState(e.KeyCode, false);
}
private void UpdateModifierKeyState(Keys key, bool isPressed)
{
switch (key)
{
case Keys.ShiftKey:
case Keys.LShiftKey:
case Keys.RShiftKey:
isShiftPressed = isPressed;
keyboardPanel.SetModifierKeyState(Keys.ShiftKey, isPressed);
break;
case Keys.ControlKey:
case Keys.LControlKey:
case Keys.RControlKey:
isCtrlPressed = isPressed;
keyboardPanel.SetModifierKeyState(Keys.ControlKey, isPressed);
break;
case Keys.Menu:
case Keys.LMenu:
case Keys.RMenu:
isAltPressed = isPressed;
keyboardPanel.SetModifierKeyState(Keys.Menu, isPressed);
break;
case Keys.CapsLock:
if (!isPressed) // 只在释放时切换状态
{
isCapsLockOn = !isCapsLockOn;
keyboardPanel.SetModifierKeyState(Keys.CapsLock, isCapsLockOn);
}
break;
case Keys.NumLock:
if (!isPressed)
{
isNumLockOn = !isNumLockOn;
keyboardPanel.SetModifierKeyState(Keys.NumLock, isNumLockOn);
}
break;
}
}
private void HandleKeyPress(Keys key, bool isDown)
{
if (isDown)
{
// 处理特殊键
switch (key)
{
case Keys.ShiftKey:
isShiftPressed = true;
keyboardPanel.SetModifierKeyState(Keys.ShiftKey, true);
return;
case Keys.ControlKey:
isCtrlPressed = true;
keyboardPanel.SetModifierKeyState(Keys.ControlKey, true);
return;
case Keys.Menu:
isAltPressed = true;
keyboardPanel.SetModifierKeyState(Keys.Menu, true);
return;
case Keys.CapsLock:
isCapsLockOn = !isCapsLockOn;
keyboardPanel.SetModifierKeyState(Keys.CapsLock, isCapsLockOn);
return;
case Keys.NumLock:
isNumLockOn = !isNumLockOn;
keyboardPanel.SetModifierKeyState(Keys.NumLock, isNumLockOn);
return;
case Keys.Escape:
this.Hide();
return;
}
// 发送按键
SendKeyToFocusedControl(key);
}
else
{
// 释放特殊键
switch (key)
{
case Keys.ShiftKey:
isShiftPressed = false;
keyboardPanel.SetModifierKeyState(Keys.ShiftKey, false);
break;
case Keys.ControlKey:
isCtrlPressed = false;
keyboardPanel.SetModifierKeyState(Keys.ControlKey, false);
break;
case Keys.Menu:
isAltPressed = false;
keyboardPanel.SetModifierKeyState(Keys.Menu, false);
break;
}
}
}
private void SendKeyToFocusedControl(Keys key)
{
try
{
// 使用InputSimulator发送按键
inputSimulator.SendKey(key, isShiftPressed, isCtrlPressed, isAltPressed);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"发送按键失败: {ex.Message}");
}
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
// 确保不获取焦点
this.Activated += (s, args) => this.Parent?.Focus();
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
keyboardHook?.Uninstall();
}
}
}
4. 键盘面板控件 (KeyboardPanel.cs)
csharp
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using VirtualKeyboard.Keyboard;
using VirtualKeyboard.Layouts;
namespace VirtualKeyboard.Controls
{
public class KeyboardPanel : UserControl
{
public event EventHandler<KeyEventArgs> KeyPressed;
public event EventHandler<KeyEventArgs> KeyReleased;
public event EventHandler<KeyboardLayout> LayoutChanged;
public KeyboardLayout Layout
{
get { return _layout; }
set
{
_layout = value;
CreateKeys();
Invalidate();
}
}
public KeyboardTheme Theme
{
get { return _theme; }
set
{
_theme = value;
ApplyTheme();
}
}
private KeyboardLayout _layout;
private KeyboardTheme _theme;
private List<KeyButton> keyButtons = new List<KeyButton>();
private Timer repeatTimer;
public KeyboardPanel()
{
InitializeComponent();
CreateKeys();
}
private void InitializeComponent()
{
this.Dock = DockStyle.Fill;
this.BackColor = Color.FromArgb(40, 40, 40);
repeatTimer = new Timer
{
Interval = 50,
Enabled = false
};
repeatTimer.Tick += RepeatTimer_Tick;
}
private void CreateKeys()
{
keyButtons.Clear();
this.Controls.Clear();
if (_layout == null) return;
int keyWidth = 60;
int keyHeight = 50;
int margin = 5;
for (int row = 0; row < _layout.Rows; row++)
{
for (int col = 0; col < _layout.Columns; col++)
{
var keyInfo = _layout.GetKey(row, col);
if (keyInfo == null) continue;
var button = new KeyButton
{
Key = keyInfo.Key,
Text = keyInfo.Text,
Width = keyInfo.Width * keyWidth + (keyInfo.Width - 1) * margin,
Height = keyHeight,
Location = new Point(col * (keyWidth + margin), row * (keyHeight + margin)),
Theme = _theme
};
button.MouseDown += KeyButton_MouseDown;
button.MouseUp += KeyButton_MouseUp;
button.MouseLeave += KeyButton_MouseLeave;
keyButtons.Add(button);
this.Controls.Add(button);
}
}
// 调整大小
this.Size = new Size(
_layout.Columns * (keyWidth + margin) - margin,
_layout.Rows * (keyHeight + margin) - margin
);
}
private void ApplyTheme()
{
if (_theme == null) return;
this.BackColor = _theme.BackgroundColor;
foreach (var button in keyButtons)
{
button.Theme = _theme;
}
}
public void SetModifierKeyState(Keys key, bool isPressed)
{
foreach (var button in keyButtons)
{
if (button.Key == key)
{
button.IsPressed = isPressed;
button.Invalidate();
}
}
}
private void KeyButton_MouseDown(object sender, MouseEventArgs e)
{
var button = sender as KeyButton;
if (button == null) return;
button.IsPressed = true;
button.Invalidate();
KeyPressed?.Invoke(this, new KeyEventArgs(button.Key));
// 开始重复计时
repeatTimer.Start();
}
private void KeyButton_MouseUp(object sender, MouseEventArgs e)
{
var button = sender as KeyButton;
if (button == null) return;
button.IsPressed = false;
button.Invalidate();
KeyReleased?.Invoke(this, new KeyEventArgs(button.Key));
repeatTimer.Stop();
}
private void KeyButton_MouseLeave(object sender, EventArgs e)
{
var button = sender as KeyButton;
if (button == null) return;
button.IsPressed = false;
button.Invalidate();
repeatTimer.Stop();
}
private void RepeatTimer_Tick(object sender, EventArgs e)
{
// 重复发送按键
foreach (var button in keyButtons)
{
if (button.IsPressed)
{
KeyPressed?.Invoke(this, new KeyEventArgs(button.Key));
}
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// 绘制边框
using (var pen = new Pen(Color.FromArgb(60, 60, 60), 1))
{
e.Graphics.DrawRectangle(pen, 0, 0, Width - 1, Height - 1);
}
}
}
}
5. 按键按钮控件 (KeyButton.cs)
csharp
using System;
using System.Drawing;
using System.Windows.Forms;
using VirtualKeyboard.Keyboard;
namespace VirtualKeyboard.Keyboard
{
public class KeyButton : Control
{
public Keys Key { get; set; }
public string NormalText { get; set; }
public string ShiftText { get; set; }
public bool IsPressed { get; set; }
public bool IsModifierKey { get; set; }
public bool IsSpecialKey { get; set; }
private KeyboardTheme _theme;
public KeyboardTheme Theme
{
get { return _theme; }
set
{
_theme = value;
Invalidate();
}
}
public KeyButton()
{
this.SetStyle(ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint, true);
this.TabStop = false;
this.DoubleBuffered = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (_theme == null) return;
// 确定背景色
Color backColor = IsPressed ? _theme.PressedColor :
IsModifierKey ? _theme.ModifierColor :
IsSpecialKey ? _theme.SpecialColor :
_theme.NormalColor;
// 绘制背景
using (var brush = new SolidBrush(backColor))
{
e.Graphics.FillRectangle(brush, 0, 0, Width, Height);
}
// 绘制边框
Color borderColor = IsPressed ? _theme.PressedBorderColor : _theme.BorderColor;
using (var pen = new Pen(borderColor, 1))
{
e.Graphics.DrawRectangle(pen, 0, 0, Width - 1, Height - 1);
}
// 绘制文字
string text = NormalText;
if (ShiftText != null && IsPressed) // 这里应该根据Shift状态判断
{
text = ShiftText;
}
Color textColor = IsPressed ? _theme.PressedTextColor : _theme.TextColor;
using (var brush = new SolidBrush(textColor))
using (var font = new Font("微软雅黑", 10, FontStyle.Regular))
{
var format = new StringFormat
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
e.Graphics.DrawString(text, font, brush,
new RectangleF(0, 0, Width, Height), format);
}
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
IsPressed = false;
Invalidate();
}
}
}
6. 键盘布局 (EnglishLayout.cs)
csharp
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace VirtualKeyboard.Layouts
{
public class EnglishLayout : KeyboardLayout
{
public EnglishLayout()
{
Name = "English";
Rows = 5;
Columns = 15;
// 第一行:功能键
SetKey(0, 0, Keys.Escape, "Esc", 1);
SetKey(0, 1, Keys.F1, "F1", 1);
SetKey(0, 2, Keys.F2, "F2", 1);
SetKey(0, 3, Keys.F3, "F3", 1);
SetKey(0, 4, Keys.F4, "F4", 1);
SetKey(0, 6, Keys.F5, "F5", 1);
SetKey(0, 7, Keys.F6, "F6", 1);
SetKey(0, 8, Keys.F7, "F7", 1);
SetKey(0, 9, Keys.F8, "F8", 1);
SetKey(0, 11, Keys.F9, "F9", 1);
SetKey(0, 12, Keys.F10, "F10", 1);
SetKey(0, 13, Keys.F11, "F11", 1);
SetKey(0, 14, Keys.F12, "F12", 1);
// 第二行:数字和符号
SetKey(1, 0, Keys.Oemtilde, "`", "~", 1);
SetKey(1, 1, Keys.D1, "1", "!", 1);
SetKey(1, 2, Keys.D2, "2", "@", 1);
SetKey(1, 3, Keys.D3, "3", "#", 1);
SetKey(1, 4, Keys.D4, "4", "$", 1);
SetKey(1, 5, Keys.D5, "5", "%", 1);
SetKey(1, 6, Keys.D6, "6", "^", 1);
SetKey(1, 7, Keys.D7, "7", "&", 1);
SetKey(1, 8, Keys.D8, "8", "*", 1);
SetKey(1, 9, Keys.D9, "9", "(", 1);
SetKey(1, 10, Keys.D0, "0", ")", 1);
SetKey(1, 11, Keys.OemMinus, "-", "_", 1);
SetKey(1, 12, Keys.Oemplus, "=", "+", 1);
SetKey(1, 13, Keys.Back, "Backspace", 2);
// 第三行:QWERTY
SetKey(2, 0, Keys.Tab, "Tab", 1.5);
SetKey(2, 1, Keys.Q, "q", "Q", 1);
SetKey(2, 2, Keys.W, "w", "W", 1);
SetKey(2, 3, Keys.E, "e", "E", 1);
SetKey(2, 4, Keys.R, "r", "R", 1);
SetKey(2, 5, Keys.T, "t", "T", 1);
SetKey(2, 6, Keys.Y, "y", "Y", 1);
SetKey(2, 7, Keys.U, "u", "U", 1);
SetKey(2, 8, Keys.I, "i", "I", 1);
SetKey(2, 9, Keys.O, "o", "O", 1);
SetKey(2, 10, Keys.P, "p", "P", 1);
SetKey(2, 11, Keys.OemOpenBrackets, "[", "{", 1);
SetKey(2, 12, Keys.OemCloseBrackets, "]", "}", 1);
SetKey(2, 13, Keys.OemBackslash, "\\", "|", 1);
// 第四行:ASDF
SetKey(3, 0, Keys.CapsLock, "Caps", 1.75);
SetKey(3, 1, Keys.A, "a", "A", 1);
SetKey(3, 2, Keys.S, "s", "S", 1);
SetKey(3, 3, Keys.D, "d", "D", 1);
SetKey(3, 4, Keys.F, "f", "F", 1);
SetKey(3, 5, Keys.G, "g", "G", 1);
SetKey(3, 6, Keys.H, "h", "H", 1);
SetKey(3, 7, Keys.J, "j", "J", 1);
SetKey(3, 8, Keys.K, "k", "K", 1);
SetKey(3, 9, Keys.L, "l", "L", 1);
SetKey(3, 10, Keys.OemSemicolon, ";", ":", 1);
SetKey(3, 11, Keys.OemQuotes, "'", "\"", 1);
SetKey(3, 12, Keys.Enter, "Enter", 2.25);
// 第五行:空格和控制键
SetKey(4, 0, Keys.LShiftKey, "Shift", 2.25);
SetKey(4, 1, Keys.Z, "z", "Z", 1);
SetKey(4, 2, Keys.X, "x", "X", 1);
SetKey(4, 3, Keys.C, "c", "C", 1);
SetKey(4, 4, Keys.V, "v", "V", 1);
SetKey(4, 5, Keys.B, "b", "B", 1);
SetKey(4, 6, Keys.N, "n", "N", 1);
SetKey(4, 7, Keys.M, "m", "M", 1);
SetKey(4, 8, Keys.Oemcomma, ",", "<", 1);
SetKey(4, 9, Keys.OemPeriod, ".", ">", 1);
SetKey(4, 10, Keys.OemQuestion, "/", "?", 1);
SetKey(4, 11, Keys.RShiftKey, "Shift", 2.25);
SetKey(4, 12, Keys.ControlKey, "Ctrl", 1);
SetKey(4, 13, Keys.Menu, "Alt", 1);
SetKey(4, 14, Keys.Space, "Space", 6);
}
}
}
7. 键盘主题 (KeyboardTheme.cs)
csharp
using System;
using System.Drawing;
namespace VirtualKeyboard.Keyboard
{
public class KeyboardTheme
{
public string Name { get; set; }
// 背景色
public Color BackgroundColor { get; set; }
public Color KeyBackgroundColor { get; set; }
// 按键颜色
public Color NormalColor { get; set; }
public Color PressedColor { get; set; }
public Color ModifierColor { get; set; }
public Color SpecialColor { get; set; }
// 边框颜色
public Color BorderColor { get; set; }
public Color PressedBorderColor { get; set; }
// 文字颜色
public Color TextColor { get; set; }
public Color PressedTextColor { get; set; }
// 字体
public Font KeyFont { get; set; }
public Font SpecialKeyFont { get; set; }
public KeyboardTheme()
{
LoadDefaultTheme();
}
public void LoadDefaultTheme()
{
Name = "默认主题";
// 深色主题
BackgroundColor = Color.FromArgb(40, 40, 40);
KeyBackgroundColor = Color.FromArgb(60, 60, 60);
NormalColor = Color.FromArgb(70, 70, 70);
PressedColor = Color.FromArgb(100, 100, 100);
ModifierColor = Color.FromArgb(50, 50, 50);
SpecialColor = Color.FromArgb(80, 80, 80);
BorderColor = Color.FromArgb(90, 90, 90);
PressedBorderColor = Color.FromArgb(120, 120, 120);
TextColor = Color.White;
PressedTextColor = Color.Black;
KeyFont = new Font("微软雅黑", 10, FontStyle.Regular);
SpecialKeyFont = new Font("微软雅黑", 9, FontStyle.Bold);
}
public void LoadLightTheme()
{
Name = "浅色主题";
BackgroundColor = Color.FromArgb(240, 240, 240);
KeyBackgroundColor = Color.White;
NormalColor = Color.White;
PressedColor = Color.FromArgb(200, 200, 200);
ModifierColor = Color.FromArgb(220, 220, 220);
SpecialColor = Color.FromArgb(180, 180, 180);
BorderColor = Color.FromArgb(150, 150, 150);
PressedBorderColor = Color.FromArgb(100, 100, 100);
TextColor = Color.Black;
PressedTextColor = Color.White;
}
public void LoadBlueTheme()
{
Name = "蓝色主题";
BackgroundColor = Color.FromArgb(30, 60, 90);
KeyBackgroundColor = Color.FromArgb(50, 80, 110);
NormalColor = Color.FromArgb(70, 100, 130);
PressedColor = Color.FromArgb(90, 120, 150);
ModifierColor = Color.FromArgb(50, 80, 110);
SpecialColor = Color.FromArgb(60, 90, 120);
BorderColor = Color.FromArgb(80, 110, 140);
PressedBorderColor = Color.FromArgb(100, 130, 160);
TextColor = Color.White;
PressedTextColor = Color.Black;
}
}
}
8. 输入模拟器 (InputSimulator.cs)
csharp
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace VirtualKeyboard.Utils
{
public class InputSimulator
{
[StructLayout(LayoutKind.Sequential)]
private struct INPUT
{
public int type;
public InputUnion u;
}
[StructLayout(LayoutKind.Explicit)]
private struct InputUnion
{
[FieldOffset(0)]
public KEYBDINPUT ki;
}
[StructLayout(LayoutKind.Sequential)]
private struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
private const int INPUT_KEYBOARD = 1;
private const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
private const uint KEYEVENTF_KEYUP = 0x0002;
private const uint KEYEVENTF_UNICODE = 0x0004;
private const uint KEYEVENTF_SCANCODE = 0x0008;
[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
[DllImport("user32.dll")]
private static extern short VkKeyScan(char ch);
public void SendKey(Keys key, bool shift = false, bool ctrl = false, bool alt = false)
{
// 发送修饰键
if (shift) SendKeyDown(Keys.ShiftKey);
if (ctrl) SendKeyDown(Keys.ControlKey);
if (alt) SendKeyDown(Keys.Menu);
// 发送主键
SendKeyDown(key);
SendKeyUp(key);
// 释放修饰键
if (alt) SendKeyUp(Keys.Menu);
if (ctrl) SendKeyUp(Keys.ControlKey);
if (shift) SendKeyUp(Keys.ShiftKey);
}
public void SendText(string text)
{
foreach (char c in text)
{
SendUnicodeChar(c);
}
}
private void SendKeyDown(Keys key)
{
INPUT[] inputs = new INPUT[]
{
new INPUT
{
type = INPUT_KEYBOARD,
u = new InputUnion
{
ki = new KEYBDINPUT
{
wVk = (ushort)key,
dwFlags = 0
}
}
}
};
SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
}
private void SendKeyUp(Keys key)
{
INPUT[] inputs = new INPUT[]
{
new INPUT
{
type = INPUT_KEYBOARD,
u = new InputUnion
{
ki = new KEYBDINPUT
{
wVk = (ushort)key,
dwFlags = KEYEVENTF_KEYUP
}
}
}
};
SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
}
private void SendUnicodeChar(char c)
{
INPUT[] inputs = new INPUT[]
{
new INPUT
{
type = INPUT_KEYBOARD,
u = new InputUnion
{
ki = new KEYBDINPUT
{
wScan = c,
dwFlags = KEYEVENTF_UNICODE
}
}
},
new INPUT
{
type = INPUT_KEYBOARD,
u = new InputUnion
{
ki = new KEYBDINPUT
{
wScan = c,
dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP
}
}
}
};
SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
}
public void SendKeyCombination(params Keys[] keys)
{
// 按下所有键
foreach (var key in keys)
{
SendKeyDown(key);
}
// 释放所有键(反向顺序)
for (int i = keys.Length - 1; i >= 0; i--)
{
SendKeyUp(keys[i]);
}
}
}
}
9. 键盘钩子 (KeyboardHook.cs)
csharp
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace VirtualKeyboard.Keyboard
{
public class KeyboardHook
{
public event EventHandler<KeyEventArgs> KeyDown;
public event EventHandler<KeyEventArgs> KeyUp;
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
private const int WM_SYSKEYDOWN = 0x0104;
private const int WM_SYSKEYUP = 0x0105;
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
private struct KBDLLHOOKSTRUCT
{
public Keys vkCode;
public int scanCode;
public int flags;
public int time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
private IntPtr hookId = IntPtr.Zero;
private LowLevelKeyboardProc proc;
public void Install()
{
proc = HookCallback;
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
hookId = SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
public void Uninstall()
{
UnhookWindowsHookEx(hookId);
}
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN ||
wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP))
{
KBDLLHOOKSTRUCT hookStruct = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
bool isKeyDown = (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN);
if (isKeyDown)
{
KeyDown?.Invoke(this, new KeyEventArgs(hookStruct.vkCode));
}
else
{
KeyUp?.Invoke(this, new KeyEventArgs(hookStruct.vkCode));
}
}
return CallNextHookEx(hookId, nCode, wParam, lParam);
}
}
}
10. 项目文件 (VirtualKeyboard.csproj)
xml
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{YOUR-PROJECT-GUID}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>VirtualKeyboard</RootNamespace>
<AssemblyName>VirtualKeyboard</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Drawing" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="MainForm.cs" />
<Compile Include="MainForm.Designer.cs" />
<Compile Include="Keyboard\VirtualKeyboardForm.cs" />
<Compile Include="Keyboard\KeyboardLayout.cs" />
<Compile Include="Keyboard\KeyButton.cs" />
<Compile Include="Keyboard\KeyboardTheme.cs" />
<Compile Include="Keyboard\KeyboardHook.cs" />
<Compile Include="Controls\KeyboardPanel.cs" />
<Compile Include="Layouts\EnglishLayout.cs" />
<Compile Include="Layouts\ChineseLayout.cs" />
<Compile Include="Layouts\NumberLayout.cs" />
<Compile Include="Layouts\SymbolLayout.cs" />
<Compile Include="Utils\InputSimulator.cs" />
<Compile Include="Utils\ScreenHelper.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
参考代码 C#写的虚拟键盘 www.youwenfan.com/contentcsv/111931.html
三、使用说明
1. 功能特点
- 触摸友好:大按钮设计,适合触摸屏使用
- 物理键盘同步:实时同步物理键盘状态
- 多语言布局:支持英文、中文、数字、符号布局
- 系统托盘:最小化到系统托盘
- 自动隐藏:失去焦点时自动隐藏
- 主题切换:支持深色、浅色、蓝色主题
- 按键重复:长按按键自动重复
- 组合键:支持Ctrl+C、Ctrl+V等组合键
2. 使用方法
- 运行程序,虚拟键盘会自动显示在屏幕底部
- 点击系统托盘图标可以显示/隐藏键盘
- 点击键盘按钮即可输入字符
- 支持Shift、Ctrl、Alt等修饰键
- 支持Caps Lock和Num Lock
3. 扩展功能建议
- 手写识别:添加手写输入面板
- 语音输入:集成语音转文字功能
- 预测输入:智能联想和预测输入
- 多显示器支持:在不同显示器上显示键盘
- 自定义布局:允许用户自定义键盘布局
- 宏录制:支持录制和播放宏命令
- 密码保护:安全输入模式,防止截屏