253 lines
9.0 KiB
C#
253 lines
9.0 KiB
C#
|
|
using AutoAgent.Domain.Exceptions;
|
|||
|
|
|
|||
|
|
namespace AutoAgent.Domain
|
|||
|
|
{
|
|||
|
|
public static class InputHandler
|
|||
|
|
{
|
|||
|
|
private static Dictionary<IntPtr, Dictionary<Models.Button, bool>> _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<Models.Button, bool> GetStateDict(IntPtr hwnd)
|
|||
|
|
{
|
|||
|
|
Dictionary<Models.Button, bool> 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);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|