mirror of
https://github.com/Ryujinx/Opentk.git
synced 2024-12-26 04:25:30 +00:00
Added support for POV hats with WinMM.
Reversed vertical axes, so that down is -1 and up is +1.
This commit is contained in:
parent
1a0c3ff31f
commit
51e2d93e38
|
@ -163,7 +163,7 @@ namespace OpenTK.Input
|
||||||
: base(id, axes, buttons)
|
: base(id, axes, buttons)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
internal TDetail Details { get { return details; } set { details = value; } }
|
internal TDetail Details;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -30,6 +30,8 @@ using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
|
using System.Security;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace OpenTK.Platform.Windows
|
namespace OpenTK.Platform.Windows
|
||||||
{
|
{
|
||||||
|
@ -40,6 +42,10 @@ namespace OpenTK.Platform.Windows
|
||||||
List<JoystickDevice> sticks = new List<JoystickDevice>();
|
List<JoystickDevice> sticks = new List<JoystickDevice>();
|
||||||
IList<JoystickDevice> sticks_readonly;
|
IList<JoystickDevice> sticks_readonly;
|
||||||
|
|
||||||
|
static readonly string RegistryJoyConfig = @"Joystick%dConfiguration";
|
||||||
|
static readonly string RegistryJoyName = @"Joystick%dOEMName";
|
||||||
|
static readonly string RegstryJoyCurrent = @"CurrentJoystickSettings";
|
||||||
|
|
||||||
bool disposed;
|
bool disposed;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -50,13 +56,13 @@ namespace OpenTK.Platform.Windows
|
||||||
{
|
{
|
||||||
sticks_readonly = sticks.AsReadOnly();
|
sticks_readonly = sticks.AsReadOnly();
|
||||||
|
|
||||||
int number = 0, max_sticks = 25;
|
// WinMM supports up to 16 joysticks.
|
||||||
while (number < max_sticks)
|
int number = 0;
|
||||||
|
while (number < UnsafeNativeMethods.joyGetNumDevs())
|
||||||
{
|
{
|
||||||
JoystickDevice<WinMMJoyDetails> stick = OpenJoystick(number++);
|
JoystickDevice<WinMMJoyDetails> stick = OpenJoystick(number++);
|
||||||
if (stick != null)
|
if (stick != null)
|
||||||
{
|
{
|
||||||
stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons)", number, stick.Axis.Count, stick.Button.Count);
|
|
||||||
sticks.Add(stick);
|
sticks.Add(stick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,21 +81,50 @@ namespace OpenTK.Platform.Windows
|
||||||
if (result != JoystickError.NoError)
|
if (result != JoystickError.NoError)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
stick = new JoystickDevice<WinMMJoyDetails>(number, caps.NumAxes, caps.NumButtons);
|
int num_axes = caps.NumAxes;
|
||||||
stick.Details = new WinMMJoyDetails(caps.NumAxes);
|
if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0)
|
||||||
|
num_axes += 2;
|
||||||
|
|
||||||
|
stick = new JoystickDevice<WinMMJoyDetails>(number, num_axes, caps.NumButtons);
|
||||||
|
stick.Details = new WinMMJoyDetails(num_axes);
|
||||||
|
|
||||||
|
// Make sure to reverse the vertical axes, so that +1 points up and -1 points down.
|
||||||
|
// I don't know if this an artifact of my joypad, but RAxis is the second horizontal and
|
||||||
|
// ZAxis is the second vertical axis here (Saitek P880).
|
||||||
int axis = 0;
|
int axis = 0;
|
||||||
if (axis < caps.NumAxes)
|
if (axis < caps.NumAxes)
|
||||||
{ stick.Details.Min[axis] = caps.XMin; stick.Details.Max[axis] = caps.XMax; axis++; }
|
{ stick.Details.Min[axis] = caps.XMin; stick.Details.Max[axis] = caps.XMax; axis++; }
|
||||||
if (axis < caps.NumAxes)
|
if (axis < caps.NumAxes)
|
||||||
{ stick.Details.Min[axis] = caps.YMin; stick.Details.Max[axis] = caps.YMax; axis++; }
|
{ stick.Details.Min[axis] = caps.YMax; stick.Details.Max[axis] = caps.YMin; axis++; }
|
||||||
if (axis < caps.NumAxes)
|
|
||||||
{ stick.Details.Min[axis] = caps.ZMin; stick.Details.Max[axis] = caps.ZMax; axis++; }
|
|
||||||
if (axis < caps.NumAxes)
|
if (axis < caps.NumAxes)
|
||||||
{ stick.Details.Min[axis] = caps.RMin; stick.Details.Max[axis] = caps.RMax; axis++; }
|
{ stick.Details.Min[axis] = caps.RMin; stick.Details.Max[axis] = caps.RMax; axis++; }
|
||||||
if (axis < caps.NumAxes)
|
if (axis < caps.NumAxes)
|
||||||
|
{ stick.Details.Min[axis] = caps.ZMax; stick.Details.Max[axis] = caps.ZMin; axis++; }
|
||||||
|
if (axis < caps.NumAxes)
|
||||||
{ stick.Details.Min[axis] = caps.UMin; stick.Details.Max[axis] = caps.UMax; axis++; }
|
{ stick.Details.Min[axis] = caps.UMin; stick.Details.Max[axis] = caps.UMax; axis++; }
|
||||||
if (axis < caps.NumAxes)
|
if (axis < caps.NumAxes)
|
||||||
{ stick.Details.Min[axis] = caps.VMin; stick.Details.Max[axis] = caps.VMax; axis++; }
|
{ stick.Details.Min[axis] = caps.VMax; stick.Details.Max[axis] = caps.VMin; axis++; }
|
||||||
|
|
||||||
|
if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0)
|
||||||
|
{
|
||||||
|
stick.Details.PovType = PovType.Exists;
|
||||||
|
if ((caps.Capabilities & JoystCapsFlags.HasPov4Dir) != 0)
|
||||||
|
stick.Details.PovType |= PovType.Discrete;
|
||||||
|
if ((caps.Capabilities & JoystCapsFlags.HasPovContinuous) != 0)
|
||||||
|
stick.Details.PovType |= PovType.Continuous;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to get the device name from the registry. Oh joy!
|
||||||
|
string key_path = String.Format("{0}\\{1}\\{2}", RegistryJoyConfig, caps.RegKey, RegstryJoyCurrent);
|
||||||
|
RegistryKey key = Registry.LocalMachine.OpenSubKey(key_path, false);
|
||||||
|
if (key == null)
|
||||||
|
key = Registry.CurrentUser.OpenSubKey(key_path, false);
|
||||||
|
if (key == null)
|
||||||
|
stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons)", number, stick.Axis.Count, stick.Button.Count);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
key.Close();
|
||||||
|
}
|
||||||
|
|
||||||
return stick;
|
return stick;
|
||||||
}
|
}
|
||||||
|
@ -117,20 +152,76 @@ namespace OpenTK.Platform.Windows
|
||||||
info.Flags = JoystickFlags.All;
|
info.Flags = JoystickFlags.All;
|
||||||
UnsafeNativeMethods.joyGetPosEx(js.Id, ref info);
|
UnsafeNativeMethods.joyGetPosEx(js.Id, ref info);
|
||||||
|
|
||||||
|
int num_axes = js.Axis.Count;
|
||||||
|
if ((js.Details.PovType & PovType.Exists) != 0)
|
||||||
|
num_axes -= 2; // Because the last two axis are used for POV input.
|
||||||
|
|
||||||
int axis = 0;
|
int axis = 0;
|
||||||
if (axis < js.Axis.Count)
|
if (axis < num_axes)
|
||||||
{ js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.XPos, axis)); axis++; }
|
{ js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.XPos, axis)); axis++; }
|
||||||
if (axis < js.Axis.Count)
|
if (axis < num_axes)
|
||||||
{ js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.YPos, axis)); axis++; }
|
{ js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.YPos, axis)); axis++; }
|
||||||
if (axis < js.Axis.Count)
|
if (axis < num_axes)
|
||||||
{ js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.ZPos, axis)); axis++; }
|
{ js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.ZPos, axis)); axis++; }
|
||||||
if (axis < js.Axis.Count)
|
if (axis < num_axes)
|
||||||
{ js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.RPos, axis)); axis++; }
|
{ js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.RPos, axis)); axis++; }
|
||||||
if (axis < js.Axis.Count)
|
if (axis < num_axes)
|
||||||
{ js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.UPos, axis)); axis++; }
|
{ js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.UPos, axis)); axis++; }
|
||||||
if (axis < js.Axis.Count)
|
if (axis < num_axes)
|
||||||
{ js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.VPos, axis)); axis++; }
|
{ js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.VPos, axis)); axis++; }
|
||||||
|
|
||||||
|
if ((js.Details.PovType & PovType.Exists) != 0)
|
||||||
|
{
|
||||||
|
float x = 0, y = 0;
|
||||||
|
|
||||||
|
// A discrete POV returns specific values for left, right, etc.
|
||||||
|
// A continuous POV returns an integer indicating an angle in degrees * 100, e.g. 18000 == 180.00 degrees.
|
||||||
|
// The vast majority of joysticks have discrete POVs, so we'll treat all of them as discrete for simplicity.
|
||||||
|
if ((JoystickPovPosition)info.Pov != JoystickPovPosition.Centered)
|
||||||
|
{
|
||||||
|
if (info.Pov > (int)JoystickPovPosition.Left || info.Pov < (int)JoystickPovPosition.Right)
|
||||||
|
{ y = 1; }
|
||||||
|
if ((info.Pov > (int)JoystickPovPosition.Forward) && (info.Pov < (int)JoystickPovPosition.Backward))
|
||||||
|
{ x = 1; }
|
||||||
|
if ((info.Pov > (int)JoystickPovPosition.Right) && (info.Pov < (int)JoystickPovPosition.Left))
|
||||||
|
{ y = -1; }
|
||||||
|
if (info.Pov > (int)JoystickPovPosition.Backward)
|
||||||
|
{ x = -1; }
|
||||||
|
}
|
||||||
|
//if ((js.Details.PovType & PovType.Discrete) != 0)
|
||||||
|
//{
|
||||||
|
// if ((JoystickPovPosition)info.Pov == JoystickPovPosition.Centered)
|
||||||
|
// { x = 0; y = 0; }
|
||||||
|
// else if ((JoystickPovPosition)info.Pov == JoystickPovPosition.Forward)
|
||||||
|
// { x = 0; y = -1; }
|
||||||
|
// else if ((JoystickPovPosition)info.Pov == JoystickPovPosition.Left)
|
||||||
|
// { x = -1; y = 0; }
|
||||||
|
// else if ((JoystickPovPosition)info.Pov == JoystickPovPosition.Backward)
|
||||||
|
// { x = 0; y = 1; }
|
||||||
|
// else if ((JoystickPovPosition)info.Pov == JoystickPovPosition.Right)
|
||||||
|
// { x = 1; y = 0; }
|
||||||
|
//}
|
||||||
|
//else if ((js.Details.PovType & PovType.Continuous) != 0)
|
||||||
|
//{
|
||||||
|
// if ((JoystickPovPosition)info.Pov == JoystickPovPosition.Centered)
|
||||||
|
// {
|
||||||
|
// // This approach moves the hat on a circle, not a square as it should.
|
||||||
|
// float angle = (float)(System.Math.PI * info.Pov / 18000.0 + System.Math.PI / 2);
|
||||||
|
// x = (float)System.Math.Cos(angle);
|
||||||
|
// y = (float)System.Math.Sin(angle);
|
||||||
|
// if (x < 0.001)
|
||||||
|
// x = 0;
|
||||||
|
// if (y < 0.001)
|
||||||
|
// y = 0;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
// throw new NotImplementedException("Please post an issue report at http://www.opentk.com/issues");
|
||||||
|
|
||||||
|
js.SetAxis((JoystickAxis)axis++, x);
|
||||||
|
js.SetAxis((JoystickAxis)axis++, y);
|
||||||
|
}
|
||||||
|
|
||||||
int button = 0;
|
int button = 0;
|
||||||
while (button < js.Button.Count)
|
while (button < js.Button.Count)
|
||||||
{
|
{
|
||||||
|
@ -195,13 +286,32 @@ namespace OpenTK.Platform.Windows
|
||||||
//MM_InvalidParameter = 11
|
//MM_InvalidParameter = 11
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum JoystCapsFlags
|
||||||
|
{
|
||||||
|
HasZ = 0x1,
|
||||||
|
HasR = 0x2,
|
||||||
|
HasU = 0x4,
|
||||||
|
HasV = 0x8,
|
||||||
|
HasPov = 0x16,
|
||||||
|
HasPov4Dir = 0x32,
|
||||||
|
HasPovContinuous = 0x64
|
||||||
|
}
|
||||||
|
|
||||||
|
enum JoystickPovPosition : ushort
|
||||||
|
{
|
||||||
|
Centered = 0xFFFF,
|
||||||
|
Forward = 0,
|
||||||
|
Right = 9000,
|
||||||
|
Backward = 18000,
|
||||||
|
Left = 27000
|
||||||
|
}
|
||||||
struct JoyCaps
|
struct JoyCaps
|
||||||
{
|
{
|
||||||
public ushort Mid;
|
public ushort Mid;
|
||||||
public ushort Pid;
|
public ushort ProductId;
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
||||||
public string Pname;
|
public string ProductName;
|
||||||
public int XMin;
|
public int XMin;
|
||||||
public int XMax;
|
public int XMax;
|
||||||
public int YMin;
|
public int YMin;
|
||||||
|
@ -217,7 +327,7 @@ namespace OpenTK.Platform.Windows
|
||||||
public int UMax;
|
public int UMax;
|
||||||
public int VMin;
|
public int VMin;
|
||||||
public int VMax;
|
public int VMax;
|
||||||
public int Caps;
|
public JoystCapsFlags Capabilities;
|
||||||
public int MaxAxes;
|
public int MaxAxes;
|
||||||
public int NumAxes;
|
public int NumAxes;
|
||||||
public int MaxButtons;
|
public int MaxButtons;
|
||||||
|
@ -261,10 +371,25 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
static class UnsafeNativeMethods
|
static class UnsafeNativeMethods
|
||||||
{
|
{
|
||||||
[DllImport("Winmm.dll")]
|
[DllImport("Winmm.dll"), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern JoystickError joyGetDevCaps(int uJoyID, out JoyCaps pjc, int cbjc);
|
public static extern JoystickError joyGetDevCaps(int uJoyID, out JoyCaps pjc, int cbjc);
|
||||||
[DllImport("Winmm.dll")]
|
[DllImport("Winmm.dll"), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern uint joyGetPosEx(int uJoyID, ref JoyInfoEx pji);
|
public static extern uint joyGetPosEx(int uJoyID, ref JoyInfoEx pji);
|
||||||
|
[DllImport("Winmm.dll"), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern int joyGetNumDevs();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region enum PovType
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum PovType
|
||||||
|
{
|
||||||
|
None = 0x0,
|
||||||
|
Exists = 0x1,
|
||||||
|
Discrete = 0x2,
|
||||||
|
Continuous = 0x4
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -274,11 +399,13 @@ namespace OpenTK.Platform.Windows
|
||||||
struct WinMMJoyDetails
|
struct WinMMJoyDetails
|
||||||
{
|
{
|
||||||
public readonly float[] Min, Max; // Minimum and maximum offset of each axis.
|
public readonly float[] Min, Max; // Minimum and maximum offset of each axis.
|
||||||
|
public PovType PovType;
|
||||||
|
|
||||||
public WinMMJoyDetails(int num_axes)
|
public WinMMJoyDetails(int num_axes)
|
||||||
{
|
{
|
||||||
Min = new float[num_axes];
|
Min = new float[num_axes];
|
||||||
Max = new float[num_axes];
|
Max = new float[num_axes];
|
||||||
|
PovType = PovType.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float CalculateOffset(float pos, int axis)
|
public float CalculateOffset(float pos, int axis)
|
||||||
|
|
Loading…
Reference in a new issue