diff --git a/MLEM.Ui/Elements/Slider.cs b/MLEM.Ui/Elements/Slider.cs
index 885bd2e..8ea92f0 100644
--- a/MLEM.Ui/Elements/Slider.cs
+++ b/MLEM.Ui/Elements/Slider.cs
@@ -32,9 +32,9 @@ namespace MLEM.Ui.Elements {
base.Update(time);
if (this.IsSelected) {
- if (this.Controls.LeftButtons.Any(b => this.Input.IsPressed(b, this.Controls.GamepadIndex))) {
+ if (this.Controls.LeftButtons.IsPressed(this.Input, this.Controls.GamepadIndex)) {
this.CurrentValue -= this.StepPerScroll;
- } else if (this.Controls.RightButtons.Any(b => this.Input.IsPressed(b, this.Controls.GamepadIndex))) {
+ } else if (this.Controls.RightButtons.IsPressed(this.Input, this.Controls.GamepadIndex)) {
this.CurrentValue += this.StepPerScroll;
}
}
diff --git a/MLEM.Ui/UiControls.cs b/MLEM.Ui/UiControls.cs
index 6250685..618dda5 100644
--- a/MLEM.Ui/UiControls.cs
+++ b/MLEM.Ui/UiControls.cs
@@ -54,39 +54,32 @@ namespace MLEM.Ui {
///
/// A list of , and/or that act as the buttons on the keyboard which perform the action.
/// If the is held, these buttons perform .
- /// To easily add more elements to this list, use .
///
- public object[] KeyboardButtons = {Keys.Space, Keys.Enter};
+ public readonly Keybind KeyboardButtons = new Keybind().Add(Keys.Space).Add(Keys.Enter);
///
- /// A list of , and/or that act as the buttons on a gamepad that perform the action.
- /// To easily add more elements to this list, use .
+ /// AA that acts as the buttons on a gamepad that perform the action.
///
- public object[] GamepadButtons = {Buttons.A};
+ public readonly Keybind GamepadButtons = new Keybind().Add(Buttons.A);
///
- /// A list of , and/or that act as the buttons on a gamepad that perform the action.
- /// To easily add more elements to this list, use .
+ /// A that acts as the buttons on a gamepad that perform the action.
///
- public object[] SecondaryGamepadButtons = {Buttons.X};
+ public readonly Keybind SecondaryGamepadButtons = new Keybind().Add(Buttons.X);
///
- /// A list of A list of , and/or that act as the buttons that select a that is above the currently selected element.
- /// To easily add more elements to this list, use .
+ /// A that acts as the buttons that select a that is above the currently selected element.
///
- public object[] UpButtons = {Buttons.DPadUp, Buttons.LeftThumbstickUp};
+ public readonly Keybind UpButtons = new Keybind().Add(Buttons.DPadUp).Add(Buttons.LeftThumbstickUp);
///
- /// A list of A list of , and/or that act as the buttons that select a that is below the currently selected element.
- /// To easily add more elements to this list, use .
+ /// A that acts as the buttons that select a that is below the currently selected element.
///
- public object[] DownButtons = {Buttons.DPadDown, Buttons.LeftThumbstickDown};
+ public readonly Keybind DownButtons = new Keybind().Add(Buttons.DPadDown).Add(Buttons.LeftThumbstickDown);
///
- /// A list of A list of , and/or that act as the buttons that select a that is to the left of the currently selected element.
- /// To easily add more elements to this list, use .
+ /// A that acts as the buttons that select a that is to the left of the currently selected element.
///
- public object[] LeftButtons = {Buttons.DPadLeft, Buttons.LeftThumbstickLeft};
+ public readonly Keybind LeftButtons = new Keybind().Add(Buttons.DPadLeft).Add(Buttons.LeftThumbstickLeft);
///
- /// A list of A list of , and/or that act as the buttons that select a that is to the right of the currently selected element.
- /// To easily add more elements to this list, use .
+ /// A that acts as the buttons that select a that is to the right of the currently selected element.
///
- public object[] RightButtons = {Buttons.DPadRight, Buttons.LeftThumbstickRight};
+ public readonly Keybind RightButtons = new Keybind().Add(Buttons.DPadRight).Add(Buttons.LeftThumbstickRight);
///
/// The zero-based index of the used for gamepad input.
/// If this index is lower than 0, every connected gamepad will trigger input.
@@ -162,7 +155,7 @@ namespace MLEM.Ui {
// KEYBOARD INPUT
if (this.HandleKeyboard) {
- if (this.KeyboardButtons.Any(this.IsAnyPressed)) {
+ if (this.KeyboardButtons.IsPressed(this.Input, this.GamepadIndex)) {
if (this.SelectedElement?.Root != null && this.SelectedElement.CanBePressed) {
if (this.Input.IsModifierKeyDown(ModifierKey.Shift)) {
// secondary action on element using space or enter
@@ -215,19 +208,19 @@ namespace MLEM.Ui {
// GAMEPAD INPUT
if (this.HandleGamepad) {
- if (this.GamepadButtons.Any(this.IsAnyPressed)) {
+ if (this.GamepadButtons.IsPressed(this.Input, this.GamepadIndex)) {
if (this.SelectedElement?.Root != null && this.SelectedElement.CanBePressed)
this.System.OnElementPressed?.Invoke(this.SelectedElement);
- } else if (this.SecondaryGamepadButtons.Any(this.IsAnyPressed)) {
+ } else if (this.SecondaryGamepadButtons.IsPressed(this.Input, this.GamepadIndex)) {
if (this.SelectedElement?.Root != null && this.SelectedElement.CanBePressed)
this.System.OnElementSecondaryPressed?.Invoke(this.SelectedElement);
- } else if (this.DownButtons.Any(this.IsAnyPressed)) {
+ } else if (this.DownButtons.IsPressed(this.Input, this.GamepadIndex)) {
this.HandleGamepadNextElement(Direction2.Down);
- } else if (this.LeftButtons.Any(this.IsAnyPressed)) {
+ } else if (this.LeftButtons.IsPressed(this.Input, this.GamepadIndex)) {
this.HandleGamepadNextElement(Direction2.Left);
- } else if (this.RightButtons.Any(this.IsAnyPressed)) {
+ } else if (this.RightButtons.IsPressed(this.Input, this.GamepadIndex)) {
this.HandleGamepadNextElement(Direction2.Right);
- } else if (this.UpButtons.Any(this.IsAnyPressed)) {
+ } else if (this.UpButtons.IsPressed(this.Input, this.GamepadIndex)) {
this.HandleGamepadNextElement(Direction2.Up);
}
}
@@ -383,10 +376,6 @@ namespace MLEM.Ui {
}
}
- private bool IsAnyPressed(object button) {
- return this.Input.IsPressed(button, this.GamepadIndex);
- }
-
private void HandleGamepadNextElement(Direction2 dir) {
this.IsAutoNavMode = true;
RectangleF searchArea = default;
@@ -417,14 +406,5 @@ namespace MLEM.Ui {
this.SelectElement(this.ActiveRoot, next);
}
- ///
- /// A helper function to add , or to an array of controls.
- ///
- /// The controls to add to
- /// The additional controls to add to the controls list
- public static void AddButtons(ref object[] controls, params object[] additional) {
- controls = controls.Concat(additional).ToArray();
- }
-
}
}
\ No newline at end of file
diff --git a/MLEM/Input/GenericInput.cs b/MLEM/Input/GenericInput.cs
new file mode 100644
index 0000000..0addb76
--- /dev/null
+++ b/MLEM/Input/GenericInput.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Runtime.Serialization;
+using Microsoft.Xna.Framework.Input;
+
+namespace MLEM.Input {
+ ///
+ /// A generic input represents any kind of input key.
+ /// This includes for keyboard keys, for mouse buttons and for gamepad buttons.
+ /// For creating and extracting inputs from a generic input, the implicit operators and can be used.
+ /// Note that this type is serializable using .
+ ///
+ [DataContract]
+ public struct GenericInput {
+
+ ///
+ /// The of this generic input's current .
+ ///
+ [DataMember]
+ public readonly InputType Type;
+ [DataMember]
+ private readonly int value;
+
+ private GenericInput(InputType type, int value) {
+ this.Type = type;
+ this.value = value;
+ }
+
+ ///
+ /// Converts a to a generic input.
+ ///
+ /// The keys to convert
+ /// The resulting generic input
+ public static implicit operator GenericInput(Keys keys) {
+ return new GenericInput(InputType.Keyboard, (int) keys);
+ }
+
+ ///
+ /// Converts a to a generic input.
+ ///
+ /// The button to convert
+ /// The resulting generic input
+ public static implicit operator GenericInput(MouseButton button) {
+ return new GenericInput(InputType.Mouse, (int) button);
+ }
+
+ ///
+ /// Converts a to a generic input.
+ ///
+ /// The buttons to convert
+ /// The resulting generic input
+ public static implicit operator GenericInput(Buttons buttons) {
+ return new GenericInput(InputType.Gamepad, (int) buttons);
+ }
+
+ ///
+ /// Converts a generic input to a .
+ ///
+ /// The input to convert
+ /// The resulting keys
+ /// If the given generic input's is not
+ public static implicit operator Keys(GenericInput input) {
+ if (input.Type != InputType.Keyboard)
+ throw new ArgumentException();
+ return (Keys) input.value;
+ }
+
+ ///
+ /// Converts a generic input to a .
+ ///
+ /// The input to convert
+ /// The resulting button
+ /// If the given generic input's is not
+ public static implicit operator MouseButton(GenericInput input) {
+ if (input.Type != InputType.Mouse)
+ throw new ArgumentException();
+ return (MouseButton) input.value;
+ }
+
+ ///
+ /// Converts a generic input to a .
+ ///
+ /// The input to convert
+ /// The resulting buttons
+ /// If the given generic input's is not
+ public static implicit operator Buttons(GenericInput input) {
+ if (input.Type != InputType.Gamepad)
+ throw new ArgumentException();
+ return (Buttons) input.value;
+ }
+
+ ///
+ /// A type of input button.
+ ///
+ [DataContract]
+ public enum InputType {
+
+ ///
+ /// A type representing
+ ///
+ [EnumMember]
+ Mouse,
+ ///
+ /// A type representing
+ ///
+ [EnumMember]
+ Keyboard,
+ ///
+ /// A type representing
+ ///
+ [EnumMember]
+ Gamepad
+
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/MLEM/Input/InputHandler.cs b/MLEM/Input/InputHandler.cs
index 36740b5..8a3d6c1 100644
--- a/MLEM/Input/InputHandler.cs
+++ b/MLEM/Input/InputHandler.cs
@@ -432,13 +432,13 @@ namespace MLEM.Input {
/// The index of the gamepad to query (if applicable), or -1 for any gamepad
/// Whether the given control is down
/// If the passed control isn't of a supported type
- public bool IsDown(object control, int index = -1) {
- if (control is Keys key)
- return this.IsKeyDown(key);
- if (control is Buttons button)
- return this.IsGamepadButtonDown(button, index);
- if (control is MouseButton mouse)
- return this.IsMouseButtonDown(mouse);
+ public bool IsDown(GenericInput control, int index = -1) {
+ if (control.Type == GenericInput.InputType.Keyboard)
+ return this.IsKeyDown(control);
+ if (control.Type == GenericInput.InputType.Gamepad)
+ return this.IsGamepadButtonDown(control, index);
+ if (control.Type == GenericInput.InputType.Mouse)
+ return this.IsMouseButtonDown(control);
throw new ArgumentException(nameof(control));
}
@@ -450,13 +450,13 @@ namespace MLEM.Input {
/// The index of the gamepad to query (if applicable), or -1 for any gamepad
/// Whether the given control is down
/// If the passed control isn't of a supported type
- public bool IsUp(object control, int index = -1) {
- if (control is Keys key)
- return this.IsKeyUp(key);
- if (control is Buttons button)
- return this.IsGamepadButtonUp(button, index);
- if (control is MouseButton mouse)
- return this.IsMouseButtonUp(mouse);
+ public bool IsUp(GenericInput control, int index = -1) {
+ if (control.Type == GenericInput.InputType.Keyboard)
+ return this.IsKeyUp(control);
+ if (control.Type == GenericInput.InputType.Gamepad)
+ return this.IsGamepadButtonUp(control, index);
+ if (control.Type == GenericInput.InputType.Mouse)
+ return this.IsMouseButtonUp(control);
throw new ArgumentException(nameof(control));
}
@@ -468,28 +468,28 @@ namespace MLEM.Input {
/// The index of the gamepad to query (if applicable), or -1 for any gamepad
/// Whether the given control is down
/// If the passed control isn't of a supported type
- public bool IsPressed(object control, int index = -1) {
- if (control is Keys key)
- return this.IsKeyPressed(key);
- if (control is Buttons button)
- return this.IsGamepadButtonPressed(button, index);
- if (control is MouseButton mouse)
- return this.IsMouseButtonPressed(mouse);
+ public bool IsPressed(GenericInput control, int index = -1) {
+ if (control.Type == GenericInput.InputType.Keyboard)
+ return this.IsKeyPressed(control);
+ if (control.Type == GenericInput.InputType.Gamepad)
+ return this.IsGamepadButtonPressed(control, index);
+ if (control.Type == GenericInput.InputType.Mouse)
+ return this.IsMouseButtonPressed(control);
throw new ArgumentException(nameof(control));
}
///
- public bool IsAnyDown(params object[] control) {
+ public bool IsAnyDown(params GenericInput[] control) {
return control.Any(c => this.IsDown(c));
}
///
- public bool IsAnyUp(params object[] control) {
+ public bool IsAnyUp(params GenericInput[] control) {
return control.Any(c => this.IsUp(c));
}
///
- public bool IsAnyPressed(params object[] control) {
+ public bool IsAnyPressed(params GenericInput[] control) {
return control.Any(c => this.IsPressed(c));
}
diff --git a/MLEM/Input/Keybind.cs b/MLEM/Input/Keybind.cs
new file mode 100644
index 0000000..61318e8
--- /dev/null
+++ b/MLEM/Input/Keybind.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.Serialization;
+using Microsoft.Xna.Framework.Input;
+
+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 .
+ ///
+ [DataContract]
+ public class Keybind {
+
+ [DataMember]
+ private readonly List combinations = new List();
+
+ ///
+ /// Adds a new key combination to this keybind that can optionally be pressed for the keybind to trigger.
+ ///
+ /// The key to be pressed.
+ /// The modifier keys that have to be held down.
+ /// This keybind, for chaining
+ public Keybind Add(GenericInput key, params GenericInput[] modifiers) {
+ this.combinations.Add(new Combination(key, modifiers));
+ return this;
+ }
+
+ ///
+ public Keybind Add(GenericInput key, ModifierKey modifier) {
+ return this.Add(key, modifier.GetKeys().Select(m => (GenericInput) m).ToArray());
+ }
+
+ ///
+ /// Clears this keybind, removing all active combinations.
+ ///
+ /// This keybind, for chaining
+ public Keybind Clear() {
+ this.combinations.Clear();
+ return this;
+ }
+
+ ///
+ /// Copies all of the combinations from the given keybind into this keybind.
+ /// Note that this doesn't this keybind, so combinations will be merged rather than replaced.
+ ///
+ /// The keybind to copy from
+ /// This keybind, for chaining
+ public Keybind CopyFrom(Keybind other) {
+ this.combinations.AddRange(other.combinations);
+ return this;
+ }
+
+ ///
+ /// Returns whether this keybind is considered to be down.
+ /// See for more information.
+ ///
+ /// The input handler to query the keys with
+ /// The index of the gamepad to query, or -1 to query all gamepads
+ /// Whether this keybind is considered to be down
+ public bool IsDown(InputHandler handler, int gamepadIndex = -1) {
+ return this.combinations.Any(c => c.IsDown(handler, gamepadIndex));
+ }
+
+ ///
+ /// Returns whether this keybind is considered to be pressed.
+ /// See for more information.
+ ///
+ /// The input handler to query the keys with
+ /// The index of the gamepad to query, or -1 to query all gamepads
+ /// Whether this keybind is considered to be pressed
+ public bool IsPressed(InputHandler handler, int gamepadIndex = -1) {
+ return this.combinations.Any(c => c.IsPressed(handler, gamepadIndex));
+ }
+
+ [DataContract]
+ private class Combination {
+
+ [DataMember]
+ private readonly GenericInput[] modifiers;
+ [DataMember]
+ private readonly GenericInput key;
+
+ public Combination(GenericInput key, GenericInput[] modifiers) {
+ this.modifiers = modifiers;
+ this.key = key;
+ }
+
+ internal bool IsDown(InputHandler handler, int gamepadIndex = -1) {
+ return this.IsModifierDown(handler, gamepadIndex) && handler.IsDown(this.key, gamepadIndex);
+ }
+
+ internal bool IsPressed(InputHandler handler, int gamepadIndex = -1) {
+ return this.IsModifierDown(handler, gamepadIndex) && handler.IsPressed(this.key, gamepadIndex);
+ }
+
+ private bool IsModifierDown(InputHandler handler, int gamepadIndex = -1) {
+ return this.modifiers.Length <= 0 || this.modifiers.Any(m => handler.IsDown(m, gamepadIndex));
+ }
+
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/build.cake b/build.cake
index f8fea57..3f479d5 100644
--- a/build.cake
+++ b/build.cake
@@ -2,7 +2,7 @@
#tool docfx.console&version=2.51.0
// this is the upcoming version, for prereleases
-var version = Argument("version", "3.3.3");
+var version = Argument("version", "4.0.0");
var target = Argument("target", "Default");
var branch = Argument("branch", "master");
var config = Argument("configuration", "Release");