using System; using System.Collections.Generic; using System.Linq; using BizHawk.Common; using BizHawk.Emulation.Common; namespace BizHawk.Client.Common { public class Controller : IController { 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; 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 bool AnyPressed { get { if (_buttons.Any(x => x.Value)) { return true; } return _floatButtons.Any(x => x.Value != 0); } } public float GetFloat(string name) { return _floatButtons[name]; } // Looks 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(boundButton => boundButton == 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) { var 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); } } var output = (input * multiplier + 10000.0f) * (range.Max - range.Min) / 20000.0f + range.Min; 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; } } } 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.Type != null) { foreach (var button in controller.Type.BoolButtons) { if (controller.IsPressed(button)) { _buttons[button] = true; } } } } public void Overrides(OverrideAdaptor controller) { foreach (var button in controller.Overrides) { _buttons[button] = controller[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 { get { return (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 Type { get { return _type; } } public bool this[string button] { get { return IsPressed(button); } } 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 bound_button in kvp.Value) { if (_buttons[kvp.Key] == false && controller[bound_button]) { _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[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 { get { return (from button in _buttons where button.Value select button.Key).ToList(); } } } }