Incompability between SDL joystick button number and other tools (Windows' and online tools)

Hi.
I’m trying to make a 1 to 1 mapping between physical device and virtual device (vJoy)

Since I’m trying to map 1-1 between physical and virtual controller, I shouldn’t have any business with mapping. Hence, As @slouken described simply in SDL Game controller button mapping issue - #2 by slouken ,I’m trying Joystick mode instead of GameController mode by thinking that joystick button numbers/indexes wouldn’t be mapped so 1-1 mapping would be simple.

This is correct for almost all controllers I have but one controller doesn’t work in that way. It is a PS4 controller.

When I press press leftshoulder button, event.jbutton.button says 9
When I press press rightshoulder button, event.jbutton.button says 10
(It also says 9 and 10 in game controller mode instead of joystick mode, same. I confirm I’m not mistakenly using controller mode by trying same method with other controllers without changing anything)

But when I test it with other tools, they give 4 and 5 as button numbers.

This is Window’s Utility:
image

This is the result from https://gamepad-tester.com/

This is result from https://greggman.github.io/html5-gamepad-test/
image

So they are all giving 4 and 5 (Window’s start from 1, so 5 and 6) for leftshoulder and rightshoulder buttons.

I tested with my other controllers and they are working 1 to 1 with this method.
So what could be the problem with that specific controller? What should I check?

SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_EVENTS);
SDL_JoystickEventState(SDL_ENABLE);
SDL_Event event;

while(SDL_WaitEventTimeout(&event, 50))
{
    switch(event.type){
        case SDL_JOYDEVICEADDED:
              m_Joystick = SDL_JoystickOpen(device);
        break;
        //
       case SDL_JOYBUTTONDOWN:
       case SDL_JOYBUTTONUP:
               qDebug() << "JoystickButton(" << QString(SDL_GameControllerGetStringForButton((SDL_GameControllerButton)event.jbutton.button)) << ")" << event.jbutton.button<< " -> " << event.jbutton.state;

      break;

    }
}

You can make a 1:1 passthrough from SDL joystick to a virtual joystick, but remember that depending on controller and driver you can’t make any assumptions about what button means what. That’s why the game controller API was added in the first place, to create a well defined semantic meaning for buttons and axes.

However, you can say “Hey, here’s a virtual joystick that has the same axes and buttons as a real one, as long as your application can remap all of them, have fun!”

For now I’d like to achieve your last statement: “Hey, here’s a virtual joystick that has the same axes and buttons as a real one…”

But the problem is what I read with SDL2 joystick mode is inconsistent with other tools.
I’m pressing same button -leftshoulder-, with SDL2 I get 9, but other tools say it is button 4…

Since I get 9, I change the state of button 9 on virtual joystick, 1-1, but it should be button 4. I’m saying it should because Window’s tool is also saying the pressed button is button 4.

This is happening with only 1 of my controllers, others work same as expected. I start thinking it might be side-effect of another tool maybe or SDL2 might be applying unexpected mapping for me.

1 Like

@slouken

I started debugging SDL input reading.

For now, it seems my PS4 controller calls functions from /src/joystick/hidapi/SDL_hidapi_ps4.c

My other USB controller calls functions from /src/joystick/windows/SDL_dinputjoystick.c

I don’t know if I can make hidapi joystick work like a windows joystick or vice versa… yet.

You shouldn’t be making any assumptions about what button and axis indexes mean. They will vary based on controller, operating system, connection method, and driver.

The application should either use the game controller API or have a way for the user to tell the application what any given button and axis means.

1 Like

For me, using any automatic controller mapping is a bad idea because you never know if the mapping will be determined correctly or not, and besides, the mapping database needs to be updated regularly for it to make sense.

A better solution in my opinion is not to map the controller automatically when connected, but to let the user set the mapping as (s)he wants, everything based on the SDL_Joystick API. After all, input is set once for each new controller, so taking two minutes to customize the controls to your requirements shouldn’t be a problem. It’s better to spend two minutes configuring than to get mad that the automatic mapping assigned the buttons wrong.

Yes, I know, it requires more work, but the advantage is that the user chooses how (s)he wants the control to look like. Besides, it’s good to create a remapping menu anyway (to suit players’ preferences or handicaps), so it’s not a waste of work. An additional advantage is that your own mapping system can have any functionality and almost no limits. The only limit is your imagination.

1 Like

Now with all of the answer, I imagine what to do.
The only thing in my mind is: SDL: Allow HIDAPI controllers to override the default joystick type

(This might not be the place to talk about that)
I tried to disable PS4_HID_API with that command:
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4, “0”);

in my application and in a very basic test setup. It seems it is giving exception internally to SDL in this case. Most probably I did wrong but its better to check by an experienced guy. Also Joystick and GameController numbers are always exactly same for my PS4 case (PS4_HID device). It seems even indexes in Joystick mode comes as mapped but I can’t confirm, its just suspicion (or they are exaclty same)

After all, thank you

Your answer combined with this answer:

is what I’m going to do now. 1-1 mapping problem seems can be solved with that approach.