Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions src/Input/Silk.NET.Input.Glfw/GlfwGamepad.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public GlfwGamepad(int i)
Thumbsticks = new Thumbstick[GamepadThumbstickCount];
Triggers = new Trigger[GamepadTriggerCount];

_connected = hasState;
IsConnected = _connected = hasState;

for (int j = 0; j < GamepadButtonCount; j++)
{
Expand All @@ -44,7 +44,12 @@ public GlfwGamepad(int i)

public string Name => GlfwProvider.GLFW.Value.GetGamepadName(Index) ?? "Silk.NET Gamepad (via GLFW)";
public int Index { get; }
public bool IsConnected => GlfwProvider.GLFW.Value.JoystickIsGamepad(Index);

/// <summary>
/// Cached connection status from GLFW's joystick connection callback.
/// </summary>
public bool IsConnected { get; internal set; }

public IReadOnlyList<Button> Buttons { get; }
public IReadOnlyList<Thumbstick> Thumbsticks { get; }
public IReadOnlyList<Trigger> Triggers { get; }
Expand All @@ -57,8 +62,10 @@ public GlfwGamepad(int i)

public void Update()
{
if (!GlfwProvider.GLFW.Value.GetGamepadState(Index, out var state))
if (!IsConnected || !GlfwProvider.GLFW.Value.GetGamepadState(Index, out var state))
{
IsConnected = false;

// Detect when this gamepad disconnects
if (_connected)
{
Expand Down
17 changes: 17 additions & 0 deletions src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public unsafe GlfwInputContext(IView window) : base(window)
Mice = _mice;

GlfwInputPlatform.RegisterWindow((WindowHandle*) Handle, _subscribers);
GlfwInputPlatform.JoystickConnectionChanged += OnJoystickConnectionChanged;
}

public override void ProcessEvents()
Expand All @@ -69,8 +70,24 @@ public override void ProcessEvents()
}
}

// Cache connection status on the devices so that ProcessEvents only polls slots that actually have something plugged
// in, rather than asking GLFW about all gamepads and all joysticks every single frame.
private void OnJoystickConnectionChanged(int jid, ConnectedState state)
{
if (jid < 0 || jid >= _joysticks.Length)
{
return;
}

var connected = state == ConnectedState.Connected;
var isGamepad = connected && GlfwProvider.GLFW.Value.JoystickIsGamepad(jid);
_gamepads[jid].IsConnected = connected && isGamepad;
_joysticks[jid].IsConnected = connected && !isGamepad;
}

public override unsafe void CoreDispose()
{
GlfwInputPlatform.JoystickConnectionChanged -= OnJoystickConnectionChanged;
GlfwInputPlatform.UnregisterWindow((WindowHandle*) Handle, _subscribers);
foreach (var gamepad in _gamepads)
{
Expand Down
22 changes: 22 additions & 0 deletions src/Input/Silk.NET.Input.Glfw/GlfwInputPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ internal class GlfwInputPlatform : IInputPlatform
{
private static readonly Dictionary<nint, GlfwEvents> _subs = new Dictionary<nint, GlfwEvents>();

// Unlike the keyboard/mouse callbacks, GLFW's joystick callback is global rather than per window, so it is
// owned here instead of by GlfwEvents.cs and available to every live input context.
private static readonly GlfwCallbacks.JoystickCallback _joystickCallback =
(jid, state) => JoystickConnectionChanged?.Invoke(jid, state);

/// <summary>
/// Raised when GLFW reports that a joystick has been connected to or disconnected from the system. The
/// underlying GLFW callback is only installed while at least one input context is alive.
/// </summary>
internal static event GlfwCallbacks.JoystickCallback? JoystickConnectionChanged;

/// <inheritdoc />
public bool IsApplicable(IView window) => window is GlfwWindow;

Expand All @@ -30,6 +41,12 @@ internal static unsafe void RegisterWindow(WindowHandle* handle, IEnumerable<IGl
{
throw new InvalidOperationException($"More than one input context for window {(nint) handle}.");
}

if (_subs.Count == 0)
{
GlfwProvider.GLFW.Value.SetJoystickCallback(_joystickCallback);
}

var events = _subs[(nint) handle] = new GlfwEvents(handle);
foreach (var subscriber in subscribers)
{
Expand All @@ -48,6 +65,11 @@ internal static unsafe void UnregisterWindow(WindowHandle* handle, IEnumerable<I

events.Dispose();
_subs.Remove((nint) handle);

if (_subs.Count == 0)
{
GlfwProvider.GLFW.Value.SetJoystickCallback(null);
}
}
else
{
Expand Down
9 changes: 6 additions & 3 deletions src/Input/Silk.NET.Input.Glfw/GlfwJoystick.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@ public GlfwJoystick(int i)
Buttons = new Button[0];
Hats = new Hat[0];

_connected = IsConnected;
IsConnected = _connected = GlfwProvider.GLFW.Value.JoystickPresent(i) &&
!GlfwProvider.GLFW.Value.JoystickIsGamepad(i);
}

public string Name => GlfwProvider.GLFW.Value.GetJoystickName(Index) ?? "Silk.NET Joystick (via GLFW)";
public int Index { get; }

public bool IsConnected => GlfwProvider.GLFW.Value.JoystickPresent(Index) &&
!GlfwProvider.GLFW.Value.JoystickIsGamepad(Index);
/// <summary>
/// Cached connection status from GLFW's joystick connection callback.
/// </summary>
public bool IsConnected { get; internal set; }

public IReadOnlyList<Axis> Axes { get; private set; }
public IReadOnlyList<Button> Buttons { get; private set; }
Expand Down