diff --git a/Source/OpenTK/Input/JoystickHatState.cs b/Source/OpenTK/Input/JoystickHatState.cs
index 4e92dedb..63a3a943 100644
--- a/Source/OpenTK/Input/JoystickHatState.cs
+++ b/Source/OpenTK/Input/JoystickHatState.cs
@@ -34,7 +34,7 @@ namespace OpenTK.Input
///
/// Describes the state of a joystick hat.
///
- public struct JoystickHatState
+ public struct JoystickHatState : IEquatable
{
HatPosition position;
@@ -113,6 +113,58 @@ namespace OpenTK.Input
Position == HatPosition.DownRight;
}
}
+
+ ///
+ /// Returns a that represents the current .
+ ///
+ /// A that represents the current .
+ public override string ToString()
+ {
+ return String.Format(
+ "{{{0}{1}{2}{3}}}",
+ IsUp ? "U" : String.Empty,
+ IsLeft ? "L" : String.Empty,
+ IsDown ? "D" : String.Empty,
+ IsRight ? "R" : String.Empty);
+ }
+
+ ///
+ /// Serves as a hash function for a object.
+ ///
+ /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
+ /// hash table.
+ public override int GetHashCode()
+ {
+ return Position.GetHashCode();
+ }
+
+ ///
+ /// Determines whether the specified is equal to the current .
+ ///
+ /// The to compare with the current .
+ /// true if the specified is equal to the current
+ /// ; otherwise, false.
+ public override bool Equals(object obj)
+ {
+ return
+ obj is JoystickHatState &&
+ Equals((JoystickHatState)obj);
+ }
+
+ #region IEquatable implementation
+
+ ///
+ /// Determines whether the specified is equal to the current .
+ ///
+ /// The to compare with the current .
+ /// true if the specified is equal to the current
+ /// ; otherwise, false.
+ public bool Equals(JoystickHatState other)
+ {
+ return Position == other.Position;
+ }
+
+ #endregion
}
}
diff --git a/Source/OpenTK/Input/JoystickState.cs b/Source/OpenTK/Input/JoystickState.cs
index 1ef3d976..a2dd64cc 100644
--- a/Source/OpenTK/Input/JoystickState.cs
+++ b/Source/OpenTK/Input/JoystickState.cs
@@ -145,9 +145,10 @@ namespace OpenTK.Input
sb.Append(String.Format("{0:f4}", GetAxis(JoystickAxis.Axis0 + i)));
}
return String.Format(
- "{{Axes:{0}; Buttons: {1}; IsConnected: {2}}}",
+ "{{Axes:{0}; Buttons: {1}; Hat: {2}; IsConnected: {3}}}",
sb.ToString(),
Convert.ToString((int)buttons, 2).PadLeft(16, '0'),
+ hat0,
IsConnected);
}
@@ -303,6 +304,11 @@ namespace OpenTK.Input
{
equals &= GetAxisUnsafe(i) == other.GetAxisUnsafe(i);
}
+ for (int i = 0; equals && i < MaxHats; i++)
+ {
+ JoystickHat hat = JoystickHat.Hat0 + i;
+ equals &= GetHat(hat).Equals(other.GetHat(hat));
+ }
return equals;
}
diff --git a/Source/OpenTK/Platform/LegacyJoystickDriver.cs b/Source/OpenTK/Platform/LegacyJoystickDriver.cs
index 4b2f39cc..b58c21f2 100644
--- a/Source/OpenTK/Platform/LegacyJoystickDriver.cs
+++ b/Source/OpenTK/Platform/LegacyJoystickDriver.cs
@@ -65,7 +65,10 @@ namespace OpenTK.Platform
if (caps.IsConnected && joysticks[i].Description == DisconnectedName)
{
// New joystick connected
- joysticks[i] = new LegacyJoystickDevice(i, caps.AxisCount, caps.ButtonCount);
+ joysticks[i] = new LegacyJoystickDevice(
+ i,
+ caps.AxisCount + 2 * caps.HatCount,
+ caps.ButtonCount);
//device.Description = Joystick.GetName(i);
joysticks[i].Description = ConnectedName;
@@ -78,16 +81,41 @@ namespace OpenTK.Platform
}
JoystickState state = Joystick.GetState(i);
- for (int axis_index = 0; axis_index < (int)caps.AxisCount; axis_index++)
+ for (int axis_index = 0; axis_index < caps.AxisCount; axis_index++)
{
JoystickAxis axis = JoystickAxis.Axis0 + axis_index;
joysticks[i].SetAxis(axis, state.GetAxis(axis));
}
- for (int button_index = 0; button_index < (int)caps.ButtonCount; button_index++)
+ for (int button_index = 0; button_index < caps.ButtonCount; button_index++)
{
JoystickButton button = JoystickButton.Button0 + button_index;
joysticks[i].SetButton(button, state.GetButton(button) == ButtonState.Pressed);
}
+ for (int hat_index = 0; hat_index < caps.HatCount; hat_index++)
+ {
+ // LegacyJoystickDriver report hats as pairs of axes
+ // Make sure we have enough axes left for this mapping
+ int axis_index = caps.AxisCount + 2 * hat_index;
+ if (axis_index < JoystickState.MaxAxes)
+ {
+ JoystickHat hat = JoystickHat.Hat0 + hat_index;
+ JoystickHatState hat_state = state.GetHat(hat);
+ JoystickAxis axis = JoystickAxis.Axis0 + axis_index;
+ float x = 0;
+ float y = 0;
+ if (hat_state.IsDown)
+ y--;
+ if (hat_state.IsUp)
+ y++;
+ if (hat_state.IsLeft)
+ x--;
+ if (hat_state.IsRight)
+ x++;
+
+ joysticks[i].SetAxis(axis, x);
+ joysticks[i].SetAxis(axis + 1, y);
+ }
+ }
}
}
diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs
index 77b14cfe..adcdf1df 100644
--- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs
+++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs
@@ -131,8 +131,16 @@ namespace OpenTK.Platform.Windows
// Make sure to reverse the vertical axes, so that +1 points up and -1 points down.
for (int axis = 0; axis < caps.NumAxes; axis++)
{
- stick.Details.Min[axis] = caps.GetMin(axis);
- stick.Details.Max[axis] = caps.GetMax(axis);
+ if (axis % 2 == 1)
+ {
+ stick.Details.Min[axis] = caps.GetMax(axis);
+ stick.Details.Max[axis] = caps.GetMin(axis);
+ }
+ else
+ {
+ stick.Details.Min[axis] = caps.GetMin(axis);
+ stick.Details.Max[axis] = caps.GetMax(axis);
+ }
}
if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0)
@@ -389,21 +397,42 @@ namespace OpenTK.Platform.Windows
else
{
// Use joyGetPosEx
- JoyInfoEx info = new JoyInfoEx();
- info.Size = JoyInfoEx.SizeInBytes;
- info.Flags = JoystickFlags.All;
+ JoyInfoEx info_ex = new JoyInfoEx();
+ info_ex.Size = JoyInfoEx.SizeInBytes;
+ info_ex.Flags = JoystickFlags.All;
- JoystickError result = UnsafeNativeMethods.joyGetPosEx(device_index, ref info);
+ JoystickError result = UnsafeNativeMethods.joyGetPosEx(device_index, ref info_ex);
if (result == JoystickError.NoError)
{
for (int i = 0; i < stick.Details.Capabilities.AxisCount; i++)
{
- state.SetAxis(JoystickAxis.Axis0 + i, CalculateOffset(info.GetAxis(i), stick.Details.Min[i], stick.Details.Max[i]));
+ state.SetAxis(JoystickAxis.Axis0 + i, CalculateOffset(info_ex.GetAxis(i), stick.Details.Min[i], stick.Details.Max[i]));
}
for (int i = 0; i < stick.Details.Capabilities.ButtonCount; i++)
{
- state.SetButton(JoystickButton.Button0 + i, (info.Buttons & 1 << i) != 0);
+ state.SetButton(JoystickButton.Button0 + i, (info_ex.Buttons & 1 << i) != 0);
+ }
+
+ for (int i = 0; i < stick.Details.Capabilities.HatCount; i++)
+ {
+ // 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_ex.Pov != JoystickPovPosition.Centered)
+ {
+ HatPosition hatpos = HatPosition.Centered;
+ if (info_ex.Pov < 4500 || info_ex.Pov >= 31500)
+ hatpos |= HatPosition.Up;
+ if (info_ex.Pov >= 4500 && info_ex.Pov < 13500)
+ hatpos |= HatPosition.Right;
+ if (info_ex.Pov >= 13500 && info_ex.Pov < 22500)
+ hatpos |= HatPosition.Down;
+ if (info_ex.Pov >= 22500 && info_ex.Pov < 31500)
+ hatpos |= HatPosition.Left;
+
+ state.SetHat(JoystickHat.Hat0 + i, new JoystickHatState(hatpos));
+ }
}
state.SetIsConnected(true);