Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incompatible gamepad because SDL detects it as a Joystick #6

Closed
cwajh opened this issue Mar 6, 2022 · 13 comments · Fixed by #7
Closed

Incompatible gamepad because SDL detects it as a Joystick #6

cwajh opened this issue Mar 6, 2022 · 13 comments · Fixed by #7

Comments

@cwajh
Copy link

cwajh commented Mar 6, 2022

My gamepad in lsusb:
Bus 003 Device 005: ID 0925:1700 Lakeview Research PS/SS/N64 Joypad
This pad works fine in some games but wasn't being recognized by flex-launcher.

I did some debugging and discovered that SDL raises a SDL_JOYDEVICEADDED event for this gamepad but NOT a SDL_CONTROLLERDEVICEADDED event, so the current code never ends up calling connect_gamepad() about it.

I may be able to hack a fix together for my own use case. But this should probably be fixed for a more general audience too.

@cwajh
Copy link
Author

cwajh commented Mar 6, 2022

I tried to fix this by getting a proper SDL gamepad config for my gamepad.

But when I try to provide it in the flex-launcher config.ini, I get this error:
Failed loading udev_device_get_action: /usr/lib64/libSDL2-2.0.so.0: undefined symbol: _udev_device_get_action

@complexlogic
Copy link
Owner

Thanks for the report. If you have entered a valid controller mapping in a text file and provided it via the ControllerMappingsFile setting in the config, and the GUID of the mapping matches your joystick, SDL should register your joystick as a GameController, and it should push the SDL_GameController events on the event queue. Based on your second comment, it sounds like you have now done that.

In regard to your other problem, an undefined symbol error is a linking issue. Out of curiosity, did you compile Flex Launcher yourself, or are you using a binary package from the release page? And which distro are you using?

@cwajh
Copy link
Author

cwajh commented Mar 6, 2022

Compiled myself. I'm on Gentoo so my package manager didn't take any of the provided package files. My guess is that my Gentoo USEflags enabled some feature of SDL that's usually disabled or vice versa, & as a result SDL decided to call into libudev when (in your binaries) it wouldn't.

Anyway, I did a little more debugging; it looks like the error I was seeing with the linking isn't relevant; it has no effect on the actual issue whether or not the library is linked in.

Here's my controller config file:

03000000250900000017000010010000,HuiJia PS/SS/N64 Joypad to USB BOX,platform:Linux,a:b0,b:b1,y:b4,x:b3,start:b8,leftshoulder:b6,rightshoulder:b7,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13,lefttrigger:b5,righttrigger:b2,

Only one line. I had to hack this together because the generator tool you linked is very out of date & won't even run on my system. But if there's a typo I can't find it.

The issue I am handling now, seems to be twofold.

First off, the log reports an error from SDL_GameControllerAddMappingsFromFile(), but I'm not sure it actually should be.

      error = SDL_GameControllerAddMappingsFromFile(config.gamepad_mappings_file);
      if (error) {

According to the SDL documentation, this function's return value works like that of SDL_GameControllerAddMappingsFromRW, which returns the number of mappings found in the file, or -1 if the file couldn't be loaded. If it's successfully loading my file, it should return 1 (since there's one line in it), which it does.

I enhanced the error message:

        output_log(LOGLEVEL_ERROR, 
          "Error: Could not load gamepad mappings from %s; returned %i (%s)\n", 
          config.gamepad_mappings_file, error, SDL_GetError()
        );

And what I see is a return of "1" and (if I link in libudev) no error at all.

But I still see the joystick attached message instead of gamepad attached, so it doesn't connect.

@complexlogic
Copy link
Owner

You need to include the platform at the end of your mapping, otherwise SDL won't accept it. So add platform:Linux, to the end of what you currently have. Remember to include the trailing comma. Give that a try and let me know the results.

Thanks for the info about the mapping tool, I will see if I can find a replacement.

@cwajh
Copy link
Author

cwajh commented Mar 6, 2022

Huh, that's good to know. The ones Steam generates seem to put platform near the beginning instead. I'll try moving it to the end.

@cwajh
Copy link
Author

cwajh commented Mar 6, 2022

New contents of controller config file:

03000000250900000017000010010000,HuiJia PS/SS/N64 Joypad to USB BOX,a:b0,b:b1,y:b4,x:b3,start:b8,leftshoulder:b6,rightshoulder:b7,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13,lefttrigger:b5,righttrigger:b2,platform:Linux,

Output of SDL_GameControllerAddMappingsFromFile() is identical to before.

I still see SDL_JOYDEVICEADDED and not SDL_CONTROLLERDEVICEADDED at app launch.

However, if I then unplug and plug back in the game controller while the app is still running, the subsequent plug-in will be detected as a SDL_CONTROLLERDEVICEADDED and everything works.

Is SDL_GameControllerAddMappingsFromFile() being called too late during initialization somehow, such that the initial scan of joysticks/gamepads doesn't yet recognize it as a controller?

@cwajh
Copy link
Author

cwajh commented Mar 6, 2022

...just out of curiosity I tried moving the SDL_GameControllerAddMappingsFromFile() call to immediately after SDL_Init() but it did not help.

@cwajh
Copy link
Author

cwajh commented Mar 6, 2022

OK, I've gotten something in my local environment that "solves" the issue for me (whether it's a real solution or just a dirty hack I'll leave to someone who actually knows their way around SDL 😂).

After adding the mappings from file, I check if there's already a gamepad at the position specified in config.ini, and if so, add it immediately.

  if(SDL_NumJoysticks() > config.gamepad_device) {
    if(SDL_IsGameController(config.gamepad_device)) {
      output_log(LOGLEVEL_DEBUG, "Gamepad is already connected with device index %i\n", config.gamepad_device);
      connect_gamepad(config.gamepad_device);
    }
  }

With this my controller can be used right away, without having to unplug & replug it.

@complexlogic
Copy link
Owner

OK. SDL will push a bunch of initial events onto the event queue when it's initialized. I'm assuming that since we call SDL_GameControllerAddMappingsFromFile() after this initial event push, the game controller connection event doesn't get pushed since it was actually connected prior to when SDL initialized. Try something like this in the main event handling loop:

case SDL_JOYDEVICEADDED:
  SDL_JoystickGUID joy_id = SDL_JoystickGetDeviceGUID(event.jdevice.which);
  if (event.jdevice.which == config.gamepad_device && SDL_GameControllerMappingForGUID(joy_id) != NULL) {
    SDL_Event joy_event;
    joy_event.type = SDL_CONTROLLERDEVICEADDED;
    joy_event.cdevice.which = event.jdevice.which;
    SDL_PushEvent(&joy_event);
  }
  break;

This would effectively "forward" the joy event as game controller event so we can properly connect the device via the game controller subsystem.

@complexlogic
Copy link
Owner

On second thought, it looks like SDL pushes both a joy event and a game controller event when a recognized gamepad is connected, so we would have duplicate events in that case. Probably not an elegant solution.

@complexlogic
Copy link
Owner

complexlogic commented Mar 7, 2022

After some thought, I believe the most straightforward solution is to just use the joy events and check whether the given joystick device is a valid game controller. By the time this is evaluated in the main event loop, the new mapping will have taken effect.

I uploaded my proposed fix in a new branch gamepad_fix. Diff is here. I would appreciate it if you could clone the branch and build it to see if it fixes the problem.

@cwajh
Copy link
Author

cwajh commented Mar 7, 2022

I gave it a test run and it seems to work great!

@complexlogic
Copy link
Owner

Good to hear. Thanks for your help in debugging this issue. I'll merge this fix now.

And thanks for the heads up on the incorrect handling of the return value of SDL_GameControllerAddMappingsFromFile(). I updated it so it's correct now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants