improve gamepad init and support hotplugging

pull/20/head
cosmonaut 2022-07-13 11:53:09 -07:00
parent 646e5e9283
commit f6fc80804e
6 changed files with 104 additions and 50 deletions

View File

@ -205,6 +205,14 @@ namespace MoonWorks
case SDL.SDL_EventType.SDL_DROPFILE: case SDL.SDL_EventType.SDL_DROPFILE:
HandleFileDrop(_event); HandleFileDrop(_event);
break; break;
case SDL.SDL_EventType.SDL_CONTROLLERDEVICEADDED:
HandleControllerAdded(_event);
break;
case SDL.SDL_EventType.SDL_CONTROLLERDEVICEREMOVED:
HandleControllerRemoved(_event);
break;
} }
} }
} }
@ -244,6 +252,22 @@ namespace MoonWorks
DropFile(filePath); DropFile(filePath);
} }
private void HandleControllerAdded(SDL.SDL_Event evt)
{
var index = evt.cdevice.which;
if (SDL.SDL_IsGameController(index) == SDL.SDL_bool.SDL_TRUE)
{
System.Console.WriteLine($"New controller detected!");
Inputs.AddGamepad(index);
}
}
private void HandleControllerRemoved(SDL.SDL_Event evt)
{
System.Console.WriteLine($"Controller removal detected!");
Inputs.RemoveGamepad(evt.cdevice.which);
}
private TimeSpan AdvanceElapsedTime() private TimeSpan AdvanceElapsedTime()
{ {
long currentTicks = gameTimer.Elapsed.Ticks; long currentTicks = gameTimer.Elapsed.Ticks;

View File

@ -1,4 +1,3 @@
using System;
using MoonWorks.Math; using MoonWorks.Math;
using SDL2; using SDL2;
@ -6,7 +5,7 @@ namespace MoonWorks.Input
{ {
public class Axis public class Axis
{ {
IntPtr GamepadHandle; public Gamepad Parent { get; }
SDL.SDL_GameControllerAxis SDL_Axis; SDL.SDL_GameControllerAxis SDL_Axis;
public AxisCode Code { get; private set; } public AxisCode Code { get; private set; }
@ -17,11 +16,11 @@ namespace MoonWorks.Input
public float Value { get; private set; } public float Value { get; private set; }
public Axis( public Axis(
IntPtr gamepadHandle, Gamepad parent,
AxisCode code, AxisCode code,
SDL.SDL_GameControllerAxis sdlAxis SDL.SDL_GameControllerAxis sdlAxis
) { ) {
GamepadHandle = gamepadHandle; Parent = parent;
SDL_Axis = sdlAxis; SDL_Axis = sdlAxis;
Code = code; Code = code;
} }
@ -29,7 +28,7 @@ namespace MoonWorks.Input
internal void Update() internal void Update()
{ {
Value = MathHelper.Normalize( Value = MathHelper.Normalize(
SDL.SDL_GameControllerGetAxis(GamepadHandle, SDL_Axis), SDL.SDL_GameControllerGetAxis(Parent.Handle, SDL_Axis),
short.MinValue, short.MaxValue, short.MinValue, short.MaxValue,
-1, 1 -1, 1
); );

View File

@ -8,7 +8,9 @@ namespace MoonWorks.Input
public class Gamepad public class Gamepad
{ {
internal IntPtr Handle; internal IntPtr Handle;
internal int Index; internal int JoystickInstanceID;
public int Slot { get; internal set; }
public GamepadButton A { get; } public GamepadButton A { get; }
public GamepadButton B { get; } public GamepadButton B { get; }
@ -61,37 +63,40 @@ namespace MoonWorks.Input
private VirtualButton[] VirtualButtons; private VirtualButton[] VirtualButtons;
internal Gamepad(IntPtr handle, int index) internal Gamepad(IntPtr handle, int slot)
{ {
Handle = handle; Handle = handle;
Index = index; Slot = slot;
IntPtr joystickHandle = SDL.SDL_GameControllerGetJoystick(Handle);
JoystickInstanceID = SDL.SDL_JoystickInstanceID(joystickHandle);
AnyPressed = false; AnyPressed = false;
A = new GamepadButton(handle, GamepadButtonCode.A, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A); A = new GamepadButton(this, GamepadButtonCode.A, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A);
B = new GamepadButton(handle, GamepadButtonCode.B, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B); B = new GamepadButton(this, GamepadButtonCode.B, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B);
X = new GamepadButton(handle, GamepadButtonCode.X, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X); X = new GamepadButton(this, GamepadButtonCode.X, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X);
Y = new GamepadButton(handle, GamepadButtonCode.Y, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y); Y = new GamepadButton(this, GamepadButtonCode.Y, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y);
Back = new GamepadButton(handle, GamepadButtonCode.Back, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_BACK); Back = new GamepadButton(this, GamepadButtonCode.Back, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_BACK);
Guide = new GamepadButton(handle, GamepadButtonCode.Guide, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_GUIDE); Guide = new GamepadButton(this, GamepadButtonCode.Guide, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_GUIDE);
Start = new GamepadButton(handle, GamepadButtonCode.Start, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START); Start = new GamepadButton(this, GamepadButtonCode.Start, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START);
LeftStick = new GamepadButton(handle, GamepadButtonCode.LeftStick, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK); LeftStick = new GamepadButton(this, GamepadButtonCode.LeftStick, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK);
RightStick = new GamepadButton(handle, GamepadButtonCode.RightStick, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSTICK); RightStick = new GamepadButton(this, GamepadButtonCode.RightStick, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSTICK);
LeftShoulder = new GamepadButton(handle, GamepadButtonCode.LeftShoulder, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER); LeftShoulder = new GamepadButton(this, GamepadButtonCode.LeftShoulder, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
RightShoulder = new GamepadButton(handle, GamepadButtonCode.RightShoulder, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); RightShoulder = new GamepadButton(this, GamepadButtonCode.RightShoulder, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
DpadUp = new GamepadButton(handle, GamepadButtonCode.DpadUp, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_UP); DpadUp = new GamepadButton(this, GamepadButtonCode.DpadUp, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_UP);
DpadDown = new GamepadButton(handle, GamepadButtonCode.DpadDown, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_DOWN); DpadDown = new GamepadButton(this, GamepadButtonCode.DpadDown, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_DOWN);
DpadLeft = new GamepadButton(handle, GamepadButtonCode.DpadLeft, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_LEFT); DpadLeft = new GamepadButton(this, GamepadButtonCode.DpadLeft, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_LEFT);
DpadRight = new GamepadButton(handle, GamepadButtonCode.DpadRight, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_RIGHT); DpadRight = new GamepadButton(this, GamepadButtonCode.DpadRight, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
LeftX = new Axis(handle, AxisCode.LeftX, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTX); LeftX = new Axis(this, AxisCode.LeftX, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTX);
LeftY = new Axis(handle, AxisCode.LeftY, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTY); LeftY = new Axis(this, AxisCode.LeftY, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTY);
RightX = new Axis(handle, AxisCode.RightX, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTX); RightX = new Axis(this, AxisCode.RightX, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTX);
RightY = new Axis(handle, AxisCode.RightY, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTY); RightY = new Axis(this, AxisCode.RightY, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTY);
LeftXLeft = new AxisButton(LeftX, false); LeftXLeft = new AxisButton(LeftX, false);
LeftXRight = new AxisButton(LeftX, true); LeftXRight = new AxisButton(LeftX, true);
@ -103,8 +108,8 @@ namespace MoonWorks.Input
RightYUp = new AxisButton(RightY, false); RightYUp = new AxisButton(RightY, false);
RightYDown = new AxisButton(RightY, true); RightYDown = new AxisButton(RightY, true);
TriggerLeft = new Trigger(handle, TriggerCode.Left, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT); TriggerLeft = new Trigger(this, TriggerCode.Left, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT);
TriggerRight = new Trigger(handle, TriggerCode.Right, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT); TriggerRight = new Trigger(this, TriggerCode.Right, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
TriggerLeftButton = new TriggerButton(TriggerLeft); TriggerLeftButton = new TriggerButton(TriggerLeft);
TriggerRightButton = new TriggerButton(TriggerRight); TriggerRightButton = new TriggerButton(TriggerRight);

View File

@ -24,16 +24,10 @@ namespace MoonWorks.Input
gamepads = new Gamepad[MAX_GAMEPADS]; gamepads = new Gamepad[MAX_GAMEPADS];
for (var i = 0; i < 4; i += 1) // initialize dummy controllers
for (var slot = 0; slot < MAX_GAMEPADS; slot += 1)
{ {
if (SDL.SDL_IsGameController(i) == SDL.SDL_bool.SDL_TRUE) gamepads[slot] = new Gamepad(IntPtr.Zero, slot);
{
gamepads[i] = new Gamepad(SDL.SDL_GameControllerOpen(i), i);
}
else
{
gamepads[i] = new Gamepad(IntPtr.Zero, -1);
}
} }
} }
@ -74,14 +68,49 @@ namespace MoonWorks.Input
public bool GamepadExists(int slot) public bool GamepadExists(int slot)
{ {
if (slot < 0 || slot >= MAX_GAMEPADS)
{
return false;
}
return !gamepads[slot].IsDummy; return !gamepads[slot].IsDummy;
} }
// From 0-4
public Gamepad GetGamepad(int slot) public Gamepad GetGamepad(int slot)
{ {
return gamepads[slot]; return gamepads[slot];
} }
internal void AddGamepad(int index)
{
for (var slot = 0; slot < MAX_GAMEPADS; slot += 1)
{
if (!GamepadExists(slot))
{
gamepads[slot].Handle = SDL.SDL_GameControllerOpen(index);
System.Console.WriteLine($"Gamepad added to slot {slot}!");
return;
}
}
System.Console.WriteLine("Too many gamepads already!");
}
internal void RemoveGamepad(int joystickInstanceID)
{
for (int slot = 0; slot < MAX_GAMEPADS; slot += 1)
{
if (joystickInstanceID == gamepads[slot].JoystickInstanceID)
{
SDL.SDL_GameControllerClose(gamepads[slot].Handle);
gamepads[slot].Handle = IntPtr.Zero;
System.Console.WriteLine($"Removing gamepad from slot {slot}!");
return;
}
}
}
internal static void OnTextInput(char c) internal static void OnTextInput(char c)
{ {
if (TextInput != null) if (TextInput != null)

View File

@ -1,4 +1,3 @@
using System;
using MoonWorks.Math; using MoonWorks.Math;
using SDL2; using SDL2;
@ -6,7 +5,7 @@ namespace MoonWorks.Input
{ {
public class Trigger public class Trigger
{ {
public IntPtr GamepadHandle; public Gamepad Parent { get; }
public SDL.SDL_GameControllerAxis SDL_Axis; public SDL.SDL_GameControllerAxis SDL_Axis;
public TriggerCode Code { get; } public TriggerCode Code { get; }
@ -17,11 +16,11 @@ namespace MoonWorks.Input
public float Value { get; private set; } public float Value { get; private set; }
public Trigger( public Trigger(
IntPtr gamepadHandle, Gamepad parent,
TriggerCode code, TriggerCode code,
SDL.SDL_GameControllerAxis sdlAxis SDL.SDL_GameControllerAxis sdlAxis
) { ) {
GamepadHandle = gamepadHandle; Parent = parent;
Code = code; Code = code;
SDL_Axis = sdlAxis; SDL_Axis = sdlAxis;
} }
@ -29,7 +28,7 @@ namespace MoonWorks.Input
internal void Update() internal void Update()
{ {
Value = MathHelper.Normalize( Value = MathHelper.Normalize(
SDL.SDL_GameControllerGetAxis(GamepadHandle, SDL_Axis), SDL.SDL_GameControllerGetAxis(Parent.Handle, SDL_Axis),
0, short.MaxValue, 0, short.MaxValue,
0, 1 0, 1
); );

View File

@ -1,25 +1,23 @@
using System;
using SDL2; using SDL2;
namespace MoonWorks.Input namespace MoonWorks.Input
{ {
public class GamepadButton : VirtualButton public class GamepadButton : VirtualButton
{ {
IntPtr GamepadHandle; public Gamepad Parent { get; }
SDL.SDL_GameControllerButton SDL_Button; SDL.SDL_GameControllerButton SDL_Button;
public GamepadButtonCode Code { get; }
public GamepadButtonCode Code { get; private set; } internal GamepadButton(Gamepad parent, GamepadButtonCode code, SDL.SDL_GameControllerButton sdlButton)
internal GamepadButton(IntPtr gamepadHandle, GamepadButtonCode code, SDL.SDL_GameControllerButton sdlButton)
{ {
GamepadHandle = gamepadHandle; Parent = parent;
Code = code; Code = code;
SDL_Button = sdlButton; SDL_Button = sdlButton;
} }
internal override bool CheckPressed() internal override bool CheckPressed()
{ {
return MoonWorks.Conversions.ByteToBool(SDL.SDL_GameControllerGetButton(GamepadHandle, SDL_Button)); return MoonWorks.Conversions.ByteToBool(SDL.SDL_GameControllerGetButton(Parent.Handle, SDL_Button));
} }
} }
} }