Bug fixes: - InputSimulator: Pass correct button state (MK_LBUTTON/MK_RBUTTON) in wParam for button-down messages instead of 0. - PeHeaderParser: ParseOptionalHeader now reads only the optional header, not section headers (fixes double-parse waste). - EntryPoint: Removed useless isPe32Plus branch (AddressOfEntryPoint is at offset 16 in both PE32 and PE32+). - RemoteWindow: Handle null foreground window case in Activate to avoid calling GetWindowThreadProcessId with HWND 0. - RemotePointer: Remove dead null-conditional operators (encoding ??) since encoding is non-nullable. Constants added: - SystemMethods: MkLButton (0x0001) and MkRButton (0x0002) for mouse button state flags. Tests: 199 passing, 4 integration/interactive skipped.
75 lines
2.2 KiB
C#
75 lines
2.2 KiB
C#
using System.Runtime.InteropServices;
|
|
using WhiteMagic.Native;
|
|
|
|
namespace WhiteMagic.Input;
|
|
|
|
/// <summary>
|
|
/// Mouse buttons supported by <see cref="InputSimulator.SendMouseClick"/>.
|
|
/// </summary>
|
|
public enum MouseButton
|
|
{
|
|
/// <summary>The left mouse button.</summary>
|
|
Left,
|
|
|
|
/// <summary>The right mouse button.</summary>
|
|
Right,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Simulates keyboard and mouse input directed at a target window via window messages.
|
|
/// </summary>
|
|
public sealed class InputSimulator
|
|
{
|
|
/// <summary>
|
|
/// Sends a sequence of character messages to <paramref name="hWnd"/>.
|
|
/// </summary>
|
|
/// <returns><see langword="true"/> if every character was posted successfully.</returns>
|
|
public bool SendKeys(IntPtr hWnd, string text)
|
|
{
|
|
if (text is null)
|
|
throw new ArgumentNullException(nameof(text));
|
|
|
|
if (hWnd == IntPtr.Zero)
|
|
return false;
|
|
|
|
foreach (char c in text)
|
|
{
|
|
if (!NativeMethods.PostMessageW(hWnd, NativeMethods.WmChar, (nuint)c, 0))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends a mouse click at client-area coordinates <paramref name="x"/>,
|
|
/// <paramref name="y"/> to <paramref name="hWnd"/>.
|
|
/// </summary>
|
|
/// <returns><see langword="true"/> if the click was posted successfully.</returns>
|
|
public bool SendMouseClick(IntPtr hWnd, int x, int y, MouseButton button)
|
|
{
|
|
if (hWnd == IntPtr.Zero)
|
|
return false;
|
|
|
|
nint lParam = MakeLong(x, y);
|
|
|
|
(uint down, uint downWParam) = button switch
|
|
{
|
|
MouseButton.Left => (NativeMethods.WmLButtonDown, NativeMethods.MkLButton),
|
|
MouseButton.Right => (NativeMethods.WmRButtonDown, NativeMethods.MkRButton),
|
|
_ => throw new ArgumentOutOfRangeException(nameof(button)),
|
|
};
|
|
|
|
if (!NativeMethods.PostMessageW(hWnd, down, downWParam, lParam))
|
|
return false;
|
|
|
|
uint up = button == MouseButton.Left ? NativeMethods.WmLButtonUp : NativeMethods.WmRButtonUp;
|
|
return NativeMethods.PostMessageW(hWnd, up, 0, lParam);
|
|
}
|
|
|
|
private static nint MakeLong(int low, int high)
|
|
{
|
|
return (nint)((uint)low | ((uint)high << 16));
|
|
}
|
|
}
|