Xbox One -- "Back" vs "B" button... Possible bug?

I haven’t debugged this yet, but I’ve recently ported my game and was testing it out on the Xbox One.

When I push the “B” button, two blocks of code are activated:

        if (input.IsNewButtonPress(Buttons.B, null, out playerIndex))
        {...
        }

and

        if (input.IsNewButtonPress(Buttons.Back, ControllingPlayer, out playerIndex))
        {...
        }

Is this expected behavior?

IsNewButtonPress is not a default Monogame function, so you would need to show us the inner workings of said function before we can conclude anything.

I’m having the same issue, Here a snippet of the code. Very basic implementation.

protected override void Update(GameTime gameTime)
{
   currentGamePadState = GamePad.GetState(PlayerIndex.One);

   if (currentGamePadState.Buttons.Back == ButtonState.Pressed)
     Exit();

   if (currentGamePadState.Button.B == ButtonState.Pressed)
     DoSomething();
   if (currentGamePadState.Button.X == ButtonState.Pressed)
     DoSomethingDifferent();
}

When running the code, If I press Back or X on the controller, I get the intended result. If i press B than the game with trigger to same behavior as if i had pressed Back on the execute the DoSomething() method. This is the same for both Windows and Xbox One deploys.

Edit: just to point out this is using the UWP template solution from 3.6

I’m having the same problem. quick test with following code results in the Back button being registered as pressed briefly when the B button is released.

spriteBatch.Begin();
if (GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed)
{
     spriteBatch.DrawString(font, "GamePad A : Pressed", new Vector2(100, 100), Color.White);
}
else
{
      spriteBatch.DrawString(font, "GamePad A : ", new Vector2(100, 100), Color.White);
}

if (GamePad.GetState(PlayerIndex.One).Buttons.B == ButtonState.Pressed)
{
      spriteBatch.DrawString(font, "GamePad B : Pressed", new Vector2(100, 120), Color.White);
}
else
{
      spriteBatch.DrawString(font, "GamePad B : ", new Vector2(100, 120), Color.White);
}

if (GamePad.GetState(PlayerIndex.One).Buttons.X == ButtonState.Pressed)
{
      spriteBatch.DrawString(font, "GamePad X : Pressed", new Vector2(100, 140), Color.White);
}
else
{
      spriteBatch.DrawString(font, "GamePad X : ", new Vector2(100, 140), Color.White);
}

if (GamePad.GetState(PlayerIndex.One).Buttons.Y == ButtonState.Pressed)
{
      spriteBatch.DrawString(font, "GamePad Y : Pressed", new Vector2(100, 160), Color.White);
}
else
{
      spriteBatch.DrawString(font, "GamePad Y : ", new Vector2(100, 160), Color.White);
}

if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
{
        spriteBatch.DrawString(font, "GamePad Back : Pressed", new Vector2(100, 180), Color.White);
}
else
{
        spriteBatch.DrawString(font, "GamePad Back : ", new Vector2(100, 180), Color.White);
}
spriteBatch.End();

Saving the previous gamepad state then checking if the previous and current buttonstate of Back button seems to stop the B button triggering Back.

GamePadState gPad, gPadLast;

gPad = GamePad.GetState(PlayerIndex.One);

if (gPad.Buttons.Back == ButtonState.Pressed && gPadLast.Buttons.Back == ButtonState.Pressed)
{
      spriteBatch.DrawString(font, "GamePad Back : Pressed", new Vector2(100, 180), Color.White);
}
else
{
     spriteBatch.DrawString(font, "GamePad Back : ", new Vector2(100, 180), Color.White);
}

gPadLast = gPad;

I’ve encountered this bug as well.
This exists in a Windows10 UWP Monogame project.

Steps to reproduce:

Create a fresh Monogame project for Windows10 UWP.
Replace the update function with this:

protected override void Update(GameTime gameTime) { base.Update(gameTime); GamePadState currentGamePadState = GamePad.GetState(PlayerIndex.One); if (currentGamePadState.Buttons.Back == ButtonState.Pressed) { System.Diagnostics.Debug.WriteLine("should not happen on B button press."); } }

Connect one 360 or XboxOne Controller, start debugging.
Upon a B button release, the Back button state is set to Pressed for a single frame.
This only happens upon RELEASE of the B button.

Yeah, I see this same behavior. It only seems to happen with UWP projects. The same code running under Windows DX does not exhibit this behavior.

I’m not deeply familiar with MonoGame internals, but I would guess based on my experience of UWP, that when the B button is pressed, that SystemNavigationManager fires the BackRequested event, which results in calling the UAPGamePlatform.BackRequested in the WindowsUniversal/UAPGamePlatform.cs file. This sets the GamePad.Back flag, which is cleared in the lambda in StartRunLoop after each frame, but results in the Back button appearing as pressed for a single frame. I see the intent of this code - when BackRequested is a UWP abstraction for allowing the user to submit a back request regardless of their input method, such as pressing the back button on a phone (similar code exists for Android).

UWP documentation describes that the BackRequested is fired when the B button is pressed. But I don’t see any way to disable that.
https://docs.microsoft.com/en-us/windows/uwp/input-and-devices/designing-for-tv#hardware-buttons

I feel it would be best if there was some way to opt out of this behavior in MonoGame - I’m not sure it makes sense to map the BackRequested action to the back button on the controller, since many games might not use the controller’s back button as a way of exiting the game.

1 Like

Still seems to be happening on latest. I logged a bug here, as it doesn’t seem to have ever been logged :cry:

I believe the issue was introduced on this change if anyone wants to avoid:

Hi,

as said in the link posted in the message previous to you, this is UWP behaviour and can’t be changed. If you observe the Xbox one gamepad, there’s no “back button”. What were Start and Back have been renamed to ‘view button’ and ‘menu button’. To avoid this pitfall, MS decided that pressing “B” would generate a “Back”.

So, it’s not a bug, it’s a UWP feature (a feature which I also hate :joy: )

Could MG change the behaviour and avoid setting the “back” variable? Sure. But then, there would be no “Back” in UWP gamepads, and that would break lots of existing code. So, it’s not possible to fix the problem unless MS supplies a way to differentiate between B and Back.

Personally what I did was handling a “Back” in a different way in UWP, because actually I was using “B” (well, “circle”, I’m a PS guy ) as “Back”. So in the end, I was getting “Back” twice (because the game came from WP8, where “back” was properly working). In short: a big mess :sweat_smile:

I see how you would get that impression but reacting to the “BackRequested” event in UWP is totally optional (I link to the code where MonoGame is doing it). It 100% can be changed (in fact that is exactly what MonoGame is doing).

The fact that MonoGame maps that event to the physical “Back Button” on Desktop is (arguably) a bug: the back button was NOT pressed, the BackRequested event was fired. There is a difference.

The way this was implemented only (maybe) makes sense on Phones (which is what that change I linked to was trying to fix) where there is a dedicated “Back” button that is not used for gameplay. On Desktop the back button is used for gameplay all the time (Pause, Options, etc). Reverting the change above would not make it so there is “no back button on UWP gamepads”. It simply would stop mapping the “back requested event” to the back button.

If we are worried about backwards compat, MonoGame could expose a way for us to override with our own “BackRequested” method, so that if we don’t want the default behaviour we can.

That’s fine if you are actually trying to “go back” in a menu or something, but for gameplay which relies on both the BACK and B buttons, this is an issue, as the B button triggers both BACK and B button presses, which is obviously wrong.

I agree with the override. The rest is just a matter of opinion between two interpretations of how MG should work, either " B equals Back and make the UWP gamepad programmers handle this by not reading Buttons.Back " or “B does not equal Back and make the UWP gamepad programmers which want to port games from phones read Button.B and interpret that as a Back”.

1 Like

What makes the bug really bad, is that BACK triggers two frames after B keyUp (Monogame on Xbox ONE 3.8.0.62)

My solution (not pretty, but works)

int ButtonB_KeyUpTime = 0;
public void Update()
        {
            previousPadState = currentPadState;
            currentPadState = GamePad.GetState(index);
    #if XBOX
            if (currentPadState.IsButtonUp(Buttons.B) && previousPadState.IsButtonDown(Buttons.B))
            {
                ButtonB_KeyUpTime = 3;
            }
            else
            {
                --ButtonB_KeyUpTime;
            }
    #endif
        }

        public bool BackButtonDownEvent()
        { //Locks the Back button three frames after B keyUp
    #if XBOX
            if (ButtonB_KeyUpTime > 0)
            {
                return false;
            }
    #endif
            return currentPadState.IsButtonDown(Buttons.Back) && previousPadState.IsButtonUp(Buttons.Back);
        }