2014-06-22 17:41:13 +00:00
|
|
|
|
using System;
|
2014-07-06 16:44:50 +00:00
|
|
|
|
using System.Drawing;
|
2014-06-22 17:41:13 +00:00
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
2014-06-24 16:36:19 +00:00
|
|
|
|
using BizHawk.Emulation.Common;
|
2014-10-09 02:19:10 +00:00
|
|
|
|
using BizHawk.Client.Common;
|
2014-07-06 16:44:50 +00:00
|
|
|
|
using System.Windows;
|
2016-01-23 15:16:19 +00:00
|
|
|
|
using BizHawk.Common.NumberExtensions;
|
2014-06-24 16:36:19 +00:00
|
|
|
|
|
2014-06-22 17:41:13 +00:00
|
|
|
|
namespace BizHawk.Client.EmuHawk
|
|
|
|
|
{
|
|
|
|
|
public partial class VirtualPadAnalogStick : UserControl, IVirtualPadControl
|
|
|
|
|
{
|
2016-01-23 15:16:19 +00:00
|
|
|
|
#region Fields
|
|
|
|
|
|
2014-06-29 03:14:40 +00:00
|
|
|
|
private bool _programmaticallyUpdatingNumerics;
|
|
|
|
|
private bool _readonly;
|
2016-06-14 17:31:40 +00:00
|
|
|
|
private int rangeAverageX; //for coordinate transformation when non orthogonal (like PSX for example)
|
|
|
|
|
private int rangeAverageY;
|
2014-06-24 16:36:19 +00:00
|
|
|
|
|
2016-01-23 15:16:19 +00:00
|
|
|
|
private EventHandler manualXYValueChangedEventHandler;
|
|
|
|
|
private EventHandler polarNumericChangedEventHandler;
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2014-06-22 17:41:13 +00:00
|
|
|
|
public VirtualPadAnalogStick()
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
2014-10-10 00:07:45 +00:00
|
|
|
|
AnalogStick.ClearCallback = ClearCallback;
|
2016-01-23 15:16:19 +00:00
|
|
|
|
|
|
|
|
|
manualXYValueChangedEventHandler = new EventHandler(ManualXY_ValueChanged);
|
|
|
|
|
polarNumericChangedEventHandler = new EventHandler(PolarNumeric_Changed);
|
|
|
|
|
|
|
|
|
|
ManualX.ValueChanged += manualXYValueChangedEventHandler;
|
|
|
|
|
ManualY.ValueChanged += manualXYValueChangedEventHandler;
|
|
|
|
|
manualR.ValueChanged += polarNumericChangedEventHandler;
|
|
|
|
|
manualTheta.ValueChanged += polarNumericChangedEventHandler;
|
2014-06-22 17:41:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-07-20 02:45:51 +00:00
|
|
|
|
public float[] RangeX = new float[] { -128f, 0.0f, 127f };
|
|
|
|
|
public float[] RangeY = new float[] { -128f, 0.0f, 127f };
|
|
|
|
|
|
2014-07-06 16:44:50 +00:00
|
|
|
|
|
2014-06-22 17:41:13 +00:00
|
|
|
|
private void VirtualPadAnalogStick_Load(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
AnalogStick.Name = Name;
|
2014-06-24 17:30:14 +00:00
|
|
|
|
AnalogStick.XName = Name;
|
|
|
|
|
AnalogStick.YName = Name.Replace("X", "Y"); // TODO: allow schema to dictate this but this is a convenient default
|
2015-07-20 02:45:51 +00:00
|
|
|
|
AnalogStick.SetRangeX(RangeX);
|
|
|
|
|
AnalogStick.SetRangeY(RangeY);
|
2014-06-29 20:32:28 +00:00
|
|
|
|
|
2015-07-20 02:45:51 +00:00
|
|
|
|
ManualX.Minimum = (decimal)RangeX[0];
|
|
|
|
|
ManualX.Maximum = (decimal)RangeX[2];
|
2014-06-29 20:32:28 +00:00
|
|
|
|
|
2015-07-20 02:45:51 +00:00
|
|
|
|
ManualY.Minimum = (decimal)RangeX[0];
|
|
|
|
|
ManualY.Maximum = (decimal)RangeX[2];
|
2014-06-29 20:32:28 +00:00
|
|
|
|
|
2015-07-20 02:45:51 +00:00
|
|
|
|
MaxXNumeric.Minimum = 1;
|
|
|
|
|
MaxXNumeric.Maximum = 100;
|
|
|
|
|
MaxXNumeric.Value = 100;
|
2014-07-06 16:44:50 +00:00
|
|
|
|
|
2015-07-20 02:45:51 +00:00
|
|
|
|
MaxYNumeric.Minimum = 1;
|
|
|
|
|
MaxYNumeric.Maximum = 100;
|
|
|
|
|
MaxYNumeric.Value = 100; // Note: these trigger change events that change the analog stick too
|
2016-06-14 17:31:40 +00:00
|
|
|
|
|
|
|
|
|
rangeAverageX = (int)((RangeX[0] + RangeX[2]) / 2);
|
|
|
|
|
rangeAverageY = (int)((RangeY[0] + RangeY[2]) / 2);
|
2014-06-22 17:41:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-25 17:26:07 +00:00
|
|
|
|
#region IVirtualPadControl Implementation
|
|
|
|
|
|
2014-07-26 17:11:47 +00:00
|
|
|
|
public void UpdateValues()
|
|
|
|
|
{
|
|
|
|
|
// Nothing to do
|
|
|
|
|
// This tool already draws as necessary
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-24 16:36:19 +00:00
|
|
|
|
public void Set(IController controller)
|
|
|
|
|
{
|
2014-06-24 17:30:14 +00:00
|
|
|
|
AnalogStick.Set(controller);
|
|
|
|
|
SetNumericsFromAnalog();
|
2014-06-24 16:36:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-10-10 00:07:45 +00:00
|
|
|
|
public void ClearCallback()
|
2014-06-22 17:41:13 +00:00
|
|
|
|
{
|
|
|
|
|
ManualX.Value = 0;
|
|
|
|
|
ManualY.Value = 0;
|
2016-01-23 15:16:19 +00:00
|
|
|
|
manualR.Value = 0;
|
|
|
|
|
manualTheta.Value = 0;
|
2014-10-09 02:19:10 +00:00
|
|
|
|
//see HOOMOO
|
|
|
|
|
Global.AutofireStickyXORAdapter.SetSticky(AnalogStick.XName, false);
|
|
|
|
|
Global.StickyXORAdapter.Unset(AnalogStick.XName);
|
|
|
|
|
Global.AutofireStickyXORAdapter.SetSticky(AnalogStick.YName, false);
|
|
|
|
|
Global.StickyXORAdapter.Unset(AnalogStick.YName);
|
2014-10-10 00:07:45 +00:00
|
|
|
|
AnalogStick.HasValue = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Clear()
|
|
|
|
|
{
|
|
|
|
|
AnalogStick.Clear();
|
2014-06-22 17:41:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-25 17:26:07 +00:00
|
|
|
|
public bool ReadOnly
|
|
|
|
|
{
|
2014-06-26 03:30:56 +00:00
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _readonly;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
2014-06-26 20:36:33 +00:00
|
|
|
|
if (_readonly != value)
|
|
|
|
|
{
|
|
|
|
|
XLabel.Enabled =
|
|
|
|
|
ManualX.Enabled =
|
|
|
|
|
YLabel.Enabled =
|
|
|
|
|
ManualY.Enabled =
|
|
|
|
|
MaxLabel.Enabled =
|
|
|
|
|
MaxXNumeric.Enabled =
|
|
|
|
|
MaxYNumeric.Enabled =
|
2016-01-23 15:16:19 +00:00
|
|
|
|
manualR.Enabled =
|
|
|
|
|
rLabel.Enabled =
|
|
|
|
|
manualTheta.Enabled =
|
|
|
|
|
thetaLabel.Enabled =
|
2014-06-26 20:36:33 +00:00
|
|
|
|
!value;
|
2014-06-26 03:30:56 +00:00
|
|
|
|
|
2016-01-23 15:16:19 +00:00
|
|
|
|
AnalogStick.ReadOnly =
|
2014-06-26 20:36:33 +00:00
|
|
|
|
_readonly =
|
|
|
|
|
value;
|
2016-01-23 15:16:19 +00:00
|
|
|
|
|
2014-06-26 03:30:56 +00:00
|
|
|
|
Refresh();
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-06-25 17:26:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2014-06-29 23:43:31 +00:00
|
|
|
|
public void Bump(int? x, int? y)
|
|
|
|
|
{
|
|
|
|
|
if (x.HasValue)
|
|
|
|
|
{
|
|
|
|
|
AnalogStick.HasValue = true;
|
|
|
|
|
AnalogStick.X += x.Value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (y.HasValue)
|
|
|
|
|
{
|
|
|
|
|
AnalogStick.HasValue = true;
|
|
|
|
|
AnalogStick.Y += y.Value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetNumericsFromAnalog();
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-29 14:42:20 +00:00
|
|
|
|
public void SetPrevious(IController previous)
|
|
|
|
|
{
|
|
|
|
|
AnalogStick.SetPrevious(previous);
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-23 15:16:19 +00:00
|
|
|
|
private void ManualXY_ValueChanged(object sender, EventArgs e)
|
2014-06-22 17:41:13 +00:00
|
|
|
|
{
|
|
|
|
|
SetAnalogControlFromNumerics();
|
|
|
|
|
}
|
2016-01-23 15:16:19 +00:00
|
|
|
|
private void MaxManualXY_ValueChanged(object sender, EventArgs e)
|
2014-06-22 17:41:13 +00:00
|
|
|
|
{
|
2016-01-23 15:16:19 +00:00
|
|
|
|
SetAnalogMaxFromNumerics();
|
2014-06-22 17:41:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-01-23 15:16:19 +00:00
|
|
|
|
private void PolarNumeric_Changed(object sender, EventArgs e)
|
2014-06-22 17:41:13 +00:00
|
|
|
|
{
|
2016-01-23 15:16:19 +00:00
|
|
|
|
ManualX.ValueChanged -= manualXYValueChangedEventHandler;
|
|
|
|
|
ManualY.ValueChanged -= manualXYValueChangedEventHandler;
|
2014-06-22 17:41:13 +00:00
|
|
|
|
|
2016-06-14 17:31:40 +00:00
|
|
|
|
ManualX.Value = Math.Ceiling(manualR.Value * (decimal)Math.Cos(Math.PI * (double)manualTheta.Value / 180)).Clamp(-127, 127) + rangeAverageX;
|
|
|
|
|
ManualY.Value = Math.Ceiling(manualR.Value * (decimal)Math.Sin(Math.PI * (double)manualTheta.Value / 180)).Clamp(-127, 127) + rangeAverageY;
|
2016-01-23 15:16:19 +00:00
|
|
|
|
|
|
|
|
|
AnalogStick.X = (int)ManualX.Value;
|
|
|
|
|
AnalogStick.Y = (int)ManualY.Value;
|
2016-06-14 17:31:40 +00:00
|
|
|
|
|
2016-01-23 15:16:19 +00:00
|
|
|
|
AnalogStick.HasValue = true;
|
|
|
|
|
AnalogStick.Refresh();
|
|
|
|
|
|
|
|
|
|
ManualX.ValueChanged += manualXYValueChangedEventHandler;
|
|
|
|
|
ManualY.ValueChanged += manualXYValueChangedEventHandler;
|
2014-06-22 17:41:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SetAnalogControlFromNumerics()
|
|
|
|
|
{
|
|
|
|
|
if (!_programmaticallyUpdatingNumerics)
|
|
|
|
|
{
|
|
|
|
|
AnalogStick.X = (int)ManualX.Value;
|
|
|
|
|
AnalogStick.Y = (int)ManualY.Value;
|
|
|
|
|
AnalogStick.HasValue = true;
|
|
|
|
|
AnalogStick.Refresh();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SetNumericsFromAnalog()
|
|
|
|
|
{
|
2016-03-21 21:13:28 +00:00
|
|
|
|
_programmaticallyUpdatingNumerics = true;
|
|
|
|
|
|
2014-06-22 17:41:13 +00:00
|
|
|
|
if (AnalogStick.HasValue)
|
|
|
|
|
{
|
2014-07-26 17:22:58 +00:00
|
|
|
|
// Setting .Value of a numeric causes a draw, so avoid it unless necessary
|
|
|
|
|
if (ManualX.Value != AnalogStick.X)
|
|
|
|
|
{
|
|
|
|
|
ManualX.Value = AnalogStick.X;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ManualY.Value != AnalogStick.Y)
|
|
|
|
|
{
|
|
|
|
|
ManualY.Value = AnalogStick.Y;
|
|
|
|
|
}
|
2014-06-22 17:41:13 +00:00
|
|
|
|
}
|
2014-07-26 13:59:06 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2014-07-26 17:22:58 +00:00
|
|
|
|
if (ManualX.Value != 0)
|
|
|
|
|
{
|
|
|
|
|
ManualX.Value = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ManualY.Value != 0)
|
|
|
|
|
{
|
|
|
|
|
ManualY.Value = 0;
|
|
|
|
|
}
|
2014-07-26 13:59:06 +00:00
|
|
|
|
}
|
2016-01-23 15:16:19 +00:00
|
|
|
|
|
|
|
|
|
manualR.ValueChanged -= polarNumericChangedEventHandler;
|
|
|
|
|
manualTheta.ValueChanged -= polarNumericChangedEventHandler;
|
|
|
|
|
|
2016-06-14 17:31:40 +00:00
|
|
|
|
manualR.Value = (decimal)Math.Sqrt(Math.Pow(AnalogStick.X - rangeAverageX, 2) + Math.Pow(AnalogStick.Y - rangeAverageY, 2));
|
|
|
|
|
manualTheta.Value = (decimal)(Math.Atan2(AnalogStick.Y - rangeAverageY, AnalogStick.X - rangeAverageX) * (180 / Math.PI));
|
2016-01-23 15:16:19 +00:00
|
|
|
|
|
|
|
|
|
manualR.ValueChanged += polarNumericChangedEventHandler;
|
|
|
|
|
manualTheta.ValueChanged += polarNumericChangedEventHandler;
|
2016-03-21 21:13:28 +00:00
|
|
|
|
|
|
|
|
|
_programmaticallyUpdatingNumerics = false;
|
2014-06-22 17:41:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AnalogStick_MouseDown(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
2014-06-26 03:30:56 +00:00
|
|
|
|
if (!ReadOnly)
|
|
|
|
|
{
|
|
|
|
|
_programmaticallyUpdatingNumerics = true;
|
|
|
|
|
SetNumericsFromAnalog();
|
|
|
|
|
_programmaticallyUpdatingNumerics = false;
|
|
|
|
|
}
|
2014-06-22 17:41:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AnalogStick_MouseMove(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
2014-06-26 03:30:56 +00:00
|
|
|
|
if (!ReadOnly)
|
|
|
|
|
{
|
|
|
|
|
_programmaticallyUpdatingNumerics = true;
|
|
|
|
|
SetNumericsFromAnalog();
|
|
|
|
|
_programmaticallyUpdatingNumerics = false;
|
|
|
|
|
}
|
2014-06-22 17:41:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SetAnalogMaxFromNumerics()
|
|
|
|
|
{
|
|
|
|
|
if (!_programmaticallyUpdatingNumerics)
|
|
|
|
|
{
|
2015-07-20 02:45:51 +00:00
|
|
|
|
//blehh,... this damn feature
|
|
|
|
|
AnalogStick.SetUserRange((float)MaxXNumeric.Value, (float)MaxYNumeric.Value);
|
2014-06-22 17:41:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|