using System; using AcDream.UI.Abstractions.Input; using Silk.NET.Input; namespace AcDream.App.Input; /// /// Bridges a Silk.NET + the active ImGui IO /// (for / ) /// to the test-fakeable used by /// . /// /// /// We don't link Hexa.NET.ImGui or ImGuiNET directly here — the /// constructor takes two delegates so the App.Rendering layer can /// proxy ImGui.GetIO().WantCaptureMouse via whichever ImGui /// package is currently active without leaking the type onto the /// abstraction interface. /// /// public sealed class SilkMouseSource : IMouseSource { private readonly IMouse _mouse; private readonly Func _wantCaptureMouse; private readonly Func _wantCaptureKeyboard; private float _lastX; private float _lastY; private bool _haveLastPos; public event Action? MouseDown; public event Action? MouseUp; public event Action? MouseMove; public event Action? Scroll; /// Caller-supplied probe for the current modifier mask. Reused /// from the keyboard source so mouse events carry consistent modifier /// state. public Func ModifierProbe { get; set; } = () => ModifierMask.None; public SilkMouseSource( IMouse mouse, Func wantCaptureMouse, Func wantCaptureKeyboard) { _mouse = mouse ?? throw new ArgumentNullException(nameof(mouse)); _wantCaptureMouse = wantCaptureMouse ?? throw new ArgumentNullException(nameof(wantCaptureMouse)); _wantCaptureKeyboard = wantCaptureKeyboard ?? throw new ArgumentNullException(nameof(wantCaptureKeyboard)); _mouse.MouseDown += (_, btn) => MouseDown?.Invoke(btn, ModifierProbe()); _mouse.MouseUp += (_, btn) => MouseUp?.Invoke(btn, ModifierProbe()); _mouse.MouseMove += (_, pos) => { float dx, dy; if (_haveLastPos) { dx = pos.X - _lastX; dy = pos.Y - _lastY; } else { dx = 0f; dy = 0f; _haveLastPos = true; } _lastX = pos.X; _lastY = pos.Y; MouseMove?.Invoke(dx, dy); }; _mouse.Scroll += (_, scroll) => Scroll?.Invoke(scroll.Y); } public bool IsHeld(MouseButton button) => _mouse.IsButtonPressed(button); public bool WantCaptureMouse => _wantCaptureMouse(); public bool WantCaptureKeyboard => _wantCaptureKeyboard(); }