Implemented thumbsticks and trigger caps

This commit is contained in:
Stefanos A 2013-12-24 12:47:09 +01:00 committed by thefiddler
parent 7e5307bd4a
commit 2839db587e
7 changed files with 230 additions and 108 deletions

View file

@ -27,12 +27,15 @@ using System;
namespace OpenTK.Input namespace OpenTK.Input
{ {
internal enum GamePadAxis [Flags]
internal enum GamePadAxes : byte
{ {
LeftX, LeftX = 1 << 0,
LeftY, LeftY = 1 << 1,
RightX, LeftTrigger = 1 << 2,
RightY RightX = 1 << 3,
RightY = 1 << 4,
RightTrigger = 1 << 5,
} }
} }

View file

@ -35,15 +35,17 @@ namespace OpenTK.Input
public struct GamePadCapabilities : IEquatable<GamePadCapabilities> public struct GamePadCapabilities : IEquatable<GamePadCapabilities>
{ {
Buttons buttons; Buttons buttons;
GamePadAxes axes;
byte gamepad_type; byte gamepad_type;
bool is_connected; bool is_connected;
#region Constructors #region Constructors
public GamePadCapabilities(GamePadType type, Buttons buttons, bool is_connected) internal GamePadCapabilities(GamePadType type, GamePadAxes axes, Buttons buttons, bool is_connected)
: this() : this()
{ {
gamepad_type = (byte)type; gamepad_type = (byte)type;
this.axes = axes;
this.buttons = buttons; this.buttons = buttons;
this.is_connected = is_connected; this.is_connected = is_connected;
} }
@ -134,32 +136,32 @@ namespace OpenTK.Input
public bool HasLeftXThumbStick public bool HasLeftXThumbStick
{ {
get { return false; } get { return (axes & GamePadAxes.LeftX) != 0; }
} }
public bool HasLeftYThumbStick public bool HasLeftYThumbStick
{ {
get { return false; } get { return (axes & GamePadAxes.LeftY) != 0; }
} }
public bool HasRightXThumbStick public bool HasRightXThumbStick
{ {
get { return false; } get { return (axes & GamePadAxes.RightX) != 0; }
} }
public bool HasRightYThumbStick public bool HasRightYThumbStick
{ {
get { return false; } get { return (axes & GamePadAxes.RightY) != 0; }
} }
public bool HasLeftTrigger public bool HasLeftTrigger
{ {
get { return false; } get { return (axes & GamePadAxes.LeftTrigger) != 0; }
} }
public bool HasRightTrigger public bool HasRightTrigger
{ {
get { return false; } get { return (axes & GamePadAxes.RightTrigger) != 0; }
} }
public bool HasLeftVibrationMotor public bool HasLeftVibrationMotor
@ -195,8 +197,11 @@ namespace OpenTK.Input
public override string ToString() public override string ToString()
{ {
return String.Format( return String.Format(
"{{Type: {0}; Buttons: {1}; Connected: {2}}}", "{{Type: {0}; Axes: {1}; Buttons: {2}; Connected: {3}}}",
GamePadType, Convert.ToString((int)buttons, 2), IsConnected); GamePadType,
Convert.ToString((int)axes, 2),
Convert.ToString((int)buttons, 2),
IsConnected);
} }
public override int GetHashCode() public override int GetHashCode()

View file

@ -62,6 +62,11 @@ namespace OpenTK.Input
get { return new GamePadDPad(buttons); } get { return new GamePadDPad(buttons); }
} }
public GamePadTriggers Triggers
{
get { return new GamePadTriggers(left_trigger, right_trigger); }
}
public bool IsConnected public bool IsConnected
{ {
get { return is_connected; } get { return is_connected; }
@ -104,23 +109,23 @@ namespace OpenTK.Input
#region Internal Members #region Internal Members
internal void SetAxis(GamePadAxis axis, short value) internal void SetAxis(GamePadAxes axis, short value)
{ {
switch (axis) switch (axis)
{ {
case GamePadAxis.LeftX: case GamePadAxes.LeftX:
left_stick_x = value; left_stick_x = value;
break; break;
case GamePadAxis.LeftY: case GamePadAxes.LeftY:
left_stick_y = value; left_stick_y = value;
break; break;
case GamePadAxis.RightX: case GamePadAxes.RightX:
right_stick_x = value; right_stick_x = value;
break; break;
case GamePadAxis.RightY: case GamePadAxes.RightY:
right_stick_y = value; right_stick_y = value;
break; break;
@ -146,11 +151,17 @@ namespace OpenTK.Input
is_connected = connected; is_connected = connected;
} }
internal void SetTriggers(byte left, byte right)
{
left_trigger = left;
right_trigger = right;
}
#endregion #endregion
#region Private Members #region Private Members
bool IsAxisValid(GamePadAxis axis) bool IsAxisValid(GamePadAxes axis)
{ {
int index = (int)axis; int index = (int)axis;
return index >= 0 && index < GamePad.MaxAxisCount; return index >= 0 && index < GamePad.MaxAxisCount;

View file

@ -41,5 +41,7 @@ namespace OpenTK.Input
BigButtonPad, BigButtonPad,
DrumKit, DrumKit,
GamePad, GamePad,
ArcadePad,
BassGuitar,
} }
} }

View file

@ -258,7 +258,7 @@ namespace OpenTK.Platform.SDL2
int id = ev.Which; int id = ev.Which;
if (IsControllerValid(id)) if (IsControllerValid(id))
{ {
controllers[id].State.SetAxis((GamePadAxis)ev.Axis, ev.Value); controllers[id].State.SetAxis((GamePadAxes)ev.Axis, ev.Value);
} }
else else
{ {

View file

@ -470,10 +470,10 @@ namespace OpenTK.Platform.Windows
info.Flags = JoystickFlags.All; info.Flags = JoystickFlags.All;
UnsafeNativeMethods.joyGetPosEx(index, ref info); UnsafeNativeMethods.joyGetPosEx(index, ref info);
state.SetAxis(GamePadAxis.LeftX, (short)info.XPos); state.SetAxis(GamePadAxes.LeftX, (short)info.XPos);
state.SetAxis(GamePadAxis.LeftY, (short)info.YPos); state.SetAxis(GamePadAxes.LeftY, (short)info.YPos);
state.SetAxis(GamePadAxis.RightX, (short)info.ZPos); state.SetAxis(GamePadAxes.RightX, (short)info.ZPos);
state.SetAxis(GamePadAxis.RightY, (short)info.RPos); state.SetAxis(GamePadAxes.RightY, (short)info.RPos);
//state.SetAxis(GamePadAxis.RightX, (short)info.ZPos); //state.SetAxis(GamePadAxis.RightX, (short)info.ZPos);
//state.SetAxis(GamePadAxis.RightY, (short)info.RPos); //state.SetAxis(GamePadAxis.RightY, (short)info.RPos);

View file

@ -33,41 +33,56 @@ using System.Text;
using OpenTK.Input; using OpenTK.Input;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security; using System.Security;
using System.Diagnostics;
namespace OpenTK.Platform.Windows namespace OpenTK.Platform.Windows
{ {
class XInputJoystick : IGamePadDriver class XInputJoystick : IGamePadDriver, IDisposable
{ {
XInput xinput = new XInput();
#region IGamePadDriver Members #region IGamePadDriver Members
public GamePadState GetState(int index) public GamePadState GetState(int index)
{ {
XInputState xstate; XInputState xstate;
XInput910.GetState((XInputUserIndex)index, out xstate); XInputErrorCode error = xinput.GetState((XInputUserIndex)index, out xstate);
GamePadState state = new GamePadState(); GamePadState state = new GamePadState();
state.SetButton(Buttons.A, (xstate.GamePad.Buttons & XInputButtons.A) != 0); if (error == XInputErrorCode.Success)
state.SetButton(Buttons.B, (xstate.GamePad.Buttons & XInputButtons.B) != 0); {
state.SetButton(Buttons.X, (xstate.GamePad.Buttons & XInputButtons.X) != 0); state.SetConnected(true);
state.SetButton(Buttons.Y, (xstate.GamePad.Buttons & XInputButtons.Y) != 0);
state.SetButton(Buttons.Start, (xstate.GamePad.Buttons & XInputButtons.Start) != 0); state.SetAxis(GamePadAxes.LeftX, xstate.GamePad.ThumbLX);
state.SetButton(Buttons.Back, (xstate.GamePad.Buttons & XInputButtons.Back) != 0); state.SetAxis(GamePadAxes.LeftY, xstate.GamePad.ThumbLY);
//state.SetButton(Buttons.BigButton, (xstate.GamePad.Buttons & XInputButtons.???) != 0); state.SetAxis(GamePadAxes.RightX, xstate.GamePad.ThumbRX);
state.SetButton(Buttons.LeftShoulder, (xstate.GamePad.Buttons & XInputButtons.LeftShoulder) != 0); state.SetAxis(GamePadAxes.RightY, xstate.GamePad.ThumbRY);
state.SetButton(Buttons.RightShoulder, (xstate.GamePad.Buttons & XInputButtons.RightShoulder) != 0);
state.SetButton(Buttons.LeftStick, (xstate.GamePad.Buttons & XInputButtons.LeftThumb) != 0); state.SetTriggers(xstate.GamePad.LeftTrigger, xstate.GamePad.RightTrigger);
state.SetButton(Buttons.RightStick, (xstate.GamePad.Buttons & XInputButtons.RightThumb) != 0);
state.SetButton(Buttons.DPadDown, (xstate.GamePad.Buttons & XInputButtons.DPadDown) != 0); state.SetButton(TranslateButtons(xstate.GamePad.Buttons), true);
state.SetButton(Buttons.DPadUp, (xstate.GamePad.Buttons & XInputButtons.DPadUp) != 0); }
state.SetButton(Buttons.DPadLeft, (xstate.GamePad.Buttons & XInputButtons.DPadLeft) != 0);
state.SetButton(Buttons.DPadRight, (xstate.GamePad.Buttons & XInputButtons.DPadRight) != 0);
return state; return state;
} }
public GamePadCapabilities GetCapabilities(int index) public GamePadCapabilities GetCapabilities(int index)
{ {
throw new NotImplementedException(); XInputDeviceCapabilities xcaps;
XInputErrorCode error = xinput.GetCapabilities(
(XInputUserIndex)index,
XInputCapabilitiesFlags.Default,
out xcaps);
if (error == XInputErrorCode.Success)
{
GamePadType type = TranslateSubType(xcaps.SubType);
Buttons buttons = TranslateButtons(xcaps.GamePad.Buttons);
GamePadAxes axes = TranslateAxes(ref xcaps.GamePad);
return new GamePadCapabilities(type, axes, buttons, true);
}
return new GamePadCapabilities();
} }
public string GetName(int index) public string GetName(int index)
@ -78,6 +93,58 @@ namespace OpenTK.Platform.Windows
#endregion #endregion
#region Private Members #region Private Members
GamePadAxes TranslateAxes(ref XInputGamePad pad)
{
GamePadAxes axes = 0;
axes |= pad.ThumbLX != 0 ? GamePadAxes.LeftX : 0;
axes |= pad.ThumbLY != 0 ? GamePadAxes.LeftY : 0;
axes |= pad.LeftTrigger != 0 ? GamePadAxes.LeftTrigger : 0;
axes |= pad.ThumbRX != 0 ? GamePadAxes.RightX : 0;
axes |= pad.ThumbRY != 0 ? GamePadAxes.RightY : 0;
axes |= pad.RightTrigger != 0 ? GamePadAxes.RightTrigger : 0;
return axes;
}
Buttons TranslateButtons(XInputButtons xbuttons)
{
Buttons buttons = 0;
buttons |= (xbuttons & XInputButtons.A) != 0 ? Buttons.A : 0;
buttons |= (xbuttons & XInputButtons.B) != 0 ? Buttons.B : 0;
buttons |= (xbuttons & XInputButtons.X) != 0 ? Buttons.X : 0;
buttons |= (xbuttons & XInputButtons.Y) != 0 ? Buttons.Y : 0;
buttons |= (xbuttons & XInputButtons.Start) != 0 ? Buttons.Start : 0;
buttons |= (xbuttons & XInputButtons.Back) != 0 ? Buttons.Back : 0;
//buttons |= (xbuttons & XInputButtons.BigButton) != 0 ? Buttons.BigButton : 0;
buttons |= (xbuttons & XInputButtons.LeftShoulder) != 0 ? Buttons.LeftShoulder : 0;
buttons |= (xbuttons & XInputButtons.RightShoulder) != 0 ? Buttons.RightShoulder : 0;
buttons |= (xbuttons & XInputButtons.LeftThumb) != 0 ? Buttons.LeftStick : 0;
buttons |= (xbuttons & XInputButtons.RightThumb) != 0 ? Buttons.RightStick : 0;
buttons |= (xbuttons & XInputButtons.DPadDown) != 0 ? Buttons.DPadDown : 0;
buttons |= (xbuttons & XInputButtons.DPadUp) != 0 ? Buttons.DPadUp : 0;
buttons |= (xbuttons & XInputButtons.DPadLeft) != 0 ? Buttons.DPadLeft : 0;
buttons |= (xbuttons & XInputButtons.DPadRight) != 0 ? Buttons.DPadRight : 0;
return buttons;
}
GamePadType TranslateSubType(XInputDeviceSubType xtype)
{
switch (xtype)
{
case XInputDeviceSubType.ArcadePad: return GamePadType.ArcadePad;
case XInputDeviceSubType.ArcadeStick: return GamePadType.ArcadeStick;
case XInputDeviceSubType.DancePad: return GamePadType.DancePad;
case XInputDeviceSubType.DrumKit: return GamePadType.DrumKit;
case XInputDeviceSubType.FlightStick: return GamePadType.FlightStick;
case XInputDeviceSubType.GamePad: return GamePadType.GamePad;
case XInputDeviceSubType.Guitar: return GamePadType.Guitar;
case XInputDeviceSubType.GuitarAlternate: return GamePadType.AlternateGuitar;
case XInputDeviceSubType.GuitarBass: return GamePadType.BassGuitar;
case XInputDeviceSubType.Wheel: return GamePadType.Wheel;
case XInputDeviceSubType.Unknown:
default:
return GamePadType.Unknown;
}
}
enum XInputErrorCode enum XInputErrorCode
{ {
@ -85,12 +152,12 @@ namespace OpenTK.Platform.Windows
DeviceNotConnected DeviceNotConnected
} }
enum XInputType enum XInputDeviceType : byte
{ {
GamePad GamePad
} }
enum XInputSubType enum XInputDeviceSubType : byte
{ {
Unknown = 0, Unknown = 0,
GamePad = 1, GamePad = 1,
@ -107,10 +174,10 @@ namespace OpenTK.Platform.Windows
enum XInputCapabilities enum XInputCapabilities
{ {
Ffb = 0x0001, ForceFeedback = 0x0001,
Wireless = 0x0002, Wireless = 0x0002,
Voice = 0x0004, Voice = 0x0004,
Pmd = 0x0008, PluginModules = 0x0008,
NoNavigation = 0x0010, NoNavigation = 0x0010,
} }
@ -197,8 +264,8 @@ namespace OpenTK.Platform.Windows
struct XInputDeviceCapabilities struct XInputDeviceCapabilities
{ {
public byte Type; public XInputDeviceType Type;
public byte SubType; public XInputDeviceSubType SubType;
public short Flags; public short Flags;
public XInputGamePad GamePad; public XInputGamePad GamePad;
public XInputVibration Vibration; public XInputVibration Vibration;
@ -210,90 +277,124 @@ namespace OpenTK.Platform.Windows
public XInputBatteryLevel Level; public XInputBatteryLevel Level;
} }
static class XInput910 class XInput : IDisposable
{ {
const string dll = "XINPUT9_1_0"; IntPtr dll;
internal XInput()
{
// Try to load the newest XInput***.dll installed on the system
// The delegates below will be loaded dynamically from that dll
dll = Functions.LoadLibrary("XINPUT1_4");
if (dll == IntPtr.Zero)
dll = Functions.LoadLibrary("XINPUT1_3");
if (dll == IntPtr.Zero)
dll = Functions.LoadLibrary("XINPUT1_2");
if (dll == IntPtr.Zero)
dll = Functions.LoadLibrary("XINPUT1_1");
if (dll == IntPtr.Zero)
dll = Functions.LoadLibrary("XINPUT9_1_0");
if (dll == IntPtr.Zero)
throw new NotSupportedException("XInput was not found on this platform");
// Load the entry points we are interested in from that dll
GetCapabilities = (XInputGetCapabilities)Load("XInputGetCapabilities", typeof(XInputGetCapabilities));
GetState = (XInputGetState)Load("XInputGetState", typeof(XInputGetState));
SetState = (XInputSetState)Load("XInputSetState", typeof(XInputSetState));
}
#region Private Members
Delegate Load(string name, Type type)
{
IntPtr pfunc = Functions.GetProcAddress(dll, name);
if (pfunc != IntPtr.Zero)
return Marshal.GetDelegateForFunctionPointer(pfunc, type);
return null;
}
#endregion
#region Internal Members
internal XInputGetCapabilities GetCapabilities;
internal XInputGetState GetState;
internal XInputSetState SetState;
[SuppressUnmanagedCodeSecurity] [SuppressUnmanagedCodeSecurity]
[DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)] internal delegate XInputErrorCode XInputGetCapabilities(
public static extern XInputErrorCode GetCapabilities(
XInputUserIndex dwUserIndex, XInputUserIndex dwUserIndex,
XInputCapabilitiesFlags dwFlags, XInputCapabilitiesFlags dwFlags,
ref XInputDeviceCapabilities pCapabilities); out XInputDeviceCapabilities pCapabilities);
[SuppressUnmanagedCodeSecurity] [SuppressUnmanagedCodeSecurity]
[DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)] internal delegate XInputErrorCode XInputGetState
public static extern XInputErrorCode GetState
( (
XInputUserIndex dwUserIndex, XInputUserIndex dwUserIndex,
out XInputState pState out XInputState pState
); );
[SuppressUnmanagedCodeSecurity] [SuppressUnmanagedCodeSecurity]
[DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)] internal delegate XInputErrorCode XInputSetState
public static extern XInputErrorCode SetState
( (
XInputUserIndex dwUserIndex, XInputUserIndex dwUserIndex,
ref XInputVibration pVibration ref XInputVibration pVibration
); );
#endregion
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
void Dispose(bool manual)
{
if (manual)
{
if (dll != IntPtr.Zero)
{
Functions.FreeLibrary(dll);
dll = IntPtr.Zero;
}
}
}
#endregion
} }
static class XInput13 #endregion
#region IDisposable Members
public void Dispose()
{ {
const string dll = "XINPUT1_3"; Dispose(true);
GC.SuppressFinalize(this);
[SuppressUnmanagedCodeSecurity]
[DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)]
public static extern XInputErrorCode GetCapabilities(
XInputUserIndex dwUserIndex,
XInputCapabilitiesFlags dwFlags,
ref XInputDeviceCapabilities pCapabilities);
[SuppressUnmanagedCodeSecurity]
[DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)]
public static extern XInputErrorCode GetState
(
XInputUserIndex dwUserIndex,
out XInputState pState
);
[SuppressUnmanagedCodeSecurity]
[DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)]
public static extern XInputErrorCode SetState
(
XInputUserIndex dwUserIndex,
ref XInputVibration pVibration
);
} }
static class XInput14 void Dispose(bool manual)
{ {
const string dll = "XINPUT1_4"; if (manual)
{
[SuppressUnmanagedCodeSecurity] xinput.Dispose();
[DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)] }
public static extern XInputErrorCode GetCapabilities( else
XInputUserIndex dwUserIndex, {
XInputCapabilitiesFlags dwFlags, Debug.Print("{0} leaked, did you forget to call Dispose()?", typeof(XInputJoystick).Name);
ref XInputDeviceCapabilities pCapabilities); }
[SuppressUnmanagedCodeSecurity]
[DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)]
public static extern XInputErrorCode GetState
(
XInputUserIndex dwUserIndex,
out XInputState pState
);
[SuppressUnmanagedCodeSecurity]
[DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)]
public static extern XInputErrorCode SetState
(
XInputUserIndex dwUserIndex,
ref XInputVibration pVibration
);
} }
#if DEBUG
~XInputJoystick()
{
Dispose(false);
}
#endif
#endregion #endregion
} }
} }