poe2-bot/src/Automata.Game/ClipboardHelper.cs
2026-02-28 15:13:31 -05:00

124 lines
3.8 KiB
C#

using System.Runtime.InteropServices;
using System.Text;
namespace Automata.Game;
/// <summary>
/// Win32 clipboard access without WinForms dependency.
/// </summary>
public static class ClipboardHelper
{
private const int MaxRetries = 5;
private const int RetryDelayMs = 30;
public static string Read()
{
for (var attempt = 0; attempt < MaxRetries; attempt++)
{
if (ClipboardNative.OpenClipboard(IntPtr.Zero))
{
try
{
var handle = ClipboardNative.GetClipboardData(ClipboardNative.CF_UNICODETEXT);
if (handle == IntPtr.Zero) return "";
var ptr = ClipboardNative.GlobalLock(handle);
if (ptr == IntPtr.Zero) return "";
try
{
return Marshal.PtrToStringUni(ptr) ?? "";
}
finally
{
ClipboardNative.GlobalUnlock(handle);
}
}
finally
{
ClipboardNative.CloseClipboard();
}
}
Thread.Sleep(RetryDelayMs);
}
return "";
}
public static void Write(string text)
{
for (var attempt = 0; attempt < MaxRetries; attempt++)
{
if (ClipboardNative.OpenClipboard(IntPtr.Zero))
{
try
{
ClipboardNative.EmptyClipboard();
var bytes = Encoding.Unicode.GetBytes(text + "\0");
var hGlobal = ClipboardNative.GlobalAlloc(ClipboardNative.GMEM_MOVEABLE, (UIntPtr)bytes.Length);
if (hGlobal == IntPtr.Zero) return;
var ptr = ClipboardNative.GlobalLock(hGlobal);
if (ptr == IntPtr.Zero)
{
ClipboardNative.GlobalFree(hGlobal);
return;
}
try
{
Marshal.Copy(bytes, 0, ptr, bytes.Length);
}
finally
{
ClipboardNative.GlobalUnlock(hGlobal);
}
ClipboardNative.SetClipboardData(ClipboardNative.CF_UNICODETEXT, hGlobal);
return;
}
finally
{
ClipboardNative.CloseClipboard();
}
}
Thread.Sleep(RetryDelayMs);
}
}
}
internal static partial class ClipboardNative
{
public const uint CF_UNICODETEXT = 13;
public const uint GMEM_MOVEABLE = 0x0002;
[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool OpenClipboard(IntPtr hWndNewOwner);
[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool CloseClipboard();
[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool EmptyClipboard();
[LibraryImport("user32.dll")]
public static partial IntPtr GetClipboardData(uint uFormat);
[LibraryImport("user32.dll")]
public static partial IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
[LibraryImport("kernel32.dll")]
public static partial IntPtr GlobalAlloc(uint uFlags, UIntPtr dwBytes);
[LibraryImport("kernel32.dll")]
public static partial IntPtr GlobalLock(IntPtr hMem);
[LibraryImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool GlobalUnlock(IntPtr hMem);
[LibraryImport("kernel32.dll")]
public static partial IntPtr GlobalFree(IntPtr hMem);
}