If anyone can shed some light on this, it’d be super helpful.
So what’s happening is that if you start a MonoGame program with a PS4 controller connected and some other controller (tested with Xbox 360 and Xbox One controllers), instead of MG reporting the PS4 and Xbox controller, there are 2 instances of the Xbox controller. On 2 different GamePad indexes, and both report button presses to polling and such. If you disconnect the Xbox controller and reconnect, then the new one will work as expected, but leaves behind the “ghost” duplicate that does not report button presses or anything. If you connect the PS4 controller after the program starts (presumably, after MG/SDL have initialized), then everything works as expected, but if the programs starts with the PS4 controller and other controller connected you can see the bug. If you disconnect the PS4 controller, the “ghost” remains until you restart the program (presumably, until MG/SDL/both have re-Init-ed).
I wonder if this is a MonoGame bug, an SDL bug, or perhaps something even deeper. Seemingly not a driver-level bug, because Windows doesn’t report multiple copies of the Xbox device, and this only happens if you Init the program with both connected at the same time.
Tested with MonoGame 3.8 - DesktopGL on Windows 10 x64
Here’s a simple MG Game class to test what I have described above (you will need a simple font content file to load to render the debug info - in this code it loads an Arial.xnb spritefont):
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Diagnostics;
namespace ControllerReader
{
public class Game1 : Game
{
private GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
string outputStr;
SpriteFont font;
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
IsFixedTimeStep = false;
}
protected override void Initialize()
{
_graphics.PreferredBackBufferWidth = 1600;
_graphics.PreferredBackBufferHeight = 900;
_graphics.ApplyChanges();
GamePad.InitDatabase();
base.Initialize();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
font = Content.Load<SpriteFont>("Arial");
}
protected override void Update(GameTime gameTime)
{
for (int i = 0; i < GamePad.MaximumGamePadCount; i++)
{
GamePadState gamepadState = GamePad.GetState(i, GamePadDeadZone.Circular);
GamePadCapabilities capabilities = GamePad.GetCapabilities(i);
outputStr += $"\n{i}: ({capabilities.Identifier}) {capabilities.DisplayName}";
// check button presses
foreach (Buttons button in Enum.GetValues(typeof(Buttons)))
if (gamepadState.IsButtonDown(button))
outputStr += $" - ({(int)button}) {button}";
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
_spriteBatch.Begin();
_spriteBatch.DrawString(font, outputStr, new Vector2(20, 20), Color.White);
_spriteBatch.End();
base.Draw(gameTime);
}
}
}