diff --git a/CHANGELOG.md b/CHANGELOG.md index f133cb7..6908733 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,9 @@ Additions - Added InputHandler.InvertPressBehavior - Added ReverseInput, ReverseOutput and AndThen to Easings +Improvements +- Allow comparing Keybind and Combination based on the amount of modifiers they have + ### MLEM.Ui Additions - Added Element.AutoNavGroup which allows forming groups for auto-navigation diff --git a/MLEM/Input/Keybind.cs b/MLEM/Input/Keybind.cs index 9b920e7..9ae014d 100644 --- a/MLEM/Input/Keybind.cs +++ b/MLEM/Input/Keybind.cs @@ -8,9 +8,10 @@ namespace MLEM.Input { /// A keybind represents a generic way to trigger input. /// A keybind is made up of multiple key combinations, one of which has to be pressed for the keybind to be triggered. /// Note that this type is serializable using . + /// Note that this class implements and , which allows two combinations to be ordered based on how many their combinations have. /// [DataContract] - public class Keybind { + public class Keybind : IComparable, IComparable { [DataMember] private Combination[] combinations = Array.Empty(); @@ -213,6 +214,32 @@ namespace MLEM.Input { return string.Join(joiner, this.combinations.Select(c => c.ToString(combinationJoiner, inputName))); } + /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object. + /// An object to compare with this instance. + /// A value that indicates the relative order of the objects being compared. The return value has these meanings: + /// + /// Value Meaning Less than zero This instance precedes in the sort order. Zero This instance occurs in the same position in the sort order as . Greater than zero This instance follows in the sort order. + public int CompareTo(Keybind other) { + return this.combinations.Sum(c => other.combinations.Sum(c.CompareTo)); + } + + /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object. + /// An object to compare with this instance. + /// + /// is not the same type as this instance. + /// A value that indicates the relative order of the objects being compared. The return value has these meanings: + /// + /// Value Meaning Less than zero This instance precedes in the sort order. Zero This instance occurs in the same position in the sort order as . Greater than zero This instance follows in the sort order. + public int CompareTo(object obj) { + if (ReferenceEquals(null, obj)) + return 1; + if (ReferenceEquals(this, obj)) + return 0; + if (!(obj is Keybind other)) + throw new ArgumentException($"Object must be of type {nameof(Keybind)}"); + return this.CompareTo(other); + } + /// /// Converts this keybind into a string, separating every included by a comma /// @@ -224,9 +251,10 @@ namespace MLEM.Input { /// /// A key combination is a combination of a set of modifier keys and a key. /// All of the keys are instances, so they can be keyboard-, mouse- or gamepad-based. + /// Note that this class implements and , which allows two combinations to be ordered based on how many they have. /// [DataContract] - public class Combination { + public class Combination : IComparable, IComparable { /// /// The inputs that have to be held down for this combination to be valid. @@ -247,7 +275,7 @@ namespace MLEM.Input { /// /// The key /// The modifiers - public Combination(GenericInput key, GenericInput[] modifiers) { + public Combination(GenericInput key, params GenericInput[] modifiers) { this.Modifiers = modifiers; this.Key = key; } @@ -324,6 +352,32 @@ namespace MLEM.Input { return string.Join(joiner, this.Modifiers.Append(this.Key).Select(i => inputName?.Invoke(i) ?? i.ToString())); } + /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object. + /// An object to compare with this instance. + /// A value that indicates the relative order of the objects being compared. The return value has these meanings: + /// + /// Value Meaning Less than zero This instance precedes in the sort order. Zero This instance occurs in the same position in the sort order as . Greater than zero This instance follows in the sort order. + public int CompareTo(Combination other) { + return this.Modifiers.Length.CompareTo(other.Modifiers.Length); + } + + /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object. + /// An object to compare with this instance. + /// + /// is not the same type as this instance. + /// A value that indicates the relative order of the objects being compared. The return value has these meanings: + /// + /// Value Meaning Less than zero This instance precedes in the sort order. Zero This instance occurs in the same position in the sort order as . Greater than zero This instance follows in the sort order. + public int CompareTo(object obj) { + if (ReferenceEquals(null, obj)) + return 1; + if (ReferenceEquals(this, obj)) + return 0; + if (!(obj is Combination other)) + throw new ArgumentException($"Object must be of type {nameof(Combination)}"); + return this.CompareTo(other); + } + /// Returns a string that represents the current object. /// A string that represents the current object. public override string ToString() { diff --git a/Tests/KeybindTests.cs b/Tests/KeybindTests.cs new file mode 100644 index 0000000..305940a --- /dev/null +++ b/Tests/KeybindTests.cs @@ -0,0 +1,39 @@ +using Microsoft.Xna.Framework.Input; +using MLEM.Input; +using NUnit.Framework; + +namespace Tests { + public class KeybindTests { + + [Test] + public void TestCombinationOrder() { + Assert.AreEqual(0, new Keybind.Combination(Keys.A).CompareTo(new Keybind.Combination(Keys.B))); + + Assert.AreEqual(1, new Keybind.Combination(Keys.A, Keys.LeftShift).CompareTo(new Keybind.Combination(Keys.B))); + Assert.AreEqual(1, new Keybind.Combination(Keys.A, Keys.LeftShift, Keys.RightShift).CompareTo(new Keybind.Combination(Keys.B))); + Assert.AreEqual(1, new Keybind.Combination(Keys.A, Keys.LeftShift, Keys.RightShift).CompareTo(new Keybind.Combination(Keys.B, Keys.LeftShift))); + + Assert.AreEqual(-1, new Keybind.Combination(Keys.A).CompareTo(new Keybind.Combination(Keys.B, Keys.LeftShift))); + Assert.AreEqual(-1, new Keybind.Combination(Keys.A).CompareTo(new Keybind.Combination(Keys.B, Keys.LeftShift, Keys.RightShift))); + Assert.AreEqual(-1, new Keybind.Combination(Keys.A, Keys.LeftShift).CompareTo(new Keybind.Combination(Keys.B, Keys.LeftShift, Keys.RightShift))); + } + + [Test] + public void TestKeybindOrder() { + Assert.AreEqual(0, new Keybind(Keys.A).CompareTo(new Keybind(Keys.B))); + + Assert.AreEqual(2, new Keybind(Keys.A, Keys.LeftShift).Add(Keys.B, Keys.RightShift).CompareTo(new Keybind(Keys.B))); + Assert.AreEqual(2, new Keybind(Keys.A, Keys.LeftShift).Add(Keys.B, Keys.RightShift).Add(Keys.C).CompareTo(new Keybind(Keys.B))); + Assert.AreEqual(3, new Keybind(Keys.A, Keys.LeftShift).Add(Keys.B, Keys.RightShift).Add(Keys.C, Keys.RightControl).CompareTo(new Keybind(Keys.B))); + Assert.AreEqual(0, new Keybind(Keys.A, Keys.LeftShift).Add(Keys.B, Keys.RightShift).Add(Keys.C, Keys.RightControl).CompareTo(new Keybind(Keys.B, Keys.LeftAlt))); + Assert.AreEqual(1, new Keybind(Keys.A, Keys.LeftShift, Keys.RightShift).Add(Keys.B, Keys.RightShift).Add(Keys.C, Keys.RightControl).CompareTo(new Keybind(Keys.B, Keys.LeftAlt))); + + Assert.AreEqual(-2, new Keybind(Keys.A).CompareTo(new Keybind(Keys.B, Keys.LeftShift).Add(Keys.B, Keys.RightShift))); + Assert.AreEqual(-2, new Keybind(Keys.A).CompareTo(new Keybind(Keys.B, Keys.LeftShift).Add(Keys.B, Keys.RightShift).Add(Keys.C))); + Assert.AreEqual(-3, new Keybind(Keys.A).CompareTo(new Keybind(Keys.B, Keys.LeftShift).Add(Keys.B, Keys.RightShift).Add(Keys.C, Keys.RightControl))); + Assert.AreEqual(0, new Keybind(Keys.A, Keys.LeftAlt).CompareTo(new Keybind(Keys.B, Keys.LeftShift).Add(Keys.B, Keys.RightShift).Add(Keys.C, Keys.RightControl))); + 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))); + } + + } +} \ No newline at end of file