diff --git a/CHANGELOG.md b/CHANGELOG.md index f505a30..46ef280 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ Jump to version: ### MLEM Additions - Added a simple outline formatting code +- Added the ability to add inverse modifiers to a Keybind +- Added GenericInput collections AllKeys, AllMouseButtons, AllButtons and AllInputs Fixes - Fixed control characters being included in TextInput diff --git a/MLEM/Input/GenericInput.cs b/MLEM/Input/GenericInput.cs index f40e781..2451946 100644 --- a/MLEM/Input/GenericInput.cs +++ b/MLEM/Input/GenericInput.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Runtime.Serialization; using Microsoft.Xna.Framework.Input; @@ -12,6 +13,24 @@ namespace MLEM.Input { [DataContract] public readonly struct GenericInput : IEquatable { + /// + /// All values created from all values of the enum. + /// + public static readonly GenericInput[] AllKeys = InputHandler.AllKeys.Select(k => (GenericInput) k).ToArray(); + /// + /// All values created from all values of the enum. + /// + public static readonly GenericInput[] AllMouseButtons = MouseExtensions.MouseButtons.Select(k => (GenericInput) k).ToArray(); + /// + /// All values created from all values of the enum. + /// + public static readonly GenericInput[] AllButtons = InputHandler.AllButtons.Select(k => (GenericInput) k).ToArray(); + /// + /// All values created from all values of the , and enums. + /// This collection represents all possible valid, non-default values. + /// + public static readonly GenericInput[] AllInputs = GenericInput.AllKeys.Concat(GenericInput.AllMouseButtons).Concat(GenericInput.AllButtons).ToArray(); + /// /// The of this generic input's current . /// diff --git a/MLEM/Input/Keybind.cs b/MLEM/Input/Keybind.cs index 7ee8ef6..07a489b 100644 --- a/MLEM/Input/Keybind.cs +++ b/MLEM/Input/Keybind.cs @@ -18,6 +18,7 @@ namespace MLEM.Input { public class Keybind : IComparable, IComparable { private static readonly Combination[] EmptyCombinations = new Combination[0]; + private static readonly GenericInput[] EmptyInputs = new GenericInput[0]; [DataMember] private Combination[] combinations = Keybind.EmptyCombinations; @@ -48,7 +49,16 @@ namespace MLEM.Input { /// The modifier keys that have to be held down. /// This keybind, for chaining public Keybind Add(GenericInput key, params GenericInput[] modifiers) { - this.combinations = this.combinations.Append(new Combination(key, modifiers)).ToArray(); + return this.Add(new Combination(key, modifiers)); + } + + /// + /// Adds the given to this keybind that can optionally be pressed for the keybind to trigger. + /// + /// The combination to add. + /// This keybind, for chaining + public Keybind Add(Combination combination) { + this.combinations = this.combinations.Append(combination).ToArray(); return this; } @@ -67,7 +77,17 @@ namespace MLEM.Input { /// The modifier keys that have to be held down. /// This keybind, for chaining. public Keybind Insert(int index, GenericInput key, params GenericInput[] modifiers) { - this.combinations = this.combinations.Take(index).Append(new Combination(key, modifiers)).Concat(this.combinations.Skip(index)).ToArray(); + return this.Insert(index, new Combination(key, modifiers)); + } + + /// + /// Inserts the given into the given of this keybind's combinations that can optionally be pressed for the keybind to trigger. + /// + /// The index to insert this combination into. + /// The combination to insert. + /// This keybind, for chaining. + public Keybind Insert(int index, Combination combination) { + this.combinations = this.combinations.Take(index).Append(combination).Concat(this.combinations.Skip(index)).ToArray(); return this; } @@ -326,12 +346,18 @@ namespace MLEM.Input { public class Combination : IComparable, IComparable { /// - /// The inputs that have to be held down for this combination to be valid. - /// If this collection is empty, there are no required modifier keys. + /// The inputs that have to be held down for this combination to be valid, which is queried in and . + /// If this collection is empty, there are no required modifiers. /// [DataMember] public readonly GenericInput[] Modifiers; /// + /// The inputs that have to be up for this combination to be valid, which is queried in and . + /// If this collection is empty, there are no required inverse modifiers. + /// + [DataMember] + public readonly GenericInput[] InverseModifiers; + /// /// The input that has to be down (or pressed) for this combination to be considered down (or pressed). /// Note that needs to be empty, or all of its values need to be down, as well. /// @@ -342,11 +368,26 @@ namespace MLEM.Input { /// Creates a new combination with the given settings. /// To add a combination to a , use instead. /// - /// The key - /// The modifiers - public Combination(GenericInput key, params GenericInput[] modifiers) { - this.Modifiers = modifiers; + /// The key. + /// The modifiers. + public Combination(GenericInput key, params GenericInput[] modifiers) : this(key, modifiers, null) {} + + /// + /// Creates a new combination with the given settings. + /// To add a combination to a , use instead. + /// Note that inputs are automatically removed from if they are also present in , or if they are the main . + /// + /// The key. + /// The modifiers, or to use no modifiers. + /// The inverse modifiers, or to use no modifiers. + public Combination(GenericInput key, GenericInput[] modifiers, GenericInput[] inverseModifiers) { this.Key = key; + this.Modifiers = modifiers ?? Keybind.EmptyInputs; + this.InverseModifiers = inverseModifiers ?? Keybind.EmptyInputs; + + // make sure that inverse modifiers don't contain any modifiers or the key + if (this.InverseModifiers.Length > 0) + this.InverseModifiers = this.InverseModifiers.Where(k => k != this.Key).Except(this.Modifiers).ToArray(); } /// @@ -406,7 +447,7 @@ namespace MLEM.Input { } /// - /// Returns whether all of this combination's modifier keys are currently down. + /// Returns whether all of this combination's are currently down and are currently up. /// /// The input handler to query the keys with /// The index of the gamepad to query, or -1 to query all gamepads @@ -416,11 +457,15 @@ namespace MLEM.Input { if (!handler.IsDown(modifier, gamepadIndex)) return false; } + foreach (var invModifier in this.InverseModifiers) { + if (handler.IsDown(invModifier, gamepadIndex)) + return false; + } return true; } /// - /// Returns whether all of this combination's modifier keys were down in the last update call. + /// Returns whether all of this combination's were down and were up in the last update call. /// /// The input handler to query the keys with /// The index of the gamepad to query, or -1 to query all gamepads @@ -430,6 +475,10 @@ namespace MLEM.Input { if (!handler.WasDown(modifier, gamepadIndex)) return false; } + foreach (var invModifier in this.InverseModifiers) { + if (handler.WasDown(invModifier, gamepadIndex)) + return false; + } return true; } diff --git a/Sandbox/GameImpl.cs b/Sandbox/GameImpl.cs index c3d254f..0c1f820 100644 --- a/Sandbox/GameImpl.cs +++ b/Sandbox/GameImpl.cs @@ -14,6 +14,7 @@ using MLEM.Extensions; using MLEM.Formatting; using MLEM.Formatting.Codes; using MLEM.Graphics; +using MLEM.Input; using MLEM.Misc; using MLEM.Startup; using MLEM.Textures; @@ -383,6 +384,11 @@ public class GameImpl : MlemGame { } }; this.OnDraw += (_, _) => batch.Draw(null, SamplerState.PointClamp, null, null, null, Matrix.CreateScale(3)); + + Console.WriteLine("Keys: " + string.Join(", ", GenericInput.AllKeys)); + Console.WriteLine("MouseButtons: " + string.Join(", ", GenericInput.AllMouseButtons)); + Console.WriteLine("Buttons: " + string.Join(", ", GenericInput.AllButtons)); + Console.WriteLine("Inputs: " + string.Join(", ", GenericInput.AllInputs)); } protected override void DoUpdate(GameTime gameTime) { @@ -397,12 +403,15 @@ public class GameImpl : MlemGame { /*if (Input.InputsDown.Length > 0) Console.WriteLine("Down: " + string.Join(", ", Input.InputsDown));*/ - if (MlemGame.Input.InputsPressed.Length > 0) + /*if (MlemGame.Input.InputsPressed.Length > 0) Console.WriteLine("Pressed: " + string.Join(", ", MlemGame.Input.InputsPressed)); MlemGame.Input.HandleKeyboardRepeats = false; /* Console.WriteLine("Down time: " + MlemGame.Input.GetDownTime(Keys.A)); - Console.WriteLine("Time since press: " + MlemGame.Input.GetTimeSincePress(Keys.A));*/ - Console.WriteLine("Up time: " + MlemGame.Input.GetUpTime(Keys.A)); + Console.WriteLine("Time since press: " + MlemGame.Input.GetTimeSincePress(Keys.A));#1# + Console.WriteLine("Up time: " + MlemGame.Input.GetUpTime(Keys.A));*/ + + var combination = new Keybind.Combination(Keys.K, new GenericInput[] {Keys.LeftShift}, GenericInput.AllKeys); + Console.WriteLine($"Mod: {combination.IsModifierDown(this.InputHandler)} Down: {combination.IsDown(this.InputHandler)}"); } protected override void DoDraw(GameTime gameTime) { diff --git a/Tests/KeybindTests.cs b/Tests/KeybindTests.cs index 4585897..4e78aa5 100644 --- a/Tests/KeybindTests.cs +++ b/Tests/KeybindTests.cs @@ -36,4 +36,11 @@ public class KeybindTests { Assert.AreEqual(-1, new Keybind(Keys.A, Keys.LeftAlt).CompareTo(new Keybind(Keys.B, Keys.LeftShift, Keys.RightShift).Add(Keys.B, Keys.RightShift).Add(Keys.C, Keys.RightControl))); } + [Test] + public void TestModifierOverlap() { + var combination = new Keybind.Combination(Keys.A, new GenericInput[] {Keys.Left, Keys.Right}, new GenericInput[] {Keys.Up, Keys.Right}); + Assert.AreEqual(combination.Modifiers, new GenericInput[] {Keys.Left, Keys.Right}); + Assert.AreEqual(combination.InverseModifiers, new GenericInput[] {Keys.Up}); + } + }