89 lines
3.3 KiB
C#
89 lines
3.3 KiB
C#
using anjianjingling.Common;
|
|
using anjianjingling.Native;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace anjianjingling.Input
|
|
{
|
|
/// <summary>
|
|
/// 系统级键盘模拟(SendInput):单键、组合键、Unicode 文本。
|
|
/// </summary>
|
|
public sealed class KeyboardInput
|
|
{
|
|
private static void SendKey(Win32.KEYBDINPUT ki)
|
|
{
|
|
var input = new Win32.INPUT
|
|
{
|
|
type = Win32.INPUT_KEYBOARD,
|
|
u = new Win32.INPUTUNION { ki = ki }
|
|
};
|
|
Win32.SendInput(1, new[] { input }, Marshal.SizeOf<Win32.INPUT>());
|
|
}
|
|
|
|
/// <summary>发送一次按键(按下并弹起)。</summary>
|
|
public void KeyPress(string keyName)
|
|
{
|
|
ushort vk = ResolveOrThrow(keyName);
|
|
KeyDownVk(vk);
|
|
Thread.Sleep(30);
|
|
KeyUpVk(vk);
|
|
}
|
|
|
|
public void KeyDown(string keyName) => KeyDownVk(ResolveOrThrow(keyName));
|
|
|
|
public void KeyUp(string keyName) => KeyUpVk(ResolveOrThrow(keyName));
|
|
|
|
private static void KeyDownVk(ushort vk)
|
|
{
|
|
ushort scan = (ushort)Win32.MapVirtualKey(vk, Win32.MAPVK_VK_TO_VSC);
|
|
uint flags = Win32.KEYEVENTF_SCANCODE;
|
|
if (VirtualKeys.IsExtended(vk)) flags |= Win32.KEYEVENTF_EXTENDEDKEY;
|
|
SendKey(new Win32.KEYBDINPUT { wVk = vk, wScan = scan, dwFlags = flags });
|
|
}
|
|
|
|
private static void KeyUpVk(ushort vk)
|
|
{
|
|
ushort scan = (ushort)Win32.MapVirtualKey(vk, Win32.MAPVK_VK_TO_VSC);
|
|
uint flags = Win32.KEYEVENTF_SCANCODE | Win32.KEYEVENTF_KEYUP;
|
|
if (VirtualKeys.IsExtended(vk)) flags |= Win32.KEYEVENTF_EXTENDEDKEY;
|
|
SendKey(new Win32.KEYBDINPUT { wVk = vk, wScan = scan, dwFlags = flags });
|
|
}
|
|
|
|
/// <summary>
|
|
/// 组合键,如 "Ctrl+A"、"Ctrl+Shift+Esc":修饰键依次按下,主键按下弹起,修饰键逆序弹起。
|
|
/// </summary>
|
|
public void HotKey(string expression)
|
|
{
|
|
var parts = expression.Split('+', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
|
|
if (parts.Length == 0) throw new ArgumentException($"无法解析组合键:{expression}");
|
|
|
|
var vks = parts.Select(ResolveOrThrow).ToArray();
|
|
for (int i = 0; i < vks.Length - 1; i++) KeyDownVk(vks[i]);
|
|
Thread.Sleep(40);
|
|
KeyDownVk(vks[^1]);
|
|
Thread.Sleep(40);
|
|
KeyUpVk(vks[^1]);
|
|
for (int i = vks.Length - 2; i >= 0; i--)
|
|
{
|
|
Thread.Sleep(20);
|
|
KeyUpVk(vks[i]);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 输入整段文本(含中文),使用 KEYEVENTF_UNICODE,不依赖键盘布局。
|
|
/// </summary>
|
|
public void TypeText(string text)
|
|
{
|
|
foreach (char c in text)
|
|
{
|
|
SendKey(new Win32.KEYBDINPUT { wScan = c, dwFlags = Win32.KEYEVENTF_UNICODE });
|
|
SendKey(new Win32.KEYBDINPUT { wScan = c, dwFlags = Win32.KEYEVENTF_UNICODE | Win32.KEYEVENTF_KEYUP });
|
|
}
|
|
}
|
|
|
|
private static ushort ResolveOrThrow(string name)
|
|
=> VirtualKeys.Resolve(name)
|
|
?? throw new ArgumentException($"未知按键名:\"{name}\"(可用如 A、F5、ENTER、SPACE、方向键等)");
|
|
}
|
|
}
|