using AutoAgent.Domain.Exceptions; namespace AutoAgent.Domain { public static class InputHandler { private static Dictionary> _state = new(); private static bool IsKeyPressed(int keyCode) { return (User32Dll.GetKeyState(keyCode) & 0x8000) != 0; } private static ushort GetMouseKeyStates() { ushort keyStates = 0; if (IsKeyPressed(0x01)) keyStates |= 0x0001; // lbutton if (IsKeyPressed(0x02)) keyStates |= 0x0002; // rbutton if (IsKeyPressed(0x04)) keyStates |= 0x0010; // mbutton if (IsKeyPressed(0x05)) keyStates |= 0x0020; // xbutton1 if (IsKeyPressed(0x06)) keyStates |= 0x0040; // xbutton2 if (IsKeyPressed(0x10)) keyStates |= 0x0004; // Shift if (IsKeyPressed(0x11)) keyStates |= 0x0008; // Ctrl return keyStates; } private static IntPtr MakeParam(int low, int high = 0) { return (high << 16) | (low & 0xffff); } private static IntPtr GetCursorPos(IntPtr hwnd) { User32Dll.GetCursorPos(out var pos); if (hwnd != IntPtr.Zero) { User32Dll.ScreenToClient(hwnd, ref pos); } return MakeParam(pos.X, pos.Y); } private static Dictionary GetStateDict(IntPtr hwnd) { Dictionary state; if (_state.TryGetValue(hwnd, out var s)) { state = s; } else { _state.Add(hwnd, state = new()); } return state; } private static bool SendInput(Models.MemoryBuffer buffer, User32Dll.INPUT input) { return User32Dll.SendInput(1, buffer.SetStruct(input), User32Dll.INPUT_SIZE) != 1; } private static bool SendInput(Models.MemoryBuffer buffer, User32Dll.MOUSEINPUT input) { return SendInput(buffer, new User32Dll.INPUT() { type = 0x00, mi = input }); } private static bool SendInput(Models.MemoryBuffer buffer, User32Dll.KEYBDINPUT input) { return SendInput(buffer, new User32Dll.INPUT() { type = 0x01, ki = input }); } private static Task ProcessMouseInput(IntPtr hwnd, Models.Button button, bool press) { return Task.Run(() => { var state = GetStateDict(hwnd); if (state.TryGetValue(button, out var s) && s == press) return; if (hwnd == IntPtr.Zero) { using (var buffer = new Models.MemoryBuffer(User32Dll.INPUT_SIZE)) { var input = new User32Dll.MOUSEINPUT(); if (button.HasFlag(Models.Button.MouseExtraFlag)) { input.dwFlags = (uint)Models.Button.MouseExtraFlag << (press ? 0 : 1); input.mouseData = (int)(button & ~Models.Button.MouseExtraFlag); } else { input.dwFlags = (uint)button << (press ? 0 : 1); } if (!SendInput(buffer, input)) { throw new InputException("SendInput is not successful"); } } } else { int msg = 0; int wFlags = 0; switch (button) { case Models.Button.MouseLeft: msg = press ? 0x0201 : 0x0202; break; case Models.Button.MouseRight: msg = press ? 0x0204 : 0x0205; break; case Models.Button.MouseMiddle: msg = press ? 0x0207 : 0x0208; break; case Models.Button.MouseExtra1: case Models.Button.MouseExtra2: msg = press ? 0x020b : 0x020c; wFlags = (int)button & 0x7f; break; default: throw new UnexpectedInputButton(button); } User32Dll.SendMessage(hwnd, msg, MakeParam(GetMouseKeyStates(), wFlags), GetCursorPos(hwnd)); } state[button] = press; }); } private static Task ProcessKeyboardInput(IntPtr hwnd, Models.Button button, bool press) { return Task.Run(() => { var state = GetStateDict(hwnd); if (state.TryGetValue(button, out var s) && s == press) return; if (hwnd == IntPtr.Zero) { using (var buffer = new Models.MemoryBuffer(User32Dll.INPUT_SIZE)) { var flags = (uint)(press ? 0x00 : 0x02); var input = new User32Dll.KEYBDINPUT(); if (button.HasFlag(Models.Button.ExtendedKeyFlag)) { flags |= 0x01; button &= ~Models.Button.ExtendedKeyFlag; } input.wVk = (ushort)button; input.dwFlags = flags; if (!SendInput(buffer, input)) { throw new InputException("SendInput is not successful"); } } } else { var btn = (int)(button & ~Models.Button.ExtendedKeyFlag); var msg = press ? 0x0100 : 0x0101; if (button == Models.Button.LAlt || button == Models.Button.RAlt) msg += 4; int flags = User32Dll.MapVirtualKey(btn, 0) | (button.HasFlag(Models.Button.ExtendedKeyFlag) ? 0x0100 : 0) | (IsKeyPressed(0x12) ? 0x2000 : 0) | (s ? 0x4000 : 0) | (press ? 0 : 0x8000); User32Dll.SendMessage(hwnd, msg, MakeParam(btn), MakeParam(1, flags)); } state[button] = press; }); } public static async Task KeyUp(IntPtr hwnd, Models.Button button, int delay) { if (button.HasFlag(Models.Button.MouseKeyFlag)) { await ProcessMouseInput(hwnd, button & ~Models.Button.MouseKeyFlag, false); } else { await ProcessKeyboardInput(hwnd, button, false); } await Task.Delay(delay); } public static async Task KeyDown(IntPtr hwnd, Models.Button button, int delay) { if (button.HasFlag(Models.Button.MouseKeyFlag)) { await ProcessMouseInput(hwnd, button & ~Models.Button.MouseKeyFlag, true); } else { await ProcessKeyboardInput(hwnd, button, true); } await Task.Delay(delay); } public static Task MouseScroll(IntPtr hwnd, int offset, int delay) { return Task.Run(async () => { if (hwnd == IntPtr.Zero) { using (var buffer = new Models.MemoryBuffer(User32Dll.INPUT_SIZE)) { if (!SendInput(buffer, new User32Dll.MOUSEINPUT { dwFlags = 0x0800, mouseData = offset } )) { throw new InputException("SendInput is not successful"); } } } else { User32Dll.SendMessage(hwnd, 0x020a, MakeParam(GetMouseKeyStates(), offset), GetCursorPos(IntPtr.Zero)); } await Task.Delay(delay); }); } public static Task MouseMove(IntPtr hwnd, Models.Point pos, int delay) { return Task.Run(async () => { if (hwnd == IntPtr.Zero) { using (var buffer = new Models.MemoryBuffer(User32Dll.INPUT_SIZE)) { if (!SendInput(buffer, new User32Dll.MOUSEINPUT { dwFlags = 0x8001, dx = pos.X, dy = pos.Y })) { throw new InputException("SendInput is not successful"); } } } else { User32Dll.SendMessage(hwnd, 0x0200, MakeParam(GetMouseKeyStates()), MakeParam(pos.X, pos.Y)); } await Task.Delay(delay); }); } } }