using System; using System.Collections.Generic; using Blacklight.Core.Keyboard; using Clave; using UnitTestSharp; namespace Blacklight.Core.UnitTests.Keyboard { public class GamepadKeyRouterTests : TestFixture { public class Recorder : IKeyboardConsumer { public readonly List Log = new List(); public KeyboardSnapshot LastDown; public KeyboardSnapshot LastUp; public bool KeyDown(KeyboardSnapshot keyboard) { LastDown = keyboard; Log.Add("Down:" + Names(keyboard.Physical.Pressed)); return true; } public bool KeyUp(KeyboardSnapshot keyboard) { LastUp = keyboard; Log.Add("Up:" + Names(keyboard.Physical.Released)); return true; } public void SyncKeys(KeyboardSnapshot keyboard) { Log.Add("Sync:" + Names(keyboard.Physical.Held)); } public void CancelKeys() { } } public class Rig { public readonly KeyTracker Tracker = new KeyTracker(); public readonly Recorder Consumer = new Recorder(); public readonly GamepadKeyRouter Router; public Rig() { Router = new GamepadKeyRouter(new GamepadSeat(Tracker, Consumer)); } } public static string Names(KeyState keys) { string returnMe = ""; for (int key = (int)KeyCode.GamepadA; key <= (int)KeyCode.GamepadDPadRight; key++) { if (keys.IsKeySet((KeyCode)key)) { returnMe += (returnMe.Length == 0 ? "" : "+") + (KeyCode)key; } } return returnMe; } public static KeyState Buttons(params KeyCode[] buttons) { return new KeyState(buttons); } public static KeyState[] Pads(KeyState pad0 = default, KeyState pad1 = default, KeyState pad2 = default, KeyState pad3 = default) { return new[] { pad0, pad1, pad2, pad3 }; } public static Rig PrimedRig() { var returnMe = new Rig(); returnMe.Router.Update(Pads()); return returnMe; } public class CtorTests : TestFixture { public void HasOneSeat() { CheckEqual(1, new Rig().Router.SeatCount); } public void PutsEveryPadOnTheFirstSeat() { var router = new Rig().Router; for (int pad = 0; pad < GamepadKeyRouter.PadCount; pad++) { CheckEqual(0, router.SeatOfPad(pad)); } } } public class AddSeatTests : TestFixture { public void ReturnsTheNumberOfTheNewSeat() { var rig = new Rig(); CheckEqual(1, rig.Router.AddSeat(new GamepadSeat(new KeyTracker(), new Recorder()))); CheckEqual(2, rig.Router.AddSeat(new GamepadSeat(new KeyTracker(), new Recorder()))); CheckEqual(3, rig.Router.SeatCount); } } public class SeatOfPadTests : TestFixture { public void BadPad_Throws() { var router = new Rig().Router; CheckThrow(typeof(ArgumentOutOfRangeException)); router.SeatOfPad(4); } } public class AssignPadTests : TestFixture { public void MovesThePad() { var rig = new Rig(); rig.Router.AddSeat(new GamepadSeat(new KeyTracker(), new Recorder())); rig.Router.AssignPad(pad: 2, seat: 1); CheckEqual(1, rig.Router.SeatOfPad(2)); CheckEqual(0, rig.Router.SeatOfPad(1)); } public void BadPad_Throws() { var router = new Rig().Router; CheckThrow(typeof(ArgumentOutOfRangeException)); router.AssignPad(pad: -1, seat: 0); } public void MissingSeat_Throws() { var router = new Rig().Router; CheckThrow(typeof(ArgumentOutOfRangeException)); router.AssignPad(pad: 0, seat: 1); } public void NoSeat_ReleasesWhatThePadHeldAtTheNextUpdate() { var rig = PrimedRig(); rig.Router.Update(Pads(Buttons(KeyCode.GamepadA))); rig.Consumer.Log.Clear(); rig.Router.AssignPad(pad: 0, seat: GamepadKeyRouter.NoSeat); rig.Router.Update(Pads(Buttons(KeyCode.GamepadA))); CheckEqual(new[] { "Up:GamepadA" }, rig.Consumer.Log.ToArray()); } public void HeldButtons_CountAsAlreadyDownForTheNewSeat() { var rig = PrimedRig(); var other = new Recorder(); var otherTracker = new KeyTracker(); int seat = rig.Router.AddSeat(new GamepadSeat(otherTracker, other)); rig.Router.AssignPad(pad: 1, seat: GamepadKeyRouter.NoSeat); rig.Router.Update(Pads()); rig.Router.Update(Pads(default, Buttons(KeyCode.GamepadA))); rig.Router.AssignPad(pad: 1, seat: seat); rig.Router.Update(Pads(default, Buttons(KeyCode.GamepadA))); CheckEqual(new[] { "Sync:GamepadA" }, other.Log.ToArray()); CheckEqual(Buttons(KeyCode.GamepadA), otherTracker.Held); } public void HeldButtons_AreSyncedByTheFirstPollWhenTheSeatHasNeverBeenPolled() { var rig = PrimedRig(); var other = new Recorder(); rig.Router.Update(Pads(default, Buttons(KeyCode.GamepadA))); int seat = rig.Router.AddSeat(new GamepadSeat(new KeyTracker(), other)); rig.Router.AssignPad(pad: 1, seat: seat); CheckEqual(0, other.Log.Count); rig.Router.Update(Pads(default, Buttons(KeyCode.GamepadA))); CheckEqual(new[] { "Sync:GamepadA" }, other.Log.ToArray()); } public void HeldButtons_AreReleasedOnTheSeatTheyLeft() { var rig = PrimedRig(); int seat = rig.Router.AddSeat(new GamepadSeat(new KeyTracker(), new Recorder())); rig.Router.Update(Pads(Buttons(KeyCode.GamepadA))); rig.Consumer.Log.Clear(); rig.Router.AssignPad(pad: 0, seat: seat); rig.Router.Update(Pads(Buttons(KeyCode.GamepadA))); CheckEqual(new[] { "Up:GamepadA" }, rig.Consumer.Log.ToArray()); } } public class UpdateTests : TestFixture { public void WrongLength_Throws() { var router = new Rig().Router; CheckThrow(typeof(ArgumentException)); router.Update(new KeyState[3]); } public void FirstPollWithNothingHeld_SendsNothing() { var rig = new Rig(); rig.Router.Update(Pads()); CheckEqual(0, rig.Consumer.Log.Count); } public void FirstPollWithAButtonHeld_SyncsItInsteadOfPressingIt() { var rig = new Rig(); rig.Router.Update(Pads(Buttons(KeyCode.GamepadA))); CheckEqual(new[] { "Sync:GamepadA" }, rig.Consumer.Log.ToArray()); CheckEqual(Buttons(KeyCode.GamepadA), rig.Tracker.Held); } public void ButtonGoingDown_IsOneKeyDownWithTheButtonPressedAndHeld() { var rig = PrimedRig(); rig.Router.Update(Pads(Buttons(KeyCode.GamepadA))); CheckEqual(new[] { "Down:GamepadA" }, rig.Consumer.Log.ToArray()); CheckEqual(Buttons(KeyCode.GamepadA), rig.Consumer.LastDown.Physical.Held); CheckEqual(Buttons(KeyCode.GamepadA), rig.Consumer.LastDown.Layout.Pressed); } public void ButtonStayingDown_SendsNothingMore() { var rig = PrimedRig(); rig.Router.Update(Pads(Buttons(KeyCode.GamepadA))); rig.Router.Update(Pads(Buttons(KeyCode.GamepadA))); CheckEqual(1, rig.Consumer.Log.Count); } public void ButtonComingUp_IsOneKeyUpWithTheButtonReleased() { var rig = PrimedRig(); rig.Router.Update(Pads(Buttons(KeyCode.GamepadB))); rig.Router.Update(Pads()); CheckEqual(new[] { "Down:GamepadB", "Up:GamepadB" }, rig.Consumer.Log.ToArray()); CheckEqual(default(KeyState), rig.Consumer.LastUp.Physical.Held); } public void SeveralButtonsAtOnce_ArriveOneEachInButtonOrder() { var rig = PrimedRig(); rig.Router.Update(Pads(Buttons(KeyCode.GamepadY, KeyCode.GamepadA))); CheckEqual(new[] { "Down:GamepadA", "Down:GamepadY" }, rig.Consumer.Log.ToArray()); } public void ReleasesComeBeforePresses() { var rig = PrimedRig(); rig.Router.Update(Pads(Buttons(KeyCode.GamepadB))); rig.Consumer.Log.Clear(); rig.Router.Update(Pads(Buttons(KeyCode.GamepadA))); CheckEqual(new[] { "Up:GamepadB", "Down:GamepadA" }, rig.Consumer.Log.ToArray()); } public void PadsOnOneSeat_ActAsOne() { var rig = PrimedRig(); rig.Router.Update(Pads(Buttons(KeyCode.GamepadA), Buttons(KeyCode.GamepadA))); rig.Router.Update(Pads(default, Buttons(KeyCode.GamepadA))); rig.Router.Update(Pads()); CheckEqual(new[] { "Down:GamepadA", "Up:GamepadA" }, rig.Consumer.Log.ToArray()); } public void NonGamepadKeys_AreIgnored() { var rig = PrimedRig(); rig.Router.Update(Pads(Buttons(KeyCode.A, KeyCode.MouseLeft))); CheckEqual(0, rig.Consumer.Log.Count); } public void PadOnAnotherSeat_ReachesOnlyThatSeat() { var rig = PrimedRig(); var other = new Recorder(); int seat = rig.Router.AddSeat(new GamepadSeat(new KeyTracker(), other)); rig.Router.AssignPad(pad: 1, seat: seat); rig.Router.Update(Pads()); rig.Router.Update(Pads(default, Buttons(KeyCode.GamepadX))); CheckEqual(new[] { "Down:GamepadX" }, other.Log.ToArray()); CheckEqual(0, rig.Consumer.Log.Count); } public void UnassignedPad_RaisesTheEventOnceAndSendsNoKeys() { var rig = PrimedRig(); var raised = new List(); rig.Router.UnassignedPadPressed += raised.Add; rig.Router.AssignPad(pad: 2, seat: GamepadKeyRouter.NoSeat); rig.Router.Update(Pads(default, default, Buttons(KeyCode.GamepadStart))); rig.Router.Update(Pads(default, default, Buttons(KeyCode.GamepadStart))); CheckEqual(new[] { 2 }, raised.ToArray()); CheckEqual(0, rig.Consumer.Log.Count); } public void AssignedPad_RaisesNoEvent() { var rig = PrimedRig(); int raised = 0; rig.Router.UnassignedPadPressed += pad => raised++; rig.Router.Update(Pads(Buttons(KeyCode.GamepadStart))); CheckEqual(0, raised); } } public class ResetTests : TestFixture { public void NextPollSyncsHeldButtonsInsteadOfPressingThem() { var rig = PrimedRig(); rig.Router.Update(Pads(Buttons(KeyCode.GamepadA))); rig.Tracker.Reset(); rig.Consumer.Log.Clear(); rig.Router.Reset(); rig.Router.Update(Pads(Buttons(KeyCode.GamepadA))); CheckEqual(new[] { "Sync:GamepadA" }, rig.Consumer.Log.ToArray()); } public void NextPollWithNothingHeld_SendsNothing() { var rig = PrimedRig(); rig.Router.Update(Pads(Buttons(KeyCode.GamepadA))); rig.Tracker.Reset(); rig.Consumer.Log.Clear(); rig.Router.Reset(); rig.Router.Update(Pads()); CheckEqual(0, rig.Consumer.Log.Count); } public void EverySeatSyncsAgain() { var rig = PrimedRig(); var other = new Recorder(); int seat = rig.Router.AddSeat(new GamepadSeat(new KeyTracker(), other)); rig.Router.AssignPad(pad: 3, seat: seat); rig.Router.Update(Pads()); rig.Router.Reset(); rig.Router.Update(Pads(default, default, default, Buttons(KeyCode.GamepadB))); CheckEqual(new[] { "Sync:GamepadB" }, other.Log.ToArray()); } } } }