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));
}
}
}
}