using System; using System.Collections.Generic; using System.Linq; using BizHawk.Common; namespace BizHawk.Client.Common { public class Controller : IController { private ControllerDefinition type; private readonly WorkingDictionary> bindings = new WorkingDictionary>(); private readonly WorkingDictionary buttons = new WorkingDictionary(); private readonly WorkingDictionary FloatButtons = new WorkingDictionary(); private readonly Dictionary FloatRanges = new WorkingDictionary(); private readonly Dictionary FloatBinds = new Dictionary(); public Controller(ControllerDefinition definition) { type = definition; for (int i = 0; i < type.FloatControls.Count; i++) { FloatButtons[type.FloatControls[i]] = type.FloatRanges[i].Mid; FloatRanges[type.FloatControls[i]] = type.FloatRanges[i]; } } public ControllerDefinition Type { get { return type; } } /// don't do this public void ForceType(ControllerDefinition newtype) { type = newtype; } public bool this[string button] { get { return IsPressed(button); } } public bool IsPressed(string button) { return buttons[button]; } public float GetFloat(string name) { return FloatButtons[name]; } public void UpdateControls(int frame) { } //look for bindings which are activated by the supplied physical button. public List SearchBindings(string button) { return (from kvp in bindings from bound_button in kvp.Value where bound_button == button select kvp.Key).ToList(); } //Searches bindings for the controller and returns true if this binding is mapped somewhere in this controller public bool HasBinding(string button) { return bindings.SelectMany(kvp => kvp.Value).Any(bound_button => bound_button == button); } /// /// uses the bindings to latch our own logical button state from the source controller's button state (which are assumed to be the physical side of the binding). /// this will clobber any existing data (use OR_* or other functions to layer in additional input sources) /// public void LatchFromPhysical(IController controller) { buttons.Clear(); foreach (var kvp in bindings) { buttons[kvp.Key] = false; foreach (var bound_button in kvp.Value) { if (controller[bound_button]) buttons[kvp.Key] = true; } } foreach (var kvp in FloatBinds) { float input = controller.GetFloat(kvp.Value.Value); string outkey = kvp.Key; float multiplier = kvp.Value.Mult; float deadzone = kvp.Value.Deadzone; ControllerDefinition.FloatRange range; if (FloatRanges.TryGetValue(outkey, out range)) { // input range is assumed to be -10000,0,10000 // first, modify for deadzone { float absinput = Math.Abs(input); float zeropoint = deadzone * 10000.0f; if (absinput < zeropoint) input = 0.0f; else { absinput -= zeropoint; absinput *= 10000.0f; absinput /= (10000.0f - zeropoint); input = absinput * Math.Sign(input); } } float output = (input * multiplier + 10000.0f) * (range.Max - range.Min) / 20000.0f + range.Min; if (output < range.Min) output = range.Min; if (output > range.Max) output = range.Max; FloatButtons[outkey] = output; } } } /// /// merges pressed logical buttons from the supplied controller, effectively ORing it with the current state /// public void OR_FromLogical(IController controller) { // change: or from each button that the other input controller has //foreach (string button in type.BoolButtons) if (controller.Type != null) foreach (string button in controller.Type.BoolButtons) { if (controller.IsPressed(button)) { buttons[button] = true; } } } public void BindButton(string button, string control) { bindings[button].Add(control); } public void BindMulti(string button, string controlString) { if (string.IsNullOrEmpty(controlString)) return; string[] controlbindings = controlString.Split(','); foreach (string control in controlbindings) bindings[button].Add(control.Trim()); } public void BindFloat(string button, Config.AnalogBind bind) { FloatBinds[button] = bind; } /// /// Returns a list of all keys mapped and the name of the button they are mapped to /// /// public List> MappingList() { return (from key in bindings from binding in key.Value select new KeyValuePair(binding, key.Key)).ToList(); } public List PressedButtons { get { return (from button in buttons where button.Value select button.Key).ToList(); } } } public class AutofireController : IController { private readonly ControllerDefinition type; private readonly WorkingDictionary> bindings = new WorkingDictionary>(); private readonly WorkingDictionary buttons = new WorkingDictionary(); public WorkingDictionary buttonStarts = new WorkingDictionary(); private bool autofire = true; public bool Autofire { get { return false; } set { autofire = value; } } public int On { get; set; } public int Off { get; set; } public AutofireController(ControllerDefinition definition) { On = Global.Config.AutofireOn < 1 ? 0 : Global.Config.AutofireOn; Off = Global.Config.AutofireOff < 1 ? 0 : Global.Config.AutofireOff; type = definition; } public ControllerDefinition Type { get { return type; } } public bool this[string button] { get { return IsPressed(button); } } public bool IsPressed(string button) { if (autofire) { int a = (Global.Emulator.Frame - buttonStarts[button])%(On + Off); if (a < On) { return buttons[button]; } else { return false; } } else { return buttons[button]; } } public float GetFloat(string name) { throw new NotImplementedException(); } public void UpdateControls(int frame) { } //look for bindings which are activated by the supplied physical button. public List SearchBindings(string button) { return (from kvp in bindings from bound_button in kvp.Value where bound_button == button select kvp.Key).ToList(); } /// /// uses the bindings to latch our own logical button state from the source controller's button state (which are assumed to be the physical side of the binding). /// this will clobber any existing data (use OR_* or other functions to layer in additional input sources) /// public void LatchFromPhysical(IController controller) { foreach (var kvp in bindings) { foreach (var bound_button in kvp.Value) { if (buttons[kvp.Key] == false && controller[bound_button]) buttonStarts[kvp.Key] = Global.Emulator.Frame; } } buttons.Clear(); foreach (var kvp in bindings) { buttons[kvp.Key] = false; foreach (var bound_button in kvp.Value) { if (controller[bound_button]) { buttons[kvp.Key] = true; } } } } /// /// merges pressed logical buttons from the supplied controller, effectively ORing it with the current state /// public void OR_FromLogical(IController controller) { foreach (string button in type.BoolButtons) { if (controller.IsPressed(button)) { buttons[button] = true; Console.WriteLine(button); } } } public void BindButton(string button, string control) { bindings[button].Add(control); } public void BindMulti(string button, string controlString) { if (!String.IsNullOrEmpty(controlString)) { string[] controlbindings = controlString.Split(','); foreach (string control in controlbindings) { bindings[button].Add(control.Trim()); } } } public void IncrementStarts() { foreach (var key in buttonStarts.Keys.ToArray()) buttonStarts[key]++; } public List PressedButtons { get { return (from button in buttons where button.Value select button.Key).ToList(); } } } }