This commit is contained in:
Gregory Lirent 2026-01-08 21:33:01 +03:00
commit d4e54e4854
34 changed files with 2545 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/.*/
/bin/
/obj/
/Properties/
/*.Development.json
/*.csproj.user

View File

@ -0,0 +1,6 @@
namespace AutoAgent.Controllers
{
public class DesktopController
{
}
}

View File

@ -0,0 +1,6 @@
namespace AutoAgent.Controllers
{
public class InputController
{
}
}

View File

@ -0,0 +1,6 @@
namespace AutoAgent.Controllers
{
public class ProcessController
{
}
}

195
Domain/DesktopHandler.cs Normal file
View File

@ -0,0 +1,195 @@
using AutoAgent.Domain.Exceptions;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
namespace AutoAgent.Domain
{
public static class DesktopHandler
{
private static Rectangle GetCaptureArea(IntPtr hwnd, Models.Point pt, Models.AreaSize size)
{
Rectangle area;
if (hwnd == IntPtr.Zero)
{
area = Rectangle.FromLTRB(User32Dll.GetSystemMetrics(76),
User32Dll.GetSystemMetrics(77),
User32Dll.GetSystemMetrics(78),
User32Dll.GetSystemMetrics(79));
}
else
{
if (User32Dll.GetClientRect(hwnd, out var rect))
{
User32Dll.RECT br = new () { X = rect.Right, Y = rect.Bottom };
if (User32Dll.ClientToScreen(hwnd, ref rect) && User32Dll.ClientToScreen(hwnd, ref br))
{
area = new Rectangle(rect.X, rect.Y, br.X - rect.X, br.Y - rect.Y);
}
else
{
throw new CaptureAreaException($"Could not convert client coordinates to screen coordinates for HWND: {hwnd}");
}
}
else
{
throw new CaptureAreaException($"Failed to get client rectangle for HWND: {hwnd}");
}
}
if (size.Width > 0 && size.Height > 0)
{
area = new Rectangle(
Math.Max(area.X, area.X + pt.X),
Math.Max(area.Y, area.Y + pt.Y),
Math.Min(size.Width, area.Right - pt.X),
Math.Min(size.Height, area.Bottom - pt.Y));
}
if (area.Width <= 0 || area.Height <= 0)
{
throw new CaptureAreaException($"Final capture rectangle has invalid dimensions: {area}");
}
return area;
}
private static bool GetWindowInfo(ref Models.WindowInfo data, IntPtr hwnd)
{
int length = User32Dll.GetWindowTextLength(hwnd);
if (length > 0)
{
var sb = new StringBuilder(length + 1);
User32Dll.GetWindowText(hwnd, sb, sb.Capacity);
data.Title = sb.ToString();
if (User32Dll.GetCursorPos(out var pt) && User32Dll.ScreenToClient(hwnd, ref pt))
{
data.CursorPosition = new Models.Point { X = pt.X, Y = pt.Y };
}
if (User32Dll.GetWindowRect(hwnd, out var wRect))
{
var rect = Rectangle.FromLTRB(wRect.Left, wRect.Top, wRect.Right, wRect.Bottom);
data.WindowPosition = new Models.Point { X = rect.X, Y = rect.Y };
data.WindowSize = new Models.AreaSize { Width = rect.Width, Height = rect.Height };
}
if (User32Dll.GetClientRect(hwnd, out var cRect))
{
var rect = Rectangle.FromLTRB(cRect.Left, cRect.Top, cRect.Right, cRect.Bottom);
data.ContentSize = new Models.AreaSize { Width = rect.Width, Height = rect.Height };
}
return true;
}
return false;
}
private static bool TryGetWindowInfo(IntPtr hwnd, ref IntPtr foreground, out Models.WindowInfo info)
{
info = new();
if (User32Dll.IsWindowVisible(hwnd))
{
info.Hwnd = hwnd.ToInt32();
if ((info.ThreadId = (int)User32Dll.GetWindowThreadProcessId(hwnd, out uint pid)) != 0)
{
info.Pid = (int)pid;
if (GetWindowInfo(ref info, hwnd))
{
info.IsActive = foreground.ToInt32() == info.Hwnd;
return true;
}
}
}
return false;
}
public static Task<IEnumerable<Models.WindowInfo>> GetWindows(ushort max = 0, IEnumerable<int>? whitelist = null)
{
if (max == 0) max = UInt16.MaxValue;
if (whitelist == null) whitelist = Array.Empty<int>();
return Task.Run(() =>
{
var foreground = User32Dll.GetForegroundWindow();
List<Models.WindowInfo> container = new();
User32Dll.EnumWindows(delegate (IntPtr hwnd, IntPtr lParam)
{
bool found = true;
if (container.Count >= max) return false;
foreach (var w in whitelist)
{
if (w == hwnd.ToInt32())
{
found = true;
break;
}
found = false;
}
if (found && TryGetWindowInfo(hwnd, ref foreground, out var info))
{
container.Add(info);
}
return true;
}, IntPtr.Zero);
return (IEnumerable<Models.WindowInfo>)container;
});
}
public static Task<(Models.AreaSize size, byte[] pngImage)> GetScreenshot(Models.Point pos, Models.AreaSize size, IntPtr hwnd = 0)
{
return Task.Run(() =>
{
Rectangle area = GetCaptureArea(hwnd, pos, size);
using (Bitmap screenshot = new Bitmap(area.Width, area.Height, PixelFormat.Format32bppArgb))
{
using (Graphics g = Graphics.FromImage(screenshot))
{
g.CopyFromScreen(area.X, area.Y, 0, 0, area.Size, CopyPixelOperation.SourceCopy);
}
using (MemoryStream ms = new MemoryStream())
{
screenshot.Save(ms, ImageFormat.Png);
return (new Models.AreaSize { Width = screenshot.Width, Height = screenshot.Height }, ms.ToArray());
}
}
});
}
public static Task<(byte r, byte g, byte b)> GetPixelColor(Models.Point pos, IntPtr hwnd = 0)
{
return Task.Run(() =>
{
Rectangle area = GetCaptureArea(hwnd, pos, new Models.AreaSize { Width = 1, Height = 1 });
using (Bitmap screenPixel = new Bitmap(1, 1))
{
using (Graphics g = Graphics.FromImage(screenPixel))
{
g.CopyFromScreen(area.Left, area.Top, 0, 0, screenPixel.Size);
}
var color = screenPixel.GetPixel(0, 0);
return (color.R, color.G, color.B);
}
});
}
}
}

View File

@ -0,0 +1,12 @@
namespace AutoAgent.Domain.Exceptions
{
public class CaptureException : DomainException
{
public CaptureException(string message) : base(message) { }
}
public class CaptureAreaException : CaptureException
{
public CaptureAreaException(string message) : base(message) { }
}
}

View File

@ -0,0 +1,8 @@
namespace AutoAgent.Domain.Exceptions
{
public class DomainException : Exception
{
public DomainException(string message) : base(message) { }
public DomainException(string message, Exception innerException) : base(message, innerException) { }
}
}

View File

@ -0,0 +1,12 @@
namespace AutoAgent.Domain.Exceptions
{
public class InputException : DomainException
{
public InputException(string message) : base(message) { }
}
public class UnexpectedInputButton : InputException
{
public UnexpectedInputButton(Models.Button button) : base($"Unexpected button {button}") { }
}
}

97
Domain/IPCHandler.cs Normal file
View File

@ -0,0 +1,97 @@
using AutoAgent.Domain.Models;
using Google.Protobuf;
using System.Reflection;
namespace AutoAgent.Domain
{
public static class IPCHandler
{
public static byte[] Serialize<T>(T message) where T : IMessage<T>
{
if (message == null)
{
throw new ArgumentNullException(nameof(message), "Protobuf message cannot be null for serialization.");
}
return message.ToByteArray();
}
public static T Deserialize<T>(byte[] data) where T : IMessage<T>, new()
{
if (data == null)
{
throw new ArgumentNullException(nameof(data), "Byte array cannot be null for deserialization.");
}
PropertyInfo? parserProperty = typeof(T).GetProperty("Parser", BindingFlags.Static | BindingFlags.Public);
if (parserProperty == null)
{
throw new InvalidOperationException($"Type {typeof(T).Name} does not have a static 'Parser' property.");
}
MessageParser<T>? parser = parserProperty.GetValue(null) as MessageParser<T>;
if (parser == null)
{
throw new InvalidOperationException($"Could not get MessageParser for type {typeof(T).Name}.");
}
return parser.ParseFrom(data);
}
public static Request CreateRequest<T>(uint id, CommandType commandType, T payloadMessage) where T : IMessage<T>
{
return new Request
{
Id = id,
Type = commandType,
Payload = ByteString.CopyFrom(Serialize(payloadMessage))
};
}
public static Response CreateResponse<T>(uint id, bool success, string? errorMessage, T payloadMessage) where T : IMessage<T>
{
return new Response
{
Id = id,
Success = success,
Message = errorMessage ?? string.Empty,
Payload = ByteString.CopyFrom(Serialize(payloadMessage))
};
}
public static Response CreateErrorResponse(uint id, string errorMessage)
{
return new Response
{
Id = id,
Success = false,
Message = errorMessage
};
}
public static T ExtractPayload<T>(Request request) where T : IMessage<T>, new()
{
if (request == null)
{
throw new ArgumentNullException(nameof(request), "Request cannot be null.");
}
if (request.Payload == null || request.Payload.IsEmpty)
{
throw new ArgumentNullException(nameof(request.Payload), "Request payload is null or empty.");
}
return Deserialize<T>(request.Payload.ToByteArray());
}
public static T ExtractPayload<T>(Response response) where T : IMessage<T>, new()
{
if (response == null)
{
throw new ArgumentNullException(nameof(response), "Response cannot be null.");
}
if (response.Payload == null || response.Payload.IsEmpty)
{
throw new ArgumentNullException(nameof(response.Payload), "Response payload is null or empty.");
}
return Deserialize<T>(response.Payload.ToByteArray());
}
}
}

252
Domain/InputHandler.cs Normal file
View File

@ -0,0 +1,252 @@
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);
});
}
}
}

View File

@ -0,0 +1,68 @@
using System.Collections.Concurrent;
namespace AutoAgent.Domain.Models
{
public class ConcurrentObject
{
internal readonly object _lock = new object();
public void LockedSet<T>(ref T dst, T value)
{
lock (_lock) dst = value;
}
public T LockedGet<T>(ref T src)
{
lock (_lock) return src;
}
}
public class LazyConcurrentContainer<T> : ConcurrentObject
{
private DateTime _lastScan = DateTime.MinValue;
private DateTime _currentScan = DateTime.MinValue;
private ConcurrentDictionary<long, T>? _container;
public DateTime LastUpdate
{
get => LockedGet(ref _lastScan);
}
public TimeSpan Elapsed
{
get { lock (_lock) return _currentScan - _lastScan; }
}
public ConcurrentDictionary<long, T>? Container
{
get => LockedGet(ref _container);
set
{
lock (_lock)
{
_lastScan = _currentScan;
_currentScan = DateTime.UtcNow;
_container = value;
}
}
}
public IEnumerable<T>? Values
{
get => _container?.Values.ToList();
}
public void SetContainer(Dictionary<long, T>? container)
{
Container = container != null ? new ConcurrentDictionary<long, T>(container) : null;
}
public void SetContainer(ConcurrentDictionary<long, T> container)
{
Container = container != null ? new ConcurrentDictionary<long, T>(container) : null;
}
public void CleanContainer()
{
Container = null;
}
}
}

128
Domain/Models/Delay.cs Normal file
View File

@ -0,0 +1,128 @@
using AutoAgent.Domain.Utils;
namespace AutoAgent.Domain.Models
{
public class Delay : BaseRandom, IComparable<Delay>
{
private int _min = 0;
private int _max = 0;
private bool _mutable = true;
public readonly static Delay None = new Delay { _mutable = false };
public readonly static Delay Random = new Delay { _mutable = false, Min = 50, Max = 250 };
public int Value
{
set => _max = _min = value;
get => (_max > _min) ? Generate(_min, _max) : _min;
}
public int Min
{
get => _min > _max ? _max : _min;
set
{
if (!_mutable)
{
throw new InvalidOperationException("Object is not mutable");
}
_min = value;
}
}
public int Max
{
get => _max < _min ? _min : _max;
set
{
if (!_mutable)
{
throw new InvalidOperationException("Object is not mutable");
}
_max = value;
}
}
async public Task WaitAsync()
{
await Task.Delay(Value);
}
public void Wait()
{
Thread.Sleep(Value);
}
public static bool operator ==(Delay? left, Delay? right)
{
if (left == null && right == null) return true;
if (left == null || right == null) return false;
return left._min == right._min && left._max == right._max;
}
public static bool operator !=(Delay? left, Delay? right)
{
return !(left == right);
}
public override bool Equals(object? obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
Delay other = (Delay)obj;
return this == other;
}
public override int GetHashCode()
{
return HashCode.Combine(_min, _max);
}
public static bool operator <(Delay left, Delay right)
{
if (left._min < right._min)
{
return true;
}
if (left._min == right._min && left._max < right._max)
{
return true;
}
return false;
}
public static bool operator >(Delay left, Delay right)
{
if (left._min > right._min)
{
return true;
}
if (left._min == right._min && left._max > right._max)
{
return true;
}
return false;
}
public static bool operator <=(Delay left, Delay right)
{
return left < right || left == right;
}
public static bool operator >=(Delay left, Delay right)
{
return left > right || left == right;
}
public int CompareTo(Delay? other)
{
if (other == null)
{
return 1;
}
int result = _min.CompareTo(other._min);
if (result != 0)
{
return result;
}
return _max.CompareTo(other._max);
}
}
}

61
Domain/Models/Key.cs Normal file
View File

@ -0,0 +1,61 @@
namespace AutoAgent.Domain.Models
{
public class Key
{
public Button Code { get; private set; }
public Key(Button code) { Code = code; }
public Key(string key)
{
Button code;
switch (key.ToLowerInvariant())
{
case "-": case "_": Code = Button.Sub; break;
case "+": case "=": Code = Button.Add; break;
case "~": case "`": Code = Button.Tilde; break;
case "<": case ",": Code = Button.Comma; break;
case ">": case ".": Code = Button.Period; break;
case ":": case ";": Code = Button.Colon; break;
case "{": case "[": Code = Button.LBracket; break;
case "}": case "]": Code = Button.RBracket; break;
case "\\": case "|": Code = Button.BSol; break;
case "/": case "?": Code = Button.Sol; break;
case "'": case "\"": Code = Button.Quote; break;
case "num+": Code = Button.NumAdd; break;
case "num-": Code = Button.NumSub; break;
case "num*": Code = Button.NumMul; break;
case "num/": Code = Button.NumDiv; break;
case "num.": Code = Button.NumDec; break;
case "a": case "b": case "c": case "d": case "e": case "f":
case "g": case "h": case "i": case "j": case "k": case "l":
case "m": case "n": case "o": case "p": case "q": case "r":
case "s": case "t": case "u": case "v": case "w": case "x":
case "y": case "z": case "0": case "1": case "2": case "3":
case "4": case "5": case "6": case "7": case "8": case "9":
if (Enum.TryParse($"Key{key}", out code))
{
Code = code;
break;
}
else goto default;
case "shift": case "ctrl": case "alt": case "win":
if (Enum.TryParse($"L{key}", out code))
{
Code = code;
break;
}
else goto default;
default:
if (Enum.TryParse(key, out code))
{
Code = code;
break;
}
else throw new ArgumentException($"Unexpected key \"{key}\"");
}
}
}
}

View File

@ -0,0 +1,91 @@
using AutoAgent.Domain.Utils;
using Google.Protobuf;
namespace AutoAgent.Domain.Models
{
public class KeyShortcut
{
private readonly static DelayGenerator _dGen = new(new RandomNumberGenerator<int>(75, 200));
private Queue<Key> _queue = new();
public KeyShortcut(Key key) { And(key); }
public KeyShortcut(string key) { And(key); }
public KeyShortcut And(Key key)
{
_queue.Enqueue(key);
return this;
}
public KeyShortcut And(string key)
{
return And(new Key(key));
}
public IEnumerable<InputAction> GetHoldDownActions()
{
Key key;
var actions = new InputAction[_queue.Count];
for (int i = 0, n = _queue.Count; i < n;)
{
_queue.Enqueue(key = _queue.Dequeue());
actions[i++] = new InputAction()
{
DelayMs = (uint)_dGen.Next().Value,
Type = InputType.KeyDown,
Payload = ByteString.CopyFrom(IPCHandler.Serialize(new ButtonInput { Button = key.Code }))
};
}
return actions;
}
public IEnumerable<InputAction> GetHoldUpActions()
{
Key key;
var actions = new InputAction[_queue.Count];
for (int n = _queue.Count; n > 0;)
{
_queue.Enqueue(key = _queue.Dequeue());
actions[--n] = new InputAction()
{
DelayMs = (uint)_dGen.Next().Value,
Type = InputType.KeyUp,
Payload = ByteString.CopyFrom(IPCHandler.Serialize(new ButtonInput { Button = key.Code }))
};
}
return actions;
}
public IEnumerable<InputAction> GetInputActions()
{
Key key;
int n = _queue.Count * 2;
var actions = new InputAction[n];
for (int i = 0; i < n;)
{
_queue.Enqueue(key = _queue.Dequeue());
actions[i++] = new InputAction()
{
DelayMs = (uint)_dGen.Next().Value,
Type = InputType.KeyDown,
Payload = ByteString.CopyFrom(IPCHandler.Serialize(new ButtonInput { Button = key.Code }))
};
actions[--n] = new InputAction()
{
DelayMs = (uint)_dGen.Next().Value,
Type = InputType.KeyUp,
Payload = ByteString.CopyFrom(IPCHandler.Serialize(new ButtonInput { Button = key.Code }))
};
}
return actions;
}
}
}

View File

@ -0,0 +1,34 @@
namespace AutoAgent.Domain.Models
{
public class KeyShortcutSequence
{
private Queue<KeyValuePair<KeyShortcut, uint>> _queue = new();
public KeyShortcutSequence(KeyShortcut key) { Next(key); }
public KeyShortcutSequence Next(KeyShortcut shortcut, int delay = 0)
{
_queue.Enqueue(new KeyValuePair<KeyShortcut, uint>(shortcut, (uint)delay));
return this;
}
public IEnumerable<InputAction> GetInputActions()
{
var actions = new InputAction[0];
do
{
var kvpair = _queue.Dequeue();
if (actions.Length > 0)
{
actions[actions.Length - 1].DelayMs += kvpair.Value;
}
actions = actions.Concat(kvpair.Key.GetInputActions()).ToArray();
} while (_queue.Count > 0);
return actions;
}
}
}

View File

@ -0,0 +1,30 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
namespace AutoAgent.Domain.Models
{
public class MemoryBuffer : IDisposable
{
private IntPtr _memory;
public IntPtr SetStruct<T>([DisallowNull] T value, bool fDeleteOld = true)
{
Marshal.StructureToPtr(value, _memory, true);
return _memory;
}
public MemoryBuffer(int size)
{
_memory = Marshal.AllocHGlobal(User32Dll.INPUT_SIZE);
}
public void Dispose()
{
if (_memory != IntPtr.Zero)
{
Marshal.FreeHGlobal(_memory);
_memory = IntPtr.Zero;
}
}
}
}

245
Domain/Models/ipc.proto Normal file
View File

@ -0,0 +1,245 @@
syntax = "proto3";
option csharp_namespace = "AutoAgent.Domain.Models";
enum CommandType {
UNKNOWN_COMMAND_TYPE = 0;
GET_WINDOWS_INFO = 1;
GET_SCREENSHOT = 2;
GET_PIXEL_COLOR = 3;
INPUT_ACTION = 4;
}
message Point {
int32 X = 1;
int32 Y = 2;
}
message AreaSize {
int32 width = 1;
int32 height = 2;
}
message WindowInfo
{
int32 hwnd = 1;
string title = 2;
int32 pid = 3;
int32 thread_id = 4;
bool is_active = 5;
Point cursor_position = 6;
AreaSize content_size = 7;
Point window_position = 8;
AreaSize window_size = 9;
}
message WindowsRequest {
repeated int32 hwnds = 1;
}
message WindowsResponse {
repeated WindowInfo data = 1;
}
message Request {
uint32 id = 1;
CommandType type = 2;
bytes payload = 15;
}
message Response {
uint32 id = 1;
bool success = 2;
string message = 3;
bytes payload = 15;
}
message ScreenshotRequest {
int32 hwnd = 1;
Point crop_position = 2;
AreaSize crop_size = 3;
}
message ScreenshotResponse {
AreaSize size = 1;
bytes data = 2;
}
message PixelRequest {
int32 hwnd = 1;
Point pixel_position = 2;
}
message PixelResponse {
uint32 rgb_color = 1;
}
enum InputType {
UNKNOWN_INPUT_TYPE = 0;
KEY_UP = 1;
KEY_DOWN = 2;
MOUSE_SCROLL = 3;
MOUSE_MOVE_TO = 4;
}
message InputAction {
InputType type = 1;
uint32 delay_ms = 2;
bytes payload = 15;
}
message ButtonInput {
Button button = 1;
}
message ScrollInput {
int32 offset = 1;
}
message MouseMoveInput {
Point position = 1;
}
message InputRequest {
int32 hwnd = 1;
repeated InputAction actions = 2;
}
message InputResponse {
int32 count = 1;
}
enum Button {
UNKNOWN_BUTTON = 0;
EXTENDED_KEY_FLAG = 32768; // 0x8000
MOUSE_EXTRA_FLAG = 128; // 0x0080
MOUSE_KEY_FLAG = 16384; // 0x4000
MOUSE_LEFT = 16386; // MOUSE_KEY_FLAG | 0x0002
MOUSE_RIGHT = 16392; // MOUSE_KEY_FLAG | 0x0008
MOUSE_MIDDLE = 16416; // MOUSE_KEY_FLAG | 0x0020
MOUSE_EXTRA1 = 16513; // MOUSE_KEY_FLAG | MOUSE_EXTRA_FLAG | 0x01
MOUSE_EXTRA2 = 16514; // MOUSE_KEY_FLAG | MOUSE_EXTRA_FLAG | 0x02
// --- Toggle Keys ---
CAPS_LOCK = 20; // 0x14
NUM_LOCK = 144; // 0x90
SCROLL_LOCK = 145; // 0x91
// --- Main Control Keys ---
BACKSPACE = 8; // 0x08
TAB = 9; // 0x09
ENTER = 13; // 0x0D
PAUSE = 19; // 0x13
ESCAPE = 27; // 0x1B
SPACE = 32; // 0x20
// --- Navigation and Editing Keys ---
PAGE_UP = 32793; // EXTENDED_KEY_FLAG | 0x21
PAGE_DOWN = 32794; // EXTENDED_KEY_FLAG | 0x22
END = 32795; // EXTENDED_KEY_FLAG | 0x23
HOME = 32796; // EXTENDED_KEY_FLAG | 0x24
LEFT = 32797; // EXTENDED_KEY_FLAG | 0x25
UP = 32798; // EXTENDED_KEY_FLAG | 0x26
RIGHT = 32799; // EXTENDED_KEY_FLAG | 0x27
DOWN = 32800; // EXTENDED_KEY_FLAG | 0x28
PRINT_SCREEN = 32808; // EXTENDED_KEY_FLAG | 0x2C
INSERT = 32813; // EXTENDED_KEY_FLAG | 0x2D
DELETE = 32814; // EXTENDED_KEY_FLAG | 0x2E
// --- Main Alphanumeric Keys ---
KEY_0 = 48; // 0x30
KEY_1 = 49; // 0x31
KEY_2 = 50; // 0x32
KEY_3 = 51; // 0x33
KEY_4 = 52; // 0x34
KEY_5 = 53; // 0x35
KEY_6 = 54; // 0x36
KEY_7 = 55; // 0x37
KEY_8 = 56; // 0x38
KEY_9 = 57; // 0x39
KEY_A = 65; // 0x41
KEY_B = 66; // 0x42
KEY_C = 67; // 0x43
KEY_D = 68; // 0x44
KEY_E = 69; // 0x45
KEY_F = 70; // 0x46
KEY_G = 71; // 0x47
KEY_H = 72; // 0x48
KEY_I = 73; // 0x49
KEY_J = 74; // 0x4A
KEY_K = 75; // 0x4B
KEY_L = 76; // 0x4C
KEY_M = 77; // 0x4D
KEY_N = 78; // 0x4E
KEY_O = 79; // 0x4F
KEY_P = 80; // 0x50
KEY_Q = 81; // 0x51
KEY_R = 82; // 0x52
KEY_S = 83; // 0x53
KEY_T = 84; // 0x54
KEY_U = 85; // 0x55
KEY_V = 86; // 0x56
KEY_W = 87; // 0x57
KEY_X = 88; // 0x58
KEY_Y = 89; // 0x59
KEY_Z = 90; // 0x5A
// --- Windows Keys ---
L_WIN = 32859; // EXTENDED_KEY_FLAG | 0x5B
R_WIN = 32860; // EXTENDED_KEY_FLAG | 0x5C
APPS = 32861; // EXTENDED_KEY_FLAG | 0x5D
// --- Numeric Keypad (NumPad) ---
NUM_0 = 32864; // EXTENDED_KEY_FLAG | 0x60
NUM_1 = 32865; // EXTENDED_KEY_FLAG | 0x61
NUM_2 = 32866; // EXTENDED_KEY_FLAG | 0x62
NUM_3 = 32867; // EXTENDED_KEY_FLAG | 0x63
NUM_4 = 32868; // EXTENDED_KEY_FLAG | 0x64
NUM_5 = 32869; // EXTENDED_KEY_FLAG | 0x65
NUM_6 = 32870; // EXTENDED_KEY_FLAG | 0x66
NUM_7 = 32871; // EXTENDED_KEY_FLAG | 0x67
NUM_8 = 32872; // EXTENDED_KEY_FLAG | 0x68
NUM_9 = 32873; // EXTENDED_KEY_FLAG | 0x69
NUM_MUL = 106; // 0x6A
NUM_ADD = 107; // 0x6B
NUM_SUB = 109; // 0x6D
NUM_DEC = 32878; // EXTENDED_KEY_FLAG | 0x6E
NUM_DIV = 32879; // EXTENDED_KEY_FLAG | 0x6F
NUM_ENTER = 32781; // EXTENDED_KEY_FLAG | ENTER
// --- Function Keys ---
F1 = 112; // 0x70
F2 = 113; // 0x71
F3 = 114; // 0x72
F4 = 115; // 0x73
F5 = 116; // 0x74
F6 = 117; // 0x75
F7 = 118; // 0x76
F8 = 119; // 0x77
F9 = 120; // 0x78
F10 = 121; // 0x79
F11 = 122; // 0x7A
F12 = 123; // 0x7B
// --- Modifier Keys ---
L_SHIFT = 160; // 0xA0
R_SHIFT = 161; // 0xA1
L_CTRL = 162; // 0xA2
R_CTRL = 32875; // EXTENDED_KEY_FLAG | 0xA3
L_ALT = 164; // 0xA4
R_ALT = 32877; // EXTENDED_KEY_FLAG | 0xA5
// --- OEM Keys ---
SUB = 189; // 0xBD
ADD = 187; // 0xBB
TILDE = 192; // 0xC0
L_BRACKET = 219; // 0xDB
R_BRACKET = 221; // 0xDD
COMMA = 188; // 0xBC
PERIOD = 190; // 0xBE
QUOTE = 222; // 0xDE
COLON = 186; // 0xBA
SOL = 191; // 0xBF
B_SOL = 220; // 0xDC
}

225
Domain/PInvoke.cs Normal file
View File

@ -0,0 +1,225 @@
using System.Runtime.InteropServices;
using System.Text;
namespace AutoAgent.Domain
{
internal static class User32Dll
{
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Explicit)]
public struct INPUT
{
[FieldOffset(0)]
public int type;
[FieldOffset(8)]
public MOUSEINPUT mi;
[FieldOffset(8)]
public KEYBDINPUT ki;
}
public static readonly int INPUT_SIZE = Marshal.SizeOf(typeof(INPUT));
[StructLayout(LayoutKind.Explicit)]
public struct RECT
{
[FieldOffset(0)] public int Left;
[FieldOffset(4)] public int Top;
[FieldOffset(8)] public int Right;
[FieldOffset(12)] public int Bottom;
[FieldOffset(0)] public int X;
[FieldOffset(4)] public int Y;
}
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern uint SendInput(uint nInputs, IntPtr pInputs, int cbSize);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern short GetKeyState(int nVirtKey);
[DllImport("user32.dll")]
public static extern int MapVirtualKey(int uCode, uint uMapType);
[DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ScreenToClient(IntPtr hWnd, ref RECT lpPoint);
[DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern int GetWindowText(IntPtr hwnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetCursorPos(out RECT lpPoint);
[DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetClientRect(IntPtr hwnd, out RECT lpRect);
[DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ClientToScreen(IntPtr hWnd, ref RECT lpPoint);
[DllImport("user32.dll")]
public static extern int GetSystemMetrics(int nIndex);
}
internal static class Kernel32Dll
{
[Flags]
public enum MemoryState : uint
{
Commit = 0x00001000,
Reserve = 0x00002000,
Free = 0x00010000,
}
[Flags]
public enum MemoryType : uint
{
Image = 0x01000000,
Mapped = 0x00040000,
Private = 0x00020000,
}
[Flags]
public enum MemoryPageProtectionState : uint
{
NoAccess = 0x0001,
ReadOnly = 0x0002,
ReadWrite = 0x0004,
WriteCopy = 0x0008,
Execute = 0x0010,
ExecuteRead = 0x0020,
ExecuteReadWrite = 0x0040,
ExecuteWriteCopy = 0x0080,
Guard = 0x0100,
NoCache = 0x0200,
WriteCombine = 0x0400,
}
[StructLayout(LayoutKind.Sequential)]
public struct MemoryBasicInformation
{
public IntPtr BaseAddress;
public IntPtr AllocationBase;
public uint AllocationProtect;
public ushort PartitionId;
public UIntPtr RegionSize;
public MemoryState State;
public MemoryPageProtectionState PageProtection;
public MemoryType Type;
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
uint dwDesiredAccess,
[MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
int dwProcessId
);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int VirtualQueryEx(
IntPtr hProcess,
IntPtr lpAddress,
out MemoryBasicInformation lpBuffer,
uint dwLength
);
}
internal static class PsApiDll
{
[Flags]
public enum ModuleFilterFlags : uint
{
Default = 0x00,
Modules32Bit = 0x01,
Modules64Bit = 0x02,
ModulesAll = Modules32Bit | Modules64Bit,
}
[StructLayout(LayoutKind.Sequential)]
public struct ModuleInformation
{
public IntPtr BaseAddress;
public uint MemorySize;
public IntPtr EntryPointAddress;
public StringBuilder Name;
public StringBuilder FileName;
}
[DllImport("psapi.dll", SetLastError = true)]
public static extern bool EnumProcessModulesEx(
IntPtr hProcess,
out IntPtr[] lphModule,
uint cb,
out uint lpcbNeeded,
ModuleFilterFlags dwFilterFlag
);
[DllImport("psapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint GetModuleFileNameEx(
IntPtr hProcess,
IntPtr hModule,
[Out] StringBuilder lpFilename,
uint nSize
);
[DllImport("psapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint GetModuleBaseName(
IntPtr hProcess,
IntPtr hModule,
out StringBuilder lpBaseName,
uint nSize
);
[DllImport("psapi.dll", SetLastError = true)]
public static extern bool GetModuleInformation(
IntPtr hProcess,
IntPtr hModule,
out ModuleInformation lpmodinfo,
uint cb
);
}
}

View File

@ -0,0 +1,16 @@
using AutoAgent.Domain.Models;
using System.Text.Json.Serialization;
namespace AutoAgent.Domain
{
public static class ProcessScanHandler
{
public static IEnumerable<ProcessInfo> GetProcesses()
{
}
}
}

View File

@ -0,0 +1,180 @@
using System.Collections;
using System.Drawing;
using System.Numerics;
namespace AutoAgent.Domain.Utils
{
public interface ISequenceGenerator<T> : IEnumerable<T>
{
public static bool IsZero(double val, double epsilon = Double.Epsilon)
{
return Math.Abs(val) < epsilon;
}
public T Min { get; }
public T Max { get; }
public double Progress { get; }
public double Step { get; }
public bool HasValues { get; }
public T Next();
public ISequenceGenerator<T> Reset();
}
public interface INumberGenerator<T> : ISequenceGenerator<T> where T : struct, INumber<T>
{
public INumberGenerator<T> Self { get; }
public virtual double DMin { get => Double.CreateChecked(Min); }
public virtual double DMax { get => Double.CreateChecked(Max); }
public virtual double Mean { get => (DMin + DMax) / 2.0; }
}
public interface IPointGenerator : ISequenceGenerator<Point>
{
public static double CalcDistance(Point pt1, Point pt2)
{
return Math.Sqrt(Math.Pow(pt1.X - pt2.X, 2) + Math.Pow(pt1.Y - pt2.Y, 2));
}
public static double CalcAngle(Point pt1, Point pt2)
{
return Math.Atan2(pt2.Y - pt1.Y, pt2.X - pt1.X);
}
public static Point CalcPoint(double x, double y, double offset, double pAngle)
{
return new Point((int)Math.Round(x + offset * Math.Cos(pAngle)), (int)Math.Round(y + offset * Math.Sin(pAngle)));
}
public static Point CalcMiddle(Point start, Point end)
{
return new Point(
(int)Math.Round(start.X + (end.X - start.X) / 2.0),
(int)Math.Round(start.Y + (end.Y - start.Y) / 2.0)
);
}
public static (double distance, double angle) CalcDistanceAngle(Point pt1, Point pt2)
{
double dx = pt2.X - pt1.X;
double dy = pt2.Y - pt1.Y;
return (Math.Sqrt(Math.Pow(dx, 2) + Math.Pow(dy, 2)), Math.Atan2(dy, dx));
}
public static double DegreesToRadians(double degrees)
{
return degrees * Math.PI / 180.0;
}
public static double RadiansToDegrees(double radians)
{
return radians * (180.0 / Math.PI);
}
public static Point NewPointAngleDistance(Point refPt, double distance, double aRadians, double epsilon = Double.Epsilon)
{
int x, y;
if (IsZero(distance, epsilon)) return new Point(refPt.X, refPt.Y);
x = (int)Math.Round(refPt.X + distance * Math.Cos(aRadians));
y = (int)Math.Round(refPt.Y + distance * Math.Sin(aRadians));
return new Point(x, y);
}
public static Point NewPointDistance(Point refPt, Point targetPt, double distance, double epsilon = Double.Epsilon)
{
return NewPointAngleDistance(refPt, distance, CalcAngle(refPt, targetPt), epsilon);
}
public static Point NewPointAngle(Point refPt, Point targetPt, double aRadians, double epsilon = Double.Epsilon)
{
return NewPointAngleDistance(refPt, CalcDistance(refPt, targetPt), aRadians, epsilon);
}
public static Point NewPointDistanceFactor(Point refPt, Point targetPt, double factor, double epsilon = Double.Epsilon)
{
return NewPointAngleDistance(refPt, CalcDistance(refPt, targetPt) * factor, CalcAngle(refPt, targetPt), epsilon);
}
public static Point GetRandomPointInRect(Rectangle rect)
{
double x = BaseRandom.NextGenerate(rect.X, rect.Width);
double y = BaseRandom.NextGenerate(rect.Y, rect.Height);
return new Point((int)Math.Round(x), (int)Math.Round(y));
}
public IPointGenerator Self { get; }
public virtual Point Start { get => Min; }
public virtual Point End { get => Max; }
public virtual double LinearX { get => Start.X + (End.X - Start.X) * Progress; }
public virtual double LinearY { get => Start.Y + (End.Y - Start.Y) * Progress; }
}
public abstract class BaseGenerator<T> : BaseRandom, ISequenceGenerator<T>
{
protected virtual double Epsilon { get; set; } = 0.01;
protected virtual bool IsZero(double val)
{
return ISequenceGenerator<T>.IsZero(val, Epsilon);
}
private double _fShape = 1.0;
private double _fFade = 0.5;
public T Min { get; protected set; }
public T Max { get; protected set; }
public virtual double Progress { get; protected set; } = -1.0;
public double ProgressRemainder { get => 1.0 - Progress; }
public virtual bool HasValues { get; protected set; } = true;
public double FShape { get => _fShape; protected set => _fShape = Math.Clamp(value, 0.0, 1.0); }
public double FFade { get => _fFade; protected set => _fFade = Math.Clamp(value, Epsilon, 1.0); }
protected double Scale { get => Math.Pow(Progress * ProgressRemainder * 4.0, FFade) * FShape; }
public abstract double Step { get; protected set; }
public BaseGenerator(T min, T max)
{
Min = min;
Max = max;
}
protected static double CalcStepByCount(int count)
{
return 1.0 / count;
}
protected abstract T Calc();
protected virtual T First() => Calc();
protected virtual T Last() => Calc();
public virtual T Next()
{
if (Progress < 0)
{
Progress = 0;
return First();
}
if ((Progress += Step) >= 1.0)
{
HasValues = false;
Progress = 1.0;
return Last();
}
return Calc();
}
public virtual ISequenceGenerator<T> Reset()
{
HasValues = true;
Progress = -1.0;
return this;
}
public IEnumerator<T> GetEnumerator()
{
while (HasValues)
{
yield return Next();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

View File

@ -0,0 +1,94 @@
using System.Numerics;
namespace AutoAgent.Domain.Utils
{
public class BaseRandom
{
private readonly static Random _random = new Random();
private static readonly BaseRandom _self = new BaseRandom();
protected Random? _pRandom = null;
private Random Rand { get => _pRandom == null ? _random : _pRandom; }
public static byte[] NextGenerate(byte[] data)
{
return _self.Generate(data);
}
public static T NextGenerate<T>(T min, T max)
where T : struct, INumber<T>
{
return _self.Generate(min, max);
}
public static T NextSpread<T>(T value, T offset)
where T : struct, INumber<T>
{
return _self.Spread(value, offset);
}
public byte[] Generate(byte[] data)
{
Rand.NextBytes(data);
return data;
}
public double Generate(double min, double max)
{
if (min > max)
{
throw new ArgumentOutOfRangeException(nameof(min), "minValue cannot be greater than maxValue.");
}
return min + (max - min) * Rand.NextDouble();
}
public long Generate(long min, long max)
{
return Rand.NextInt64(min, max + 1);
}
public ulong Generate(ulong min, ulong max)
{
ulong res;
long lmin = (long)min;
long lmax = (long)max;
if (lmin > lmax) res = (ulong)Rand.NextInt64(lmax, lmin + 1);
else res = (ulong)Rand.NextInt64(lmin, lmax + 1);
return UInt64.Clamp(res, min, max);
}
public uint Generate(uint min, uint max)
{
return (uint)Generate((long)min, (long)max);
}
public T Generate<T>(T min, T max) where T : struct, INumber<T>
{
var min32 = Int32.CreateChecked(min);
var max32 = Int32.CreateChecked(max);
return T.CreateChecked(Rand.Next(min32, max32));
}
public T Spread<T>(T value, T offset)
where T : struct, INumber<T>
{
T min, max, cur;
cur = T.CreateChecked(Math.Abs(Double.CreateChecked(offset)));
min = value - cur;
max = value + cur;
if (min > max)
{
var tmp = min;
min = max;
max = tmp;
}
value = Generate(min, max);
return value;
}
public BaseRandom() { }
public BaseRandom(int seed)
{
_pRandom = new Random(seed);
}
}
}

View File

@ -0,0 +1,161 @@
using System.Drawing;
using System.Numerics;
namespace AutoAgent.Domain.Utils
{
public abstract class BezierGenerator<T, TControl> : BaseGenerator<T> where TControl : struct
{
public bool IsCubic { get => Control2 != null; }
protected TControl Control1 { get; set; }
protected TControl? Control2 { get; set; }
public override double Step { get; protected set; }
protected double CalcBezier(double start, double end, double ctrl1, double? ctrl2)
{
double t = Progress;
double rt = ProgressRemainder;
if (IsCubic && ctrl2 != null)
{
double rt3 = rt * rt * rt;
double t3 = t * t * t;
double rt2_t = rt * rt * t;
double rt_t2 = rt * t * t;
return rt3 * start +
3 * rt2_t * ctrl1 +
3 * rt_t2 * ctrl2.Value +
t3 * end;
}
double rt2 = rt * rt;
double t2 = t * t;
double rt_t = rt * t;
return rt2 * start +
2 * rt_t * ctrl1 +
t2 * end;
}
public BezierGenerator(T min, T max, TControl ctrl1, TControl? ctrl2)
: base(min, max)
{
Control1 = ctrl1;
Control2 = ctrl2;
}
}
public class BezierNumberGenerator<T> : BezierGenerator<T, double>, INumberGenerator<T> where T : struct, INumber<T>
{
public INumberGenerator<T> Self { get => this; }
private double Bezier { get => CalcBezier(Self.DMin, Self.DMax, Control1, Control2); }
public BezierNumberGenerator<T> SetShapeFactor(double shape) { FShape = shape; return this; }
public BezierNumberGenerator<T> SetFadeFactor(double fade) { FFade = fade; return this; }
protected override T Calc()
{
return T.CreateChecked(Math.Clamp(Self.Mean + (Bezier - Self.Mean) * Scale, Self.DMin, Self.DMax));
}
public BezierNumberGenerator(T start, T end, double ctrl1, double? ctrl2 = null, int count = 10)
: base(start, end, ctrl1, ctrl2) { Step = CalcStepByCount(count); }
}
public class ArcNumberGenerator<T> : BezierNumberGenerator<T> where T : struct, INumber<T>
{
public ArcNumberGenerator(T start, T end, int count = 10, bool bidirectional = true, bool reverse = false)
: base(start, end, Double.NaN, null, count)
{
var hMean = (Self.DMax - Self.Mean);
if (bidirectional)
{
Control1 = (reverse) ? Self.DMin : Self.DMax;
Control2 = (reverse) ? Self.DMax : Self.DMin;
}
else
{
Control1 = (reverse) ? Self.DMin : Self.DMax;
}
}
}
public class BezierPointGenerator : BezierGenerator<Point, Point>, IPointGenerator
{
protected readonly double _pAngle;
public IPointGenerator Self { get => this; }
public BezierPointGenerator SetShapeFactor(double shape) { FShape = shape; return this; }
public BezierPointGenerator SetFadeFactor(double fade) { FFade = fade; return this; }
private double BezierX { get => CalcBezier(Min.X, Max.X, Control1.X, Control2?.X); }
private double BezierY { get => CalcBezier(Min.Y, Max.Y, Control1.Y, Control2?.Y); }
protected override Point Calc()
{
double dx = BezierX - Self.LinearX;
double dy = BezierY - Self.LinearY;
return IPointGenerator.CalcPoint(Self.LinearX + dx * Scale, Self.LinearY + dy * Scale, 0, 0);
}
public static BezierPointGenerator CreateByCount(Point start, Point end, Point ctrl1, Point? ctrl2 = null, int count = 10)
{
return new BezierPointGenerator(start, end, ctrl1, ctrl2)
{
Step = CalcStepByCount(count)
};
}
public static BezierPointGenerator CreateByStepSize(Point start, Point end, Point ctrl1, Point? ctrl2 = null, double pxPerStep = 5)
{
return new BezierPointGenerator(start, end, ctrl1, ctrl2, pxPerStep);
}
public BezierPointGenerator(Point start, Point end, Point ctrl1, Point? ctrl2 = null, double pxPerStep = 5)
: this(start, end, ctrl1, ctrl2)
{
Step = pxPerStep / IPointGenerator.CalcDistance(start, end);
}
public BezierPointGenerator(Point start, Point end, Point ctrl1, Point? ctrl2 = null)
: base(start, end, ctrl1, ctrl2)
{
_pAngle = IPointGenerator.CalcAngle(start, end) + Math.PI / 2.0;
}
}
public sealed class ArcPointGenerator : BezierPointGenerator
{
public new ArcPointGenerator SetShapeFactor(double shape) { base.SetShapeFactor(shape); return this; }
public new ArcPointGenerator SetFadeFactor(double fade) { base.SetFadeFactor(fade); return this; }
public static ArcPointGenerator CreateByCount(Point start, Point end, bool bidirectional = false, bool reverse = false, double arcHeight = 15.0, int count = 10)
{
return new ArcPointGenerator(start, end, bidirectional, reverse, arcHeight)
{
Step = CalcStepByCount(count)
};
}
public static ArcPointGenerator CreateByStepSize(Point start, Point end, bool bidirectional = false, bool reverse = false, double arcHeight = 15.0, double pxPerStep = 5)
{
return new ArcPointGenerator(start, end, bidirectional, reverse, arcHeight, pxPerStep);
}
public ArcPointGenerator(Point start, Point end, bool bidirectional = false, bool reverse = false, double arcHeight = 15.0, double pxPerStep = 5)
: this(start, end, bidirectional, reverse, arcHeight)
{
Step = pxPerStep / IPointGenerator.CalcDistance(start, end);
}
private ArcPointGenerator(Point start, Point end, bool bidirectional, bool reverse, double arcHeight)
: base(start, end, Point.Empty, null)
{
var height = (reverse) ? -arcHeight : arcHeight;
if (bidirectional)
{
Control1 = IPointGenerator.NewPointAngleDistance(IPointGenerator.NewPointDistanceFactor(start, end, 1.0 / 3.0), height, _pAngle);
Control2 = IPointGenerator.NewPointAngleDistance(IPointGenerator.NewPointDistanceFactor(start, end, 2.0 / 3.0), -height, _pAngle);
}
else
{
Control1 = IPointGenerator.NewPointAngleDistance(IPointGenerator.CalcMiddle(start, end), height, _pAngle);
}
}
}
}

View File

@ -0,0 +1,47 @@
using System.Collections;
using AutoAgent.Domain.Models;
namespace AutoAgent.Domain.Utils
{
public class DelayGenerator : ISequenceGenerator<Delay>
{
private ISequenceGenerator<int> _generator;
public Delay Min { get => new Delay { Value = _generator.Min }; }
public Delay Max { get => new Delay { Value = _generator.Max }; }
public double Progress { get => _generator.Progress; }
public double Step { get => _generator.Step; }
public bool HasValues { get => _generator.HasValues; }
public Delay Next()
{
if (!HasValues)
{
Reset();
}
return new Delay { Value = _generator.Next() };
}
public ISequenceGenerator<Delay> Reset()
{
_generator.Reset();
return this;
}
public DelayGenerator(ISequenceGenerator<int> generator)
{
_generator = generator;
}
public IEnumerator<Delay> GetEnumerator()
{
while (HasValues)
{
yield return Next();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

View File

@ -0,0 +1,206 @@
using System.Drawing;
using System.Numerics;
namespace AutoAgent.Domain.Utils
{
public abstract class OscillationGenerator<T> : BaseGenerator<T>
{
private int _segments = 1;
private double _amplitude = 100.0;
public double Amplitude { get => _amplitude; protected set => _amplitude = Math.Abs(value); }
public int Segments { get => _segments; protected set => _segments = value < 1 ? 1 : value; }
public override double Step { get; protected set; }
protected abstract double FOffset { get; }
public OscillationGenerator(T min, T max)
: base(min, max) { }
}
public abstract class SawtoothGenerator<T> : OscillationGenerator<T>
{
protected override double FOffset { get { double s = (Progress * Segments) % 1.0; return (s < 0.5 ? s : (1.0 - s)) * 4.0 - 1.0; } }
public SawtoothGenerator(T min, T max)
: base(min, max) { }
}
public abstract class SineWaveGenerator<T> : OscillationGenerator<T>
{
protected override double FOffset { get => Math.Sin(Progress * (Segments * 2.0) * Math.PI); }
public SineWaveGenerator(T min, T max)
: base(min, max) { }
}
public abstract class SquareWaveGenerator<T> : OscillationGenerator<T>
{
protected override double FOffset { get => (Math.Floor(Progress * Segments) % 2 == 0) ? 1 : -1; }
public SquareWaveGenerator(T min, T max)
: base(min, max) { }
}
public sealed class SawtoothNumberGenerator<T> : SawtoothGenerator<T>, INumberGenerator<T> where T : struct, INumber<T>
{
public INumberGenerator<T> Self { get => this; }
public SawtoothNumberGenerator<T> SetShapeFactor(double fShape) { FShape = fShape; return this; }
public SawtoothNumberGenerator<T> SetFadeFactor(double fade) { FFade = fade; return this; }
public SawtoothNumberGenerator<T> SetSegments(int count) { Segments = count; return this; }
public SawtoothNumberGenerator<T> SetAmplitude(double amplitude) { Amplitude = amplitude; return this; }
protected override T Calc()
{
var offs = Amplitude * FOffset * Scale * ((Self.DMax - Self.DMin) / 2.0);
return T.CreateChecked(Math.Clamp(Self.Mean + offs, Self.DMin, Self.DMax));
}
public SawtoothNumberGenerator(T min, T max, int count = 10) : base(min, max)
{
Step = CalcStepByCount(count);
Amplitude = 1.0; // Set default
}
}
public sealed class SineWaveNumberGenerator<T> : SineWaveGenerator<T>, INumberGenerator<T> where T : struct, INumber<T>
{
public INumberGenerator<T> Self { get => this; }
public SineWaveNumberGenerator<T> SetShapeFactor(double fShape) { FShape = fShape; return this; }
public SineWaveNumberGenerator<T> SetFadeFactor(double fade) { FFade = fade; return this; }
public SineWaveNumberGenerator<T> SetSegments(int count) { Segments = count; return this; }
public SineWaveNumberGenerator<T> SetAmplitude(double amplitude) { Amplitude = amplitude; return this; }
protected override T Calc()
{
var offs = Amplitude * FOffset * Scale * ((Self.DMax - Self.DMin) / 2.0);
return T.CreateChecked(Math.Clamp(Self.Mean + offs, Self.DMin, Self.DMax));
}
public SineWaveNumberGenerator(T min, T max, int count = 10) : base(min, max)
{
Step = CalcStepByCount(count);
Amplitude = 1.0; // Set default
}
}
public sealed class SquareWaveNumberGenerator<T> : SquareWaveGenerator<T>, INumberGenerator<T> where T : struct, INumber<T>
{
public INumberGenerator<T> Self { get => this; }
public SquareWaveNumberGenerator<T> SetShapeFactor(double fShape) { FShape = fShape; return this; }
public SquareWaveNumberGenerator<T> SetFadeFactor(double fade) { FFade = fade; return this; }
public SquareWaveNumberGenerator<T> SetSegments(int count) { Segments = count; return this; }
public SquareWaveNumberGenerator<T> SetAmplitude(double amplitude) { Amplitude = amplitude; return this; }
protected override T Calc()
{
var offs = Amplitude * FOffset * Scale * ((Self.DMax - Self.DMin) / 2.0);
return T.CreateChecked(Math.Clamp(Self.Mean + offs, Self.DMin, Self.DMax));
}
public SquareWaveNumberGenerator(T min, T max, int count = 10) : base(min, max)
{
Step = CalcStepByCount(count);
Amplitude = 1.0; // Set default
}
}
public sealed class SawtoothPointGenerator : SawtoothGenerator<Point>, IPointGenerator
{
private readonly double _pAngle;
public IPointGenerator Self { get => this; }
public SawtoothPointGenerator SetShapeFactor(double fShape) { FShape = fShape; return this; }
public SawtoothPointGenerator SetFadeFactor(double fade) { FFade = fade; return this; }
public SawtoothPointGenerator SetSegments(int count) { Segments = count; return this; }
public SawtoothPointGenerator SetAmplitude(double amplitude) { Amplitude = amplitude; return this; }
protected override Point Calc()
{
return IPointGenerator.CalcPoint(Self.LinearX, Self.LinearY, Amplitude * FOffset * Scale, _pAngle);
}
public static SawtoothPointGenerator CreateByCount(Point start, Point end, int count)
{
return new SawtoothPointGenerator(start, end) { Step = CalcStepByCount(count) };
}
public static SawtoothPointGenerator CreateByStepSize(Point start, Point end, double pxPerStep = 5)
{
return new SawtoothPointGenerator(start, end, pxPerStep);
}
public SawtoothPointGenerator(Point start, Point end, double pxPerStep = 5)
: this(start, end)
{
Step = pxPerStep / IPointGenerator.CalcDistance(start, end);
}
private SawtoothPointGenerator(Point start, Point end)
: base(start, end)
{
_pAngle = IPointGenerator.CalcAngle(start, end) + Math.PI / 2.0;
}
}
public sealed class SineWavePointGenerator : SineWaveGenerator<Point>, IPointGenerator
{
private readonly double _pAngle;
public IPointGenerator Self { get => this; }
public SineWavePointGenerator SetShapeFactor(double fShape) { FShape = fShape; return this; }
public SineWavePointGenerator SetFadeFactor(double fade) { FFade = fade; return this; }
public SineWavePointGenerator SetSegments(int count) { Segments = count; return this; }
public SineWavePointGenerator SetAmplitude(double amplitude) { Amplitude = amplitude; return this; }
protected override Point Calc()
{
return IPointGenerator.CalcPoint(Self.LinearX, Self.LinearY, Amplitude * FOffset * Scale, _pAngle);
}
public static SineWavePointGenerator CreateByCount(Point start, Point end, int count)
{
return new SineWavePointGenerator(start, end) { Step = CalcStepByCount(count) };
}
public static SineWavePointGenerator CreateByStepSize(Point start, Point end, double pxPerStep = 5)
{
return new SineWavePointGenerator(start, end, pxPerStep);
}
public SineWavePointGenerator(Point start, Point end, double pxPerStep = 5)
: this(start, end)
{
Step = pxPerStep / IPointGenerator.CalcDistance(start, end);
}
private SineWavePointGenerator(Point start, Point end)
: base(start, end)
{
_pAngle = IPointGenerator.CalcAngle(start, end) + Math.PI / 2.0;
}
}
public sealed class SquareWavePointGenerator : SquareWaveGenerator<Point>, IPointGenerator
{
private readonly double _pAngle;
public IPointGenerator Self { get => this; }
public SquareWavePointGenerator SetShapeFactor(double fShape) { FShape = fShape; return this; }
public SquareWavePointGenerator SetFadeFactor(double fade) { FFade = fade; return this; }
public SquareWavePointGenerator SetSegments(int count) { Segments = count; return this; }
public SquareWavePointGenerator SetAmplitude(double amplitude) { Amplitude = amplitude; return this; }
protected override Point Calc()
{
return IPointGenerator.CalcPoint(Self.LinearX, Self.LinearY, Amplitude * FOffset * Scale, _pAngle);
}
public static SquareWavePointGenerator CreateByCount(Point start, Point end, int count)
{
return new SquareWavePointGenerator(start, end) { Step = CalcStepByCount(count) };
}
public static SquareWavePointGenerator CreateByStepSize(Point start, Point end, double pxPerStep = 5)
{
return new SquareWavePointGenerator(start, end, pxPerStep);
}
public SquareWavePointGenerator(Point start, Point end, double pxPerStep = 5)
: this(start, end)
{
Step = pxPerStep / IPointGenerator.CalcDistance(start, end);
}
private SquareWavePointGenerator(Point start, Point end)
: base(start, end)
{
_pAngle = IPointGenerator.CalcAngle(start, end) + Math.PI / 2.0;
}
}
}

View File

@ -0,0 +1,187 @@
using System.Drawing;
using System.Numerics;
namespace AutoAgent.Domain.Utils
{
public class Perlin2D : BaseRandom
{
byte[] _mTable = new byte[1024];
public Perlin2D(int seed = 0)
: base(seed)
{
Generate(_mTable);
}
private double[] GetPseudoRandomGradientVector(int x, int y)
{
int v = (int)(((x * 1836311903) ^ (y * 2971215073) + 4807526976) & 1023);
v = _mTable[v] & 3;
switch (v)
{
case 0: return new double[] { 1, 0 };
case 1: return new double[] { -1, 0 };
case 2: return new double[] { 0, 1 };
default: return new double[] { 0, -1 };
}
}
static double QunticCurve(double t)
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
static double Lerp(double a, double b, double t)
{
return a + (b - a) * t;
}
static double Dot(double[] a, double[] b)
{
return a[0] * b[0] + a[1] * b[1];
}
public double Noise(double fx, double fy)
{
int left = (int)System.Math.Floor(fx);
int top = (int)System.Math.Floor(fy);
double pointInQuadX = fx - left;
double pointInQuadY = fy - top;
double[] topLeftGradient = GetPseudoRandomGradientVector(left, top);
double[] topRightGradient = GetPseudoRandomGradientVector(left + 1, top);
double[] bottomLeftGradient = GetPseudoRandomGradientVector(left, top + 1);
double[] bottomRightGradient = GetPseudoRandomGradientVector(left + 1, top + 1);
double[] distanceToTopLeft = { pointInQuadX, pointInQuadY };
double[] distanceToTopRight = { pointInQuadX - 1, pointInQuadY };
double[] distanceToBottomLeft = { pointInQuadX, pointInQuadY - 1 };
double[] distanceToBottomRight = { pointInQuadX - 1, pointInQuadY - 1 };
double tx1 = Dot(distanceToTopLeft, topLeftGradient);
double tx2 = Dot(distanceToTopRight, topRightGradient);
double bx1 = Dot(distanceToBottomLeft, bottomLeftGradient);
double bx2 = Dot(distanceToBottomRight, bottomRightGradient);
pointInQuadX = QunticCurve(pointInQuadX);
pointInQuadY = QunticCurve(pointInQuadY);
double tx = Lerp(tx1, tx2, pointInQuadX);
double bx = Lerp(bx1, bx2, pointInQuadX);
double tb = Lerp(tx, bx, pointInQuadY);
return tb;
}
public double Noise(double fx, double fy, int octaves, double persistence = 0.5)
{
double amplitude = 1;
double max = 0;
double result = 0;
while (octaves-- > 0)
{
max += amplitude;
result += Noise(fx, fy) * amplitude;
amplitude *= persistence;
fx *= 2;
fy *= 2;
}
return result / max;
}
}
public abstract class PerlinGenerator<T> : BaseGenerator<T>
{
private Perlin2D _perlin;
private double _amplitude = 100.0;
public double Amplitude { get => _amplitude; protected set => _amplitude = Math.Abs(value); }
public double Persistance { get; protected set; } = 0.5;
public double Frequency { get; protected set; } = 5.0;
public int Octaves { get; protected set; } = 4;
public double Seed { get; private set; }
public override double Step { get; protected set; }
protected double Noise { get => _perlin.Noise(Progress * Frequency, Seed, Octaves, Persistance); }
public PerlinGenerator(T min, T max, double seed)
: base(min, max)
{
Seed = seed;
_perlin = new Perlin2D((int)(Seed * 0x000fffff));
}
}
public sealed class PerlinNumberGenerator<T> : PerlinGenerator<T>, INumberGenerator<T> where T : struct, INumber<T>
{
public INumberGenerator<T> Self { get => this; }
public PerlinNumberGenerator<T> SetShapeFactor(double fShape) { FShape = fShape; return this; }
public PerlinNumberGenerator<T> SetFadeFactor(double fade) { FFade = fade; return this; }
public PerlinNumberGenerator<T> SetOctaves(int octaves) { Octaves = octaves; return this; }
public PerlinNumberGenerator<T> SetPersistence(double peristance) { Persistance = peristance; return this; }
public PerlinNumberGenerator<T> SetFrequency(double frequency) { Frequency = frequency; return this; }
public PerlinNumberGenerator<T> SetAmplitude(double amplitude) { Amplitude = amplitude; return this; }
protected override T Calc()
{
var offs = Noise * Scale * ((Self.DMax - Self.DMin) / 2.0);
return T.CreateChecked(Math.Clamp(Self.Mean + offs, Self.DMin, Self.DMax));
}
private static double GetSeed(T min, T max, double seed)
{
if (Double.IsNormal(seed)) return seed;
return (Double.CreateChecked(min) + Double.CreateChecked(max)) / 1000.0;
}
public PerlinNumberGenerator(T min, T max, int count = 10, double seed = Double.NaN) : base(min, max, GetSeed(min, max, seed))
{
Step = CalcStepByCount(count);
Amplitude = 1.0; // Set default
}
}
public sealed class PerlinPointGenerator : PerlinGenerator<Point>, IPointGenerator
{
private readonly double _pAngle;
public IPointGenerator Self { get => this; }
public PerlinPointGenerator SetShapeFactor(double fShape) { FShape = fShape; return this; }
public PerlinPointGenerator SetFadeFactor(double fade) { FFade = fade; return this; }
public PerlinPointGenerator SetOctaves(int octaves) { Octaves = octaves; return this; }
public PerlinPointGenerator SetPersistence(double peristance) { Persistance = peristance; return this; }
public PerlinPointGenerator SetFrequency(double frequency) { Frequency = frequency; return this; }
public PerlinPointGenerator SetAmplitude(double amplitude) { Amplitude = amplitude; return this; }
protected override Point Calc()
{
return IPointGenerator.CalcPoint(Self.LinearX, Self.LinearY, Noise * Amplitude * Scale, _pAngle);
}
private static double GetSeed(Point start, Point end, double seed)
{
if (Double.IsNormal(seed)) return seed;
return (start.X + end.Y) / 1000.0;
}
public static PerlinPointGenerator CreateByCount(Point start, Point end, int count, double seed = Double.NaN)
{
return new PerlinPointGenerator(start, end, seed)
{
Step = CalcStepByCount(count)
};
}
public static PerlinPointGenerator CreateByStepSize(Point start, Point end, double pxPerStep = 5, double seed = Double.NaN)
{
return new PerlinPointGenerator(start, end, pxPerStep, seed);
}
public PerlinPointGenerator(Point start, Point end, double pxPerStep = 5, double seed = Double.NaN)
: this(start, end, seed)
{
Step = pxPerStep / IPointGenerator.CalcDistance(start, end);
}
private PerlinPointGenerator(Point start, Point end, double seed)
: base(start, end, GetSeed(start, end, seed))
{
_pAngle = IPointGenerator.CalcAngle(start, end) + Math.PI / 2.0;
}
}
}

View File

@ -0,0 +1,16 @@
using System.Numerics;
namespace AutoAgent.Domain.Utils
{
public sealed class RandomNumberGenerator<T> : BaseGenerator<T>, INumberGenerator<T> where T : struct, INumber<T>
{
public override double Step { get; protected set; }
public INumberGenerator<T> Self { get => this; }
protected override T Calc()
{
return NextGenerate(Min, Max);
}
public RandomNumberGenerator(T min, T max) : base(min, max)
{ Step = CalcStepByCount(Int32.MaxValue); }
}
}

View File

@ -0,0 +1,6 @@
namespace AutoAgent.Domain
{
public class WindowScanHandler
{
}
}

8
LICENSE Normal file
View File

@ -0,0 +1,8 @@
MIT License
Copyright (c) <2024-2025> <Gregory Lirent>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

49
Models/MemoryRegion.cs Normal file
View File

@ -0,0 +1,49 @@
using AutoAgent.Domain.Models;
using System.Text.Json.Serialization;
namespace AutoAgent.Models
{
public class MemoryRegion : ConcurrentObject
{
private long _addr = 0;
private ulong _size = 0;
[JsonIgnore]
public long MemoryAddress
{
get => LockedGet(ref _addr);
set => LockedSet(ref _addr, value);
}
public ulong MemorySize
{
get => LockedGet(ref _size);
set => LockedSet(ref _size, value);
}
public string? BaseAddress
{
get => (MemoryAddress > 0) ? $"0x{MemoryAddress:X16}" : null;
}
}
public class MemoryRegionInfo : MemoryRegion
{
private WindowsProcess.MemoryState _state = 0;
private WindowsProcess.MemoryPageProtectionState _protect = 0;
private WindowsProcess.MemoryType _type = 0;
public WindowsProcess.MemoryState MemoryState
{
get => LockedGet(ref _state);
set => LockedSet(ref _state, value);
}
public WindowsProcess.MemoryPageProtectionState MemoryPageProtection
{
get => LockedGet(ref _protect);
set => LockedSet(ref _protect, value);
}
public WindowsProcess.MemoryType MemoryType
{
get => LockedGet(ref _type);
set => LockedSet(ref _type, value);
}
}
}

6
Services/AgentService.cs Normal file
View File

@ -0,0 +1,6 @@
namespace AutoAgent.Services
{
public class AgentService
{
}
}

View File

@ -0,0 +1,6 @@
namespace AutoAgent.Services
{
public class ProcessMonitoringService
{
}
}

11
app.manifest Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="AutomationAgent.app"/>
<trustInfo>
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@ -0,0 +1,45 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RootNamespace>AutoAgent</RootNamespace>
<AssemblyName>AutomationAgent</AssemblyName>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<Version>0.1.0</Version>
<Company>OpenSource</Company>
<Product>Automation Agent</Product>
<Description>A service for automation and detailed monitoring processes and memory regions.</Description>
<Copyright>Copyright © 2024-2025 Gregory Lirent</Copyright>
<NeutralLanguage>en-US</NeutralLanguage>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.6" />
<PackageReference Include="System.Management" Version="8.0.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="Google.Protobuf" Version="3.27.2" />
<PackageReference Include="Grpc.Tools" Version="2.63.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Protobuf Include="Domain\Models\ipc.proto" GrpcServices="None" ProtoRoot="." />
</ItemGroup>
<ItemGroup>
<Folder Include="Configuration\" />
<Folder Include="Controllers\Debug\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36221.1 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "win32-automation-agent", "win32-automation-agent.csproj", "{D1205A01-F94B-8495-3264-C2568D920EDB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D1205A01-F94B-8495-3264-C2568D920EDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1205A01-F94B-8495-3264-C2568D920EDB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1205A01-F94B-8495-3264-C2568D920EDB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1205A01-F94B-8495-3264-C2568D920EDB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {64BE19AF-903D-4F11-9E1B-6AEAC14B012B}
EndGlobalSection
EndGlobal