refactor(input): extract the gameplay frame

This commit is contained in:
Erik 2026-07-22 01:38:40 +02:00
parent 0bc9fda9de
commit c557038353
24 changed files with 2433 additions and 559 deletions

View file

@ -11,18 +11,15 @@ namespace AcDream.App.Input;
/// <see cref="InputDispatcher"/>.
///
/// <para>
/// We don't link Hexa.NET.ImGui or ImGuiNET directly here — the
/// constructor takes two delegates so the App.Rendering layer can
/// proxy <c>ImGui.GetIO().WantCaptureMouse</c> via whichever ImGui
/// package is currently active without leaking the type onto the
/// abstraction interface.
/// Production receives a typed capture source, keeping retained-UI and
/// developer-UI ownership outside the Silk adapter. The public delegate
/// overload remains as a compatibility seam for standalone consumers.
/// </para>
/// </summary>
public sealed class SilkMouseSource : IMouseSource
{
private readonly IMouse _mouse;
private readonly Func<bool> _wantCaptureMouse;
private readonly Func<bool> _wantCaptureKeyboard;
private readonly IInputCaptureSource _capture;
private float _lastX;
private float _lastY;
private bool _haveLastPos;
@ -32,10 +29,21 @@ public sealed class SilkMouseSource : IMouseSource
public event Action<float, float>? MouseMove;
public event Action<float>? Scroll;
/// <summary>Caller-supplied probe for the current modifier mask. Reused
/// from the keyboard source so mouse events carry consistent modifier
/// state.</summary>
public Func<ModifierMask> ModifierProbe { get; set; } = () => ModifierMask.None;
/// <summary>The keyboard source that owns the current modifier mask, so
/// mouse events and keyboard events resolve identical chords.</summary>
public IKeyboardSource? ModifierSource { get; set; }
internal SilkMouseSource(
IMouse mouse,
IInputCaptureSource capture,
IKeyboardSource modifierSource)
{
_mouse = mouse ?? throw new ArgumentNullException(nameof(mouse));
_capture = capture ?? throw new ArgumentNullException(nameof(capture));
ModifierSource = modifierSource
?? throw new ArgumentNullException(nameof(modifierSource));
Subscribe();
}
public SilkMouseSource(
IMouse mouse,
@ -43,11 +51,16 @@ public sealed class SilkMouseSource : IMouseSource
Func<bool> wantCaptureKeyboard)
{
_mouse = mouse ?? throw new ArgumentNullException(nameof(mouse));
_wantCaptureMouse = wantCaptureMouse ?? throw new ArgumentNullException(nameof(wantCaptureMouse));
_wantCaptureKeyboard = wantCaptureKeyboard ?? throw new ArgumentNullException(nameof(wantCaptureKeyboard));
_capture = new DelegateInputCaptureSource(
wantCaptureMouse,
wantCaptureKeyboard);
Subscribe();
}
_mouse.MouseDown += (_, btn) => MouseDown?.Invoke(btn, ModifierProbe());
_mouse.MouseUp += (_, btn) => MouseUp?.Invoke(btn, ModifierProbe());
private void Subscribe()
{
_mouse.MouseDown += (_, btn) => MouseDown?.Invoke(btn, ReadModifiers());
_mouse.MouseUp += (_, btn) => MouseUp?.Invoke(btn, ReadModifiers());
_mouse.MouseMove += (_, pos) =>
{
float dx, dy;
@ -69,8 +82,11 @@ public sealed class SilkMouseSource : IMouseSource
_mouse.Scroll += (_, scroll) => Scroll?.Invoke(scroll.Y);
}
private ModifierMask ReadModifiers() =>
ModifierSource?.CurrentModifiers ?? ModifierMask.None;
public bool IsHeld(MouseButton button) => _mouse.IsButtonPressed(button);
public bool WantCaptureMouse => _wantCaptureMouse();
public bool WantCaptureKeyboard => _wantCaptureKeyboard();
public bool WantCaptureMouse => _capture.WantCaptureMouse;
public bool WantCaptureKeyboard => _capture.WantCaptureKeyboard;
}