using System.Drawing; using System.Runtime.InteropServices; using System.Text; namespace XFEExtension.NetCore.InputSimulator; /// /// 模拟用户输入 /// public static partial class InputSimulator { #region DLL引用 [LibraryImport("user32.dll", SetLastError = true)] private static partial void keybd_event(byte bVk, byte bScan, uint dwFlags, IntPtr dwExtraInfo); [LibraryImport("user32.dll")] private static partial void mouse_event(uint dwFlags, int dx, int dy, int dwData, IntPtr dwExtraInfo); [LibraryImport("user32.dll")] private static partial int GetSystemMetrics(int nIndex); [LibraryImport("user32.dll")] private static partial void SetCursorPos(int x, int y); [LibraryImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static partial bool GetCursorPos(out Point lpPoint); [LibraryImport("user32.dll")] private static partial IntPtr GetDC(IntPtr hWnd); [LibraryImport("user32.dll")] private static partial int ReleaseDC(IntPtr hWnd, IntPtr hDC); [LibraryImport("user32.dll")] private static partial int GetDpiForWindow(IntPtr hWnd); [LibraryImport("user32.dll")] private static partial short GetAsyncKeyState(int vKey); [LibraryImport("user32.dll")] private static partial IntPtr GetDesktopWindow(); [LibraryImport("gdi32.dll")] private static partial int GetDeviceCaps(IntPtr hdc, int nIndex); #endregion #region 常量 private const int KEYEVENTF_KEYDOWN = 0x0000; // 按键按下 private const int KEYEVENTF_KEYUP = 0x0002; // 按键松开 private const uint MOUSEEVENTF_MOVE = 0x0001; // 鼠标移动 private const uint MOUSEEVENTF_LEFTDOWN = 0x0002; // 鼠标左键按下 private const uint MOUSEEVENTF_LEFTUP = 0x0004; // 鼠标左键松开 private const uint MOUSEEVENTF_RIGHTDOWN = 0x0008; // 鼠标右键按下 private const uint MOUSEEVENTF_RIGHTUP = 0x0010; // 鼠标右键松开 private const uint MOUSEEVENTF_MIDDOWN = 0x0020; // 鼠标中键按下 private const uint MOUSEEVENTF_MIDUP = 0x0040; // 鼠标中键松开 private const uint MOUSEEVENTF_WHEEL = 0x0800; // 鼠标滚轮 private const int VK_LBUTTON = 0x01; // 检测鼠标左键 private const int VK_RBUTTON = 0x02; // 检测鼠标右键 private const int VK_MBUTTON = 0x04; // 检测鼠标中键 private const int SM_CXSCREEN = 0; // 屏幕宽度 private const int SM_CYSCREEN = 1; // 屏幕高度 private const int HORZRES = 8; private const int VERTRES = 10; private const int LOGPIXELSX = 88; private const int LOGPIXELSY = 90; private const int DESKTOPVERTRES = 117; private const int DESKTOPHORZRES = 118; #endregion #region 键盘方法 /// /// 按住某个按键 /// /// 按键 public static void KeyDown(char key) { byte keyCode = (byte)key; keybd_event(keyCode, 0, KEYEVENTF_KEYDOWN, IntPtr.Zero); } /// /// 松开某个按键 /// /// 按键 public static void KeyUp(char key) { byte keyCode = (byte)key; keybd_event(keyCode, 0, KEYEVENTF_KEYUP, IntPtr.Zero); } /// /// 按下某个按键 /// /// /// 如果需要输入一组按键,请使用 /// /// 按键 public static void PressKey(char key) { byte keyCode = (byte)key; keybd_event(keyCode, 0, KEYEVENTF_KEYDOWN, IntPtr.Zero); keybd_event(keyCode, 0, KEYEVENTF_KEYUP, IntPtr.Zero); } /// /// 按下某个按键 /// /// /// 如果需要输入一组按键,请使用 /// /// 按键 /// 按下时间 public static async Task PressKeyAsync(char key, int holdTime) { byte keyCode = (byte)key; keybd_event(keyCode, 0, KEYEVENTF_KEYDOWN, IntPtr.Zero); await Task.Delay(holdTime); keybd_event(keyCode, 0, KEYEVENTF_KEYUP, IntPtr.Zero); } /// /// 输入一组按键 /// /// /// 如果需要输入延迟,请使用 /// /// 待输入按键 public static void InputKeys(string keys) { foreach (var key in keys.Select(key => key.ToString())) { if (key.Equals(key, StringComparison.CurrentCultureIgnoreCase)) { keybd_event(0x10, 0, KEYEVENTF_KEYDOWN, IntPtr.Zero); keybd_event(Encoding.ASCII.GetBytes(key).FirstOrDefault(), 0, KEYEVENTF_KEYDOWN, IntPtr.Zero); keybd_event(Encoding.ASCII.GetBytes(key).FirstOrDefault(), 0, KEYEVENTF_KEYUP, IntPtr.Zero); keybd_event(0x10, 0, KEYEVENTF_KEYUP, IntPtr.Zero); } else { keybd_event(Encoding.ASCII.GetBytes(key.ToUpper()).FirstOrDefault(), 0, KEYEVENTF_KEYDOWN, IntPtr.Zero); keybd_event(Encoding.ASCII.GetBytes(key.ToUpper()).FirstOrDefault(), 0, KEYEVENTF_KEYUP, IntPtr.Zero); } } } /// /// 输入一组按键 /// /// 待输入按键 /// 每个按键按住的时间 /// 按键间延迟 /// public static async Task InputKeysAsync(string keys, int holdTime = 0, int delay = 0) { foreach (var key in keys.Select(key => key.ToString())) { if (key.Equals(key, StringComparison.CurrentCultureIgnoreCase)) { keybd_event(0x10, 0, KEYEVENTF_KEYDOWN, IntPtr.Zero); keybd_event(Encoding.ASCII.GetBytes(key).FirstOrDefault(), 0, KEYEVENTF_KEYDOWN, IntPtr.Zero); await Task.Delay(holdTime); keybd_event(Encoding.ASCII.GetBytes(key).FirstOrDefault(), 0, KEYEVENTF_KEYUP, IntPtr.Zero); keybd_event(0x10, 0, KEYEVENTF_KEYUP, IntPtr.Zero); } else { keybd_event(Encoding.ASCII.GetBytes(key.ToUpper()).FirstOrDefault(), 0, KEYEVENTF_KEYDOWN, IntPtr.Zero); await Task.Delay(holdTime); keybd_event(Encoding.ASCII.GetBytes(key.ToUpper()).FirstOrDefault(), 0, KEYEVENTF_KEYUP, IntPtr.Zero); } await Task.Delay(delay); } } #endregion #region 鼠标方法 /// /// 相对移动 /// /// /// 如果需要绝对移动请使用方法 /// /// X偏移 /// Y偏移 public static void MouseMove(int x, int y) { mouse_event(MOUSEEVENTF_MOVE, x, y, 0, IntPtr.Zero); } /// /// 将鼠标定位至 /// /// /// 如果需要相对移动请使用方法 /// /// X坐标 /// Y坐标 public static void LocateTo(int x, int y) { SetCursorPos(x, y); } /// /// 将鼠标定位至 /// /// /// 如果需要相对移动请使用方法 /// /// 定位到的位置 public static void LocateTo(Point point) { LocateTo(point.X, point.Y); } /// /// 将鼠标定位至 /// /// /// 如果需要相对移动请使用方法 /// /// 屏幕空间位置 public static void LocateTo(ScreenPosition screenPosition) { switch (screenPosition) { case ScreenPosition.TopLeft: LocateTo(0, 0); break; case ScreenPosition.TopRight: LocateTo(GetScreenSize().Width - 1, 0); break; case ScreenPosition.Top: LocateTo(GetScreenSize().Width / 2, 0); break; case ScreenPosition.Left: LocateTo(0, GetScreenSize().Height / 2); break; case ScreenPosition.Right: LocateTo(GetScreenSize().Width - 1, GetScreenSize().Height / 2); break; case ScreenPosition.Center: LocateTo(GetScreenSize().Width / 2, GetScreenSize().Height / 2); break; case ScreenPosition.BottomLeft: LocateTo(0, GetScreenSize().Height - 1); break; case ScreenPosition.Bottom: LocateTo(GetScreenSize().Width / 2, GetScreenSize().Height - 1); break; case ScreenPosition.BottomRight: LocateTo(GetScreenSize().Width - 1, GetScreenSize().Height - 1); break; default: break; } } /// /// 模拟鼠标点击 /// /// 鼠标按键 public static void MouseClick(MouseButton mouseButton) { switch (mouseButton) { case MouseButton.Left: mouse_event(MOUSEEVENTF_LEFTDOWN, GetMousePosition().X, GetMousePosition().Y, 0, IntPtr.Zero); mouse_event(MOUSEEVENTF_LEFTUP, GetMousePosition().X, GetMousePosition().Y, 0, IntPtr.Zero); break; case MouseButton.Right: mouse_event(MOUSEEVENTF_RIGHTDOWN, GetMousePosition().X, GetMousePosition().Y, 0, IntPtr.Zero); mouse_event(MOUSEEVENTF_RIGHTUP, GetMousePosition().X, GetMousePosition().Y, 0, IntPtr.Zero); break; case MouseButton.Middle: mouse_event(MOUSEEVENTF_MIDDOWN, GetMousePosition().X, GetMousePosition().Y, 0, IntPtr.Zero); mouse_event(MOUSEEVENTF_MIDUP, GetMousePosition().X, GetMousePosition().Y, 0, IntPtr.Zero); break; default: break; } } /// /// 模拟鼠标点击 /// /// 鼠标按键 /// 鼠标按键按住时间 public static async Task MouseClickAsync(MouseButton mouseButton, int holdTime) { switch (mouseButton) { case MouseButton.Left: mouse_event(MOUSEEVENTF_LEFTDOWN, GetMousePosition().X, GetMousePosition().Y, 0, IntPtr.Zero); await Task.Delay(holdTime); mouse_event(MOUSEEVENTF_LEFTUP, GetMousePosition().X, GetMousePosition().Y, 0, IntPtr.Zero); break; case MouseButton.Right: mouse_event(MOUSEEVENTF_RIGHTDOWN, GetMousePosition().X, GetMousePosition().Y, 0, IntPtr.Zero); await Task.Delay(holdTime); mouse_event(MOUSEEVENTF_RIGHTUP, GetMousePosition().X, GetMousePosition().Y, 0, IntPtr.Zero); break; case MouseButton.Middle: mouse_event(MOUSEEVENTF_MIDDOWN, GetMousePosition().X, GetMousePosition().Y, 0, IntPtr.Zero); await Task.Delay(holdTime); mouse_event(MOUSEEVENTF_MIDUP, GetMousePosition().X, GetMousePosition().Y, 0, IntPtr.Zero); break; default: break; } } /// /// 鼠标滚轮滚动 /// /// 滚动长度,负为向下滚动 public static void MouseWhellRoll(int length) { mouse_event(MOUSEEVENTF_WHEEL, GetMousePosition().X, GetMousePosition().Y, length, IntPtr.Zero); } /// /// 检查鼠标是否按下 /// /// 鼠标按键 /// 是否被按下 public static bool GetMouseDown(MouseButton button) => button switch { MouseButton.Left => (GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0, MouseButton.Right => (GetAsyncKeyState(VK_RBUTTON) & 0x8000) != 0, MouseButton.Middle => (GetAsyncKeyState(VK_MBUTTON) & 0x8000) != 0, _ => false }; #endregion #region 系统信息获取方法 /// /// 获取屏幕的宽高 /// /// 屏幕宽高 public static Size GetScreenSize() { return new Size(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); } /// /// 获取屏幕的绝对宽高 /// /// public static Size GetAbsoluteScreenSize() { var hdc = GetDC(GetDesktopWindow()); int nWidth = GetDeviceCaps(hdc, DESKTOPHORZRES); int nHeight = GetDeviceCaps(hdc, DESKTOPVERTRES); _ = ReleaseDC(IntPtr.Zero, hdc); return new Size(nWidth, nHeight); } /// /// 获取鼠标的当前位置 /// /// 鼠标位置 public static Point GetMousePosition() { GetCursorPos(out Point point); return point; } /// /// 获取鼠标位置相对于屏幕大小的百分比 /// /// 百分比,0-1之间(X, Y) public static (double X, double Y) GetMousePointRelatively() { GetCursorPos(out Point point); return ((double)point.X / (GetSystemMetrics(SM_CXSCREEN) - 1), (double)point.Y / (GetSystemMetrics(SM_CYSCREEN) - 1)); } /// /// 获取当前缩放倍率 /// /// public static double GetScalingFactorForWindow() { return GetAbsoluteScreenSize().Width / GetScreenSize().Width; } /// /// 获取当前窗口的缩放倍率 /// /// 窗口句柄 /// public static double GetScalingFactorForWindow(nint hWnd) { var hDC = GetDC(hWnd); var dpi = GetDpiForWindow(hWnd); _ = ReleaseDC(hWnd, hDC); return dpi / 96.0f; } #endregion }