Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Incorrect handling of multiple controllers events  (Read 822 times)

0 Members and 1 Guest are viewing this topic.

EatMyShorts

  • Newbie
  • *
  • Posts: 10
    • View Profile
Incorrect handling of multiple controllers events
« on: August 10, 2022, 04:06:45 pm »
I am using SFML 2.5.1.

I have two Xbox One Controllers connected to my PC. Obviously they will have two ids, 0 and 1.

When I disconnect the one with id 0 (the first one) bad magic happens.

First of all, I can see a weird sequence of JoystickDisconnected/JoystickConnected events.
The 0 controller gets disconnected, and a new 0 controller gets connected.

Secondly, once the 0 controller is disconnected, events for connected controller are reported with id 0 and 1.

I wrote a simple code for tracing Joystick events.
Quote
      sf::Event event;
      while (m_window.pollEvent(event))
      {
         switch (event.type)
         {
         case sf::Event::JoystickMoved:
            {
               Diagnostics::Trace::Write("Controller move: Id:[{0}]\n", event.joystickMove.joystickId);
            }
            break;
         case sf::Event::JoystickDisconnected:
            {
               Diagnostics::Trace::Write("Controller disconnected: Id:[{0}]\n", event.joystickConnect.joystickId);
            }
            break;
         case sf::Event::JoystickConnected:
            {
               Diagnostics::Trace::Write("Controller connected: Id:[{0}]\n", event.joystickConnect.joystickId);
            }
            break;
         }
      }

This is the output after disconnecting 0 controller and moving a thumbstick on other, still connected controller.
Quote
Controller disconnected: Id:[0]
Controller connected: Id:[0]
Controller move: Id:[0]
Controller move: Id:[0]
Controller move: Id:[0]
Controller move: Id:[0]
Controller move: Id:[1]
Controller move: Id:[1]
Controller move: Id:[1]
Controller move: Id:[1]
Controller move: Id:[0]
Controller move: Id:[0]
Controller move: Id:[1]
Controller move: Id:[1]

As you can see:
1. Controller 0 gets somehow connected
2. Events are reported for both controllers 0 and 1 even there is only one controller connected.

This seems to be a bug in SFML library.
I have found two topics about similar problems, but there is no explanation what is going on.

https://en.sfml-dev.org/forums/index.php?topic=27376.0
https://en.sfml-dev.org/forums/index.php?topic=24764.0
« Last Edit: August 10, 2022, 05:09:51 pm by EatMyShorts »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10394
    • View Profile
    • development blog
    • Email
Re: Incorrect handling of multiple controllers events
« Reply #1 on: August 11, 2022, 05:00:35 pm »
Sounds like a bug indeed, maybe the SFML implementation expects a different behavior from the OS API.

I don't (currently) have one or even two gamepads to test this, so I past it along to some other people, maybe they can try and reproduce it.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://dev.my-gate.net/

kojack

  • Full Member
  • ***
  • Posts: 209
    • View Profile
Re: Incorrect handling of multiple controllers events
« Reply #2 on: August 15, 2022, 02:20:31 am »
I've given it a try, but can't replicate it. Two xbox one controllers, connecting and disconnecting them works correctly.
(I also tested with 2 xbox one controllers, an xbox series x controller and a PS5 controller all at once. Interesting side note: SFML picks up the PS5 controller's button events even when the main window isn't in focus, but the xbox controllers only when in focus)

Which OS are you on?
I'm on Win 10 using wireless dongle for xbox controllers and bluetooth for ps5.
Do you have any virtual joystick style stuff installed? vJoy, Joystick Gremlin, DS4Windows, etc.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10394
    • View Profile
    • development blog
    • Email
Re: Incorrect handling of multiple controllers events
« Reply #3 on: August 15, 2022, 03:56:01 am »
I've given it a try, but can't replicate it.
Did you use SFML 2.5.1 or SFML 2.6.x?

I am using SFML 2.5.1.
Can you give SFML 2.6.x a try (build from source, or see the snapshot builds here).
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://dev.my-gate.net/

kojack

  • Full Member
  • ***
  • Posts: 209
    • View Profile
Re: Incorrect handling of multiple controllers events
« Reply #4 on: August 15, 2022, 06:52:00 am »
2.5.1.
(This particular one built from source 3 years ago)

Oh, and 64 bit.

EatMyShorts

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: Incorrect handling of multiple controllers events
« Reply #5 on: August 28, 2022, 08:35:36 pm »
2.6 does not work

In file JoystickImpl.cpp is wierd logic:
Quote
    // Remove devices that were not connected during the enumeration
    for (std::vector<JoystickRecord>::iterator i = joystickList.begin(); i != joystickList.end();)
    {
        if (!i->plugged)
            i = joystickList.erase(i);
        else
            ++i;
    }

As you all know erase() invalidates iterator used there.
Moreover, there is a problem with indexing connected controllers.

I have two controllers, lets call them red and blue.
Application starts, and red is indexed as 1, and blue is indexed as 0.

When I push red button it is registered as controller 0 button press
When I push blue button it is registered as controller 1 button press

I have tried to debug it on my own, but i have failed... I have not time for it.
I do not care ... I am out.
« Last Edit: August 28, 2022, 08:43:24 pm by EatMyShorts »

kojack

  • Full Member
  • ***
  • Posts: 209
    • View Profile
Re: Incorrect handling of multiple controllers events
« Reply #6 on: August 28, 2022, 10:10:49 pm »

In file JoystickImpl.cpp is wierd logic:
Quote
    // Remove devices that were not connected during the enumeration
    for (std::vector<JoystickRecord>::iterator i = joystickList.begin(); i != joystickList.end();)
    {
        if (!i->plugged)
            i = joystickList.erase(i);
        else
            ++i;
    }

As you all know erase() invalidates iterator used there.
That's a common way to remove items from a vector while looping over it.
Erase does invalidate the current iterator, but it returns a new (valid) iterator to the next item. That's why ++i is only done when not erasing instead of up in the for loop, because i = joystickList.erase(i) is effectively doing ++i as well as removing.

If what you want is explicitly xbox controllers in windows, one solution would be to ignore SFML's joystick system and use XInput directly. SFML uses DirectInput for joysticks (on windows), Microsoft intentionally degraded xbox controller support in DirectInput compared to XInput.
Luckily XInput is incredibly easy to use, just a few lines of code, and it enables missing features like split triggers and vibration.
Although that doesn't help if you want generic gamepad support too, since XInput is xbox controller only.


If you have a binary that is exhibiting this behavior I could give it a run and see if maybe it's something in the build process that caused it (mixed versions or something).
« Last Edit: August 28, 2022, 10:13:48 pm by kojack »