using System; using System.Collections.Generic; using System.Linq; using BizHawk.Common; using BizHawk.Emulation.Common; namespace BizHawk.Client.Common { public class Controller : IController { 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 Definition => _type; public bool IsPressed(string button) { return _buttons[button]; } public float GetFloat(string name) { return _floatButtons[name]; } 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(); private ControllerDefinition _type; /// don't do this public void ForceType(ControllerDefinition newtype) { _type = newtype; } public bool this[string button] => IsPressed(button); public bool AnyPressed { get { if (_buttons.Any(b => b.Value)) { return true; } return _floatButtons.Any(b => b.Value != 0); } } // Looks for bindings which are activated by the supplied physical button. public List SearchBindings(string button) { return (from kvp in _bindings from boundButton in kvp.Value where boundButton == 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(boundButton => boundButton == button); } public void NormalizeFloats(IController controller) { foreach (var kvp in _floatBinds) { var input = _floatButtons[kvp.Key]; 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); } } // zero 09-mar-2015 - not sure if adding + 1 here is correct.. but... maybe? var output = (((input * multiplier) + 10000.0f) * (range.Max - range.Min + 1) / 20000.0f) + range.Min; // zero 09-mar-2015 - at this point, we should only have integers, since thats all 100% of consoles ever see // if this becomes a problem we can add flags to the range and update GUIs to be able to display floats output = (int)output; float lbound = Math.Min(range.Min, range.Max); float ubound = Math.Max(range.Min, range.Max); if (output < lbound) { output = lbound; } if (output > ubound) { output = ubound; } _floatButtons[outkey] = output; } } } /// /// 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.IsPressed(bound_button)) { _buttons[kvp.Key] = true; } } } foreach (var kvp in _floatBinds) { var input = controller.GetFloat(kvp.Value.Value); string outkey = kvp.Key; if (_floatRanges.ContainsKey(outkey)) { _floatButtons[outkey] = input; } } // it's not sure where this should happen, so for backwards compatibility.. do it every time NormalizeFloats(controller); } public void ApplyAxisConstraints(string constraintClass) { _type.ApplyAxisConstraints(constraintClass, _floatButtons); } /// /// 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.Definition != null) { foreach (var button in controller.Definition.BoolButtons) { if (controller.IsPressed(button)) { _buttons[button] = true; } } } } public void Overrides(OverrideAdaptor controller) { foreach (var button in controller.Overrides) { _buttons[button] = controller.IsPressed(button); } foreach (var button in controller.FloatOverrides) { _floatButtons[button] = controller.GetFloat(button); } foreach (var button in controller.InversedButtons) { _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; } var controlbindings = controlString.Split(','); foreach (var 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 => (from button in _buttons where button.Value select button.Key).ToList(); } public class AutofireController : IController { public AutofireController(ControllerDefinition definition, IEmulator emulator) { On = Global.Config.AutofireOn < 1 ? 0 : Global.Config.AutofireOn; Off = Global.Config.AutofireOff < 1 ? 0 : Global.Config.AutofireOff; _type = definition; _emulator = emulator; } private readonly IEmulator _emulator; private readonly ControllerDefinition _type; private readonly WorkingDictionary> _bindings = new WorkingDictionary>(); private readonly WorkingDictionary _buttons = new WorkingDictionary(); private readonly 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 ControllerDefinition Definition => _type; public bool IsPressed(string button) { if (_autofire) { var a = (_emulator.Frame - _buttonStarts[button]) % (On + Off); return a < On && _buttons[button]; } return _buttons[button]; } public void ClearStarts() { _buttonStarts.Clear(); } public float GetFloat(string name) { throw new NotImplementedException(); } // 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 boundBtn in kvp.Value) { if (_buttons[kvp.Key] == false && controller.IsPressed(boundBtn)) { _buttonStarts[kvp.Key] = _emulator.Frame; } } } _buttons.Clear(); foreach (var kvp in _bindings) { _buttons[kvp.Key] = false; foreach (var bound_button in kvp.Value) { if (controller.IsPressed(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 (var button in _type.BoolButtons.Where(controller.IsPressed)) { _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)) { var controlbindings = controlString.Split(','); foreach (var control in controlbindings) { _bindings[button].Add(control.Trim()); } } } public void IncrementStarts() { foreach (var key in _buttonStarts.Keys.ToArray()) { _buttonStarts[key]++; } } public List PressedButtons => (from button in _buttons where button.Value select button.Key).ToList(); } }