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:
HandleFileDrop(_event);
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);
}
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()
{
long currentTicks = gameTimer.Elapsed.Ticks;

View File

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

View File

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

View File

@ -24,16 +24,10 @@ namespace MoonWorks.Input
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[i] = new Gamepad(SDL.SDL_GameControllerOpen(i), i);
}
else
{
gamepads[i] = new Gamepad(IntPtr.Zero, -1);
}
gamepads[slot] = new Gamepad(IntPtr.Zero, slot);
}
}
@ -74,14 +68,49 @@ namespace MoonWorks.Input
public bool GamepadExists(int slot)
{
if (slot < 0 || slot >= MAX_GAMEPADS)
{
return false;
}
return !gamepads[slot].IsDummy;
}
// From 0-4
public Gamepad GetGamepad(int 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)
{
if (TextInput != null)

View File

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

View File

@ -1,25 +1,23 @@
using System;
using SDL2;
namespace MoonWorks.Input
{
public class GamepadButton : VirtualButton
{
IntPtr GamepadHandle;
public Gamepad Parent { get; }
SDL.SDL_GameControllerButton SDL_Button;
public GamepadButtonCode Code { get; }
public GamepadButtonCode Code { get; private set; }
internal GamepadButton(IntPtr gamepadHandle, GamepadButtonCode code, SDL.SDL_GameControllerButton sdlButton)
internal GamepadButton(Gamepad parent, GamepadButtonCode code, SDL.SDL_GameControllerButton sdlButton)
{
GamepadHandle = gamepadHandle;
Parent = parent;
Code = code;
SDL_Button = sdlButton;
}
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));
}
}
}