using AcDream.App.Input; using AcDream.UI.Abstractions.Input; using Silk.NET.Input; namespace AcDream.App.Tests.Input; public sealed class DispatcherMovementInputSourceTests { [Fact] public void UnboundSourceCapturesNeutralInput() { var source = new DispatcherMovementInputSource(); Assert.Equal(default, source.Capture()); } [Fact] public void CapturesDispatcherHeldStateAndRetailWalkModifier() { var (dispatcher, _, _) = CreateDispatcher(); var source = new DispatcherMovementInputSource(); source.Bind(dispatcher); Assert.True(dispatcher.TrySetAutomationActionHeld( InputAction.MovementForward, held: true)); Assert.True(dispatcher.TrySetAutomationActionHeld( InputAction.MovementWalkMode, held: true)); MovementInput captured = source.Capture(); Assert.True(captured.Forward); Assert.False(captured.Run); } [Fact] public void RetainedKeyboardCaptureSilencesHeldKeysButDoesNotCancelAutorun() { var (dispatcher, _, mouse) = CreateDispatcher(); var source = new DispatcherMovementInputSource(); source.Bind(dispatcher); dispatcher.TrySetAutomationActionHeld(InputAction.MovementForward, held: true); Assert.True(source.HandlePressedAction(InputAction.MovementRunLock)); mouse.WantCaptureKeyboard = true; MovementInput captured = source.Capture(); Assert.True(captured.Forward); Assert.True(source.AutoRunActive); source.HandlePressedAction(InputAction.MovementRunLock); captured = source.Capture(); Assert.False(captured.Forward); } [Fact] public void DevToolsKeyboardCapturePausesAutorunWithoutClearingItsLatch() { var capture = new FakeCapture(); var (dispatcher, _, _) = CreateDispatcher(); var source = new DispatcherMovementInputSource(capture); source.Bind(dispatcher); source.HandlePressedAction(InputAction.MovementRunLock); capture.DevToolsWantCaptureKeyboard = true; Assert.Equal(default, source.Capture()); Assert.True(source.AutoRunActive); capture.DevToolsWantCaptureKeyboard = false; Assert.True(source.Capture().Forward); } [Theory] [InlineData(InputAction.MovementBackup)] [InlineData(InputAction.MovementStop)] [InlineData(InputAction.MovementStrafeLeft)] [InlineData(InputAction.MovementStrafeRight)] public void RetailCancelActionsClearAutorun(InputAction action) { var source = new DispatcherMovementInputSource(); source.HandlePressedAction(InputAction.MovementRunLock); Assert.False(source.HandlePressedAction(action)); Assert.False(source.AutoRunActive); } [Fact] public void ForwardDoesNotCancelAutorunAndResetDoes() { var source = new DispatcherMovementInputSource(); source.HandlePressedAction(InputAction.MovementRunLock); Assert.False(source.HandlePressedAction(InputAction.MovementForward)); Assert.True(source.AutoRunActive); source.ResetSession(); Assert.False(source.AutoRunActive); } [Fact] public void BindingIsIdempotentOnlyForTheSameDispatcher() { var source = new DispatcherMovementInputSource(); var (first, _, _) = CreateDispatcher(); var (second, _, _) = CreateDispatcher(); source.Bind(first); source.Bind(first); Assert.Throws(() => source.Bind(second)); } private static (InputDispatcher Dispatcher, FakeKeyboard Keyboard, FakeMouse Mouse) CreateDispatcher() { var keyboard = new FakeKeyboard(); var mouse = new FakeMouse(); return (new InputDispatcher(keyboard, mouse, new KeyBindings()), keyboard, mouse); } private sealed class FakeKeyboard : IKeyboardSource { #pragma warning disable CS0067 public event Action? KeyDown; public event Action? KeyUp; #pragma warning restore CS0067 public bool IsHeld(Key key) => false; public ModifierMask CurrentModifiers => ModifierMask.None; } private sealed class FakeMouse : IMouseSource { #pragma warning disable CS0067 public event Action? MouseDown; public event Action? MouseUp; public event Action? MouseMove; public event Action? Scroll; #pragma warning restore CS0067 public bool WantCaptureKeyboard { get; set; } public bool WantCaptureMouse { get; set; } public bool IsHeld(MouseButton button) => false; } private sealed class FakeCapture : IInputCaptureSource { public bool WantCaptureMouse { get; set; } public bool WantCaptureKeyboard { get; set; } public bool DevToolsWantCaptureKeyboard { get; set; } } }