From 3169968858984fdfe2f948d6eaa07020da00d1dd Mon Sep 17 00:00:00 2001 From: goyuken Date: Thu, 18 Jul 2013 16:18:17 +0000 Subject: [PATCH] analog input support. this is bad code and should all be reverted as soon as possible. binds (along with sensitivity, deadzone, flip customization) are not supported yet. to test out, try using the first two axes of dinput joystick #5 on N64 player #1 --- .../Consoles/Atari/7800/Atari7800Control.cs | 22 +++++++++ .../Consoles/Nintendo/N64/N64.cs | 11 +++++ BizHawk.Emulation/Consoles/Sony/PSP/PSP.cs | 5 ++ BizHawk.Emulation/Interfaces/IController.cs | 39 ++++++++++++++- .../Input/ControllerBinding.cs | 31 ++++++++++-- BizHawk.MultiClient/Input/GamePad.cs | 7 +++ BizHawk.MultiClient/Input/Input.cs | 47 +++++++++++++------ BizHawk.MultiClient/MainForm.cs | 3 ++ BizHawk.MultiClient/movie/InputAdapters.cs | 9 +++- 9 files changed, 154 insertions(+), 20 deletions(-) diff --git a/BizHawk.Emulation/Consoles/Atari/7800/Atari7800Control.cs b/BizHawk.Emulation/Consoles/Atari/7800/Atari7800Control.cs index b060e1c89e..6b4c23f5fb 100644 --- a/BizHawk.Emulation/Consoles/Atari/7800/Atari7800Control.cs +++ b/BizHawk.Emulation/Consoles/Atari/7800/Atari7800Control.cs @@ -48,6 +48,14 @@ namespace BizHawk.Emulation "P2 Paddle", "P3 Paddle", "P4 Paddle" + }, + FloatRanges = + { + // what is the center point supposed to be here? + new[] {0.0f, 0.0f, 700000.0f}, + new[] {0.0f, 0.0f, 700000.0f}, + new[] {0.0f, 0.0f, 700000.0f}, + new[] {0.0f, 0.0f, 700000.0f} } }; public static ControllerDefinition Keypad = new ControllerDefinition @@ -103,6 +111,12 @@ namespace BizHawk.Emulation { "P1 Driving", "P2 Driving" + }, + FloatRanges = + { + new[] {0.0f, 0.0f, 3.0f}, + new[] {0.0f, 0.0f, 3.0f}, + new[] {0.0f, 0.0f, 3.0f} } }; public static ControllerDefinition BoosterGrip = new ControllerDefinition @@ -159,6 +173,14 @@ namespace BizHawk.Emulation { "P1 VPos", "P1 HPos", "P2 VPos", "P2 HPos" + }, + FloatRanges = + { + // how many scanlines are there again?? + new[] {0.0f, 0.0f, 240.0f}, + new[] {0.0f, 0.0f, 319.0f}, + new[] {0.0f, 0.0f, 240.0f}, + new[] {0.0f, 0.0f, 319.0f} } }; diff --git a/BizHawk.Emulation/Consoles/Nintendo/N64/N64.cs b/BizHawk.Emulation/Consoles/Nintendo/N64/N64.cs index aee3013cef..da62f0d7aa 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/N64/N64.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/N64/N64.cs @@ -49,6 +49,17 @@ namespace BizHawk.Emulation.Consoles.Nintendo.N64 "P2 X Axis", "P2 Y Axis", "P3 X Axis", "P3 Y Axis", "P4 X Axis", "P4 Y Axis" + }, + FloatRanges = + { + new[] {-128.0f, 0.0f, 127.0f}, + new[] {-128.0f, 0.0f, 127.0f}, + new[] {-128.0f, 0.0f, 127.0f}, + new[] {-128.0f, 0.0f, 127.0f}, + new[] {-128.0f, 0.0f, 127.0f}, + new[] {-128.0f, 0.0f, 127.0f}, + new[] {-128.0f, 0.0f, 127.0f}, + new[] {-128.0f, 0.0f, 127.0f} } }; diff --git a/BizHawk.Emulation/Consoles/Sony/PSP/PSP.cs b/BizHawk.Emulation/Consoles/Sony/PSP/PSP.cs index f4cb4cbc7b..ecbaeccbd8 100644 --- a/BizHawk.Emulation/Consoles/Sony/PSP/PSP.cs +++ b/BizHawk.Emulation/Consoles/Sony/PSP/PSP.cs @@ -18,6 +18,11 @@ namespace BizHawk.Emulation.Consoles.Sony.PSP FloatControls = { "Stick X", "Stick Y" + }, + FloatRanges = // TODO + { + new[] {-1.0f, 0.0f, 1.0f}, + new[] {-1.0f, 0.0f, 1.0f}, } }; diff --git a/BizHawk.Emulation/Interfaces/IController.cs b/BizHawk.Emulation/Interfaces/IController.cs index cfdedc8091..e61434d45d 100644 --- a/BizHawk.Emulation/Interfaces/IController.cs +++ b/BizHawk.Emulation/Interfaces/IController.cs @@ -1,12 +1,49 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace BizHawk { + // doesn't do what is desired + // http://connect.microsoft.com/VisualStudio/feedback/details/459307/extension-add-methods-are-not-considered-in-c-collection-initializers + /* + public static class UltimateMagic + { + public static void Add(this List + /// default position + /// + public readonly float Mid; + public FloatRange(float Min, float Mid, float Max) + { + this.Min = Min; + this.Mid = Mid; + this.Max = Max; + } + // for terse construction + public static implicit operator FloatRange(float[] f) + { + if (f.Length != 3) + throw new ArgumentException(); + return new FloatRange(f[0], f[1], f[2]); + } + } + public string Name; public List BoolButtons = new List(); public List FloatControls = new List(); + public List FloatRanges = new List(); /// /// copy /// diff --git a/BizHawk.MultiClient/Input/ControllerBinding.cs b/BizHawk.MultiClient/Input/ControllerBinding.cs index 6a1b9827dd..55406e1552 100644 --- a/BizHawk.MultiClient/Input/ControllerBinding.cs +++ b/BizHawk.MultiClient/Input/ControllerBinding.cs @@ -10,9 +10,22 @@ namespace BizHawk.MultiClient 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]; + } + FloatBinds.Add("J5 X", "P1 X Axis"); + FloatBinds.Add("J5 Y", "P1 Y Axis"); } public ControllerDefinition Type { get { return type; } } @@ -24,9 +37,7 @@ namespace BizHawk.MultiClient return buttons[button]; } - // the default state of an unpressed float is assumed to be zero. - // so always return zero here, until we add a float binding infrastructure to Controller - public float GetFloat(string name) { return 0.0f; } + public float GetFloat(string name) { return FloatButtons[name]; } public void UpdateControls(int frame) { } //look for bindings which are activated by the supplied physical button. @@ -72,10 +83,22 @@ namespace BizHawk.MultiClient buttons[kvp.Key] = false; foreach (var bound_button in kvp.Value) { - if(controller[bound_button]) + if (controller[bound_button]) buttons[kvp.Key] = true; } } + foreach (var kvp in FloatBinds) + { + float input = controller.GetFloat(kvp.Key); + string outkey = kvp.Value; + ControllerDefinition.FloatRange range; + if (FloatRanges.TryGetValue(outkey, out range)) + { + // input range is assumed to be -10000,0,10000 + // this is where deadzone, axis flip, sensitivity would be implemented + FloatButtons[outkey] = (input + 10000.0f) * (range.Max - range.Min) / 20000.0f + range.Min; + } + } } /// diff --git a/BizHawk.MultiClient/Input/GamePad.cs b/BizHawk.MultiClient/Input/GamePad.cs index c1968a7525..c5065a140b 100644 --- a/BizHawk.MultiClient/Input/GamePad.cs +++ b/BizHawk.MultiClient/Input/GamePad.cs @@ -87,6 +87,13 @@ namespace BizHawk.MultiClient return; } + public IEnumerable> GetFloats() + { + var pis = typeof(JoystickState).GetProperties(); + foreach (var pi in pis) + yield return new Tuple(pi.Name, 10.0f * (float)(int)pi.GetValue(state, null)); + } + /// FOR DEBUGGING ONLY public JoystickState GetInternalState() { diff --git a/BizHawk.MultiClient/Input/Input.cs b/BizHawk.MultiClient/Input/Input.cs index 22f88e612d..b3a30445e7 100644 --- a/BizHawk.MultiClient/Input/Input.cs +++ b/BizHawk.MultiClient/Input/Input.cs @@ -163,6 +163,7 @@ namespace BizHawk.MultiClient private readonly WorkingDictionary LastState = new WorkingDictionary(); private readonly WorkingDictionary UnpressState = new WorkingDictionary(); private readonly HashSet IgnoreKeys = new HashSet(new[] { "LeftShift", "RightShift", "LeftControl", "RightControl", "LeftAlt", "RightAlt" }); + private readonly List> FloatValues = new List>(); void HandleButton(string button, bool newState) { @@ -254,6 +255,16 @@ namespace BizHawk.MultiClient } } + public List> GetFloats() + { + List> FloatValuesCopy; + lock (FloatValues) + { + FloatValuesCopy = new List>(FloatValues); + } + return FloatValuesCopy; + } + #if WINDOWS void UpdateThreadProc() { @@ -276,23 +287,31 @@ namespace BizHawk.MultiClient else HandleButton(k.ToString(), false); - //analyze xinput - for (int i = 0; i < GamePad360.Devices.Count; i++) + lock (FloatValues) { - var pad = GamePad360.Devices[i]; - string xname = "X" + (i + 1) + " "; - for (int b = 0; b < pad.NumButtons; b++) - HandleButton(xname + pad.ButtonName(b), pad.Pressed(b)); - } + FloatValues.Clear(); - //analyze joysticks - for (int i = 0; i < GamePad.Devices.Count; i++) - { - var pad = GamePad.Devices[i]; - string jname = "J" + (i + 1) + " "; + //analyze xinput + for (int i = 0; i < GamePad360.Devices.Count; i++) + { + var pad = GamePad360.Devices[i]; + string xname = "X" + (i + 1) + " "; + for (int b = 0; b < pad.NumButtons; b++) + HandleButton(xname + pad.ButtonName(b), pad.Pressed(b)); + } + + //analyze joysticks + for (int i = 0; i < GamePad.Devices.Count; i++) + { + var pad = GamePad.Devices[i]; + string jname = "J" + (i + 1) + " "; + + for (int b = 0; b < pad.NumButtons; b++) + HandleButton(jname + pad.ButtonName(b), pad.Pressed(b)); + foreach (var sv in pad.GetFloats()) + FloatValues.Add(new Tuple(jname + sv.Item1, sv.Item2)); + } - for (int b = 0; b < pad.NumButtons; b++) - HandleButton(jname + pad.ButtonName(b), pad.Pressed(b)); } bool swallow = !Global.MainForm.AllowInput; diff --git a/BizHawk.MultiClient/MainForm.cs b/BizHawk.MultiClient/MainForm.cs index dc72deeea5..499bf43885 100644 --- a/BizHawk.MultiClient/MainForm.cs +++ b/BizHawk.MultiClient/MainForm.cs @@ -1928,6 +1928,9 @@ namespace BizHawk.MultiClient } } //foreach event + + // also handle floats + Global.ControllerInputCoalescer.AcceptNewFloats(Input.Instance.GetFloats()); } private void ClearAutohold() diff --git a/BizHawk.MultiClient/movie/InputAdapters.cs b/BizHawk.MultiClient/movie/InputAdapters.cs index 2484d69a95..26351ec336 100644 --- a/BizHawk.MultiClient/movie/InputAdapters.cs +++ b/BizHawk.MultiClient/movie/InputAdapters.cs @@ -101,9 +101,10 @@ namespace BizHawk.MultiClient public ControllerDefinition Type { get; set; } protected WorkingDictionary Buttons = new WorkingDictionary(); + protected WorkingDictionary Floats = new WorkingDictionary(); public virtual bool this[string button] { get { return Buttons[button]; } set { Buttons[button] = value; } } public virtual bool IsPressed(string button) { return this[button]; } - public float GetFloat(string name) { return 0.0f; } //TODO + public float GetFloat(string name) { return Floats[name]; } public void UpdateControls(int frame) { } public IEnumerable> BoolButtons() @@ -118,6 +119,12 @@ namespace BizHawk.MultiClient Buttons[button] = source[button]; } } + + public void AcceptNewFloats(IEnumerable> NewValues) + { + foreach (var sv in NewValues) + Floats[sv.Item1] = sv.Item2; + } } public class ORAdapter : IController