Closed DanTheMan827 closed 3 years ago
Can you take a look at the changes I made to input.cpp earlier. I'm hoping that this automatically sets up sensible controls using gamecontrollerdb.txt. The mapping I created in void Input::open_joy() appears to setup my controller ok and map the buttons correctly automatically. I implemented this as it was clear the proposed change with the gamecontrollerdb.txt file actually did nothing...
Oh, I didn't see those commits, my issue was based on the code as of last night...
I'll give that a shot, but it seems like that may work since you grab the button index on joy connect if it's a gamepad.
Using SDL_CONTROLLERBUTTONDOWN
, and SDL_CONTROLLERBUTTONUP
gives you consistent button indexes, but now it seems you just went for a static button assignment without remapping support through config.xml?
gamecontrollerdb.txt also takes care of axis mapping, so say you have a weird controller that has the directions reversed and up is down, down is up, and so on, gamecontrollerdb.txt has that info and SDL2 provides APIs for reading the intended buttons/axis values
Or say you have something like a DualShock3 that has a ridiculous number of axes (27)
You could actually create a gamecontrollerdb.txt line for that controller that maps motion to the left analog stick so you could use it like a steering wheel.
The button mapping logic seems sound, although not really the way sdl2 expects it do be done, there are different events for controller and joypad input, and on a controller the d-pad is actually a series of buttons.
SDL_CONTROLLERBUTTONDOWN
SDL_CONTROLLERBUTTONUP
SDL_CONTROLLERAXISMOTION
SDL_CONTROLLERDEVICEADDED
SDL_CONTROLLERDEVICEREMOVED
I don't think it sends those events for unmapped buttons in the case of an unknown controller though, which is probably why OpenLara also has a fallback for:
SDL_JOYBUTTONDOWN
SDL_JOYBUTTONUP
SDL_JOYAXISMOTION
SDL_JOYDEVICEADDED
SDL_JOYDEVICEREMOVED
FYI, I did test the commits you made, and they don't seem to have made any difference, the mappings are still different between controllers.
I find the fact this doesn't work for you a bit baffling. If I don't setup ANY mappings at all for my 360 controller (e.g. I use the default config.xml file where everything is set to '-1'), the code I've written correctly assigns everything perfectly - all analog and digital controls. Whilst I can imagine that for some controllers the mappings would seem sub-par, I don't understand why they wouldn't work full-stop. I haven't coded anything that's 360 specific after all. I just detect it as a game controller and then request the controls to be assigned to sensible buttons.
Short of actually getting a different controller, I'm going to struggle to guess how to fix this further. Can you set some break points in the code and figure out how it's going wrong for you? Can you send me details of which buttons on your controller the CannonBall controls get assigned to?
FYI, I did test the commits you made, and they don't seem to have made any difference, the mappings are still different between controllers.
I suspect you may have mis-interpreted my code.
Just to clarify it works as follows:
1/ If the controller is not configured at all (buttons/axis set to -1 in config.xml) it will attempt to assign the axis and buttons automatically to something sensible (e.g. accelerate is right trigger, brake is left trigger, start is start etc.)
2/ Once configured, this process will never take place again. So swapping a new different controller in wouldn't trigger a reconfiguration. So just to clarify - If you are swapping controllers, then you will need to manually go back and edit the config.xml currently, to force the buttons to be reassigned. I can add a "reset controls to default" option in the menu, but until the initial mapping is proven to be working, I'm holding off on this. The other option is to check whether the newly inserted controller has a different ID to the previously configured one, and then perform step 1/ again.
3/ The automatically assigned controls can be remapped through the in-built configuration menu. So buttons and axis can be reassigned by the user. Regardless of what is done in Step 1/, I still want to provide the flexibility for the user to change the button mapping to whatever they want.
4/ Everything works perfectly for me. Argh. :-D
"It works fine on my machine" 😂 And that's why docker exists...
Kidding aside, the proper way for handling the mapping would be to store the controller button number (not joypad) in the config and compare the input given by the game controller events (again, not the joypad events) to the ones assigned in the config file.
This way it wouldn't matter if you changed controllers or not, all pads would have the same controller button indexes for the buttons based on their physical position on the pad (SDL2 is based around a 360 layout)
So if you checked for a controller button of Y, it would also give you that value with a PS3 controller for the triangle button, even if you swapped controllers with the game running.
I hope you understood I was joking with point 4!
And I think you're just reiterating what I wrote in point 2 with regard to storing in the config.xml?
What I'm trying to get to the bottom of is whether it works for other controllers. Can you confirm whether your controller is working?
I've gone through the implementation line by line in the debugger and all seems in order.
If it is working, then I can go and finish the implementation and close this bug. The comment in the discussions forum seems to suggest it is, at least, working for [one entire other person other than myself] (https://github.com/djyt/cannonball/discussions/76#discussioncomment-507328).
Yeah, I knew you were joking with 4
I'm not saying your code doesn't work, I'm just saying that it doesn't work as one would expect if you switch controllers.
there's the joystick and gamecontroller methods to read the pad, but it doesn't really make a whole lot of sense to use gamecontroller just to get raw button values for joystick when you could just use gamecontroller to read the values in the first place since that abstracts the actual buttons and gives you virtual ones in the layout of a 360-style controller.
Regarding point 2, since it auto-configures to one controller you can't then swap controllers and expect the proper mapping afterwards, your code would work and give the appropriate mappings one-time, but it you use the controller method like in #80, you can use any controller and switch them out even after the first time.
With your code as you describe it, I can't plug in a 360 controller, play the game, and then swap in for a PS3 controller (or any other really) without then manually re-mapping the controls, but with the controller interface, the controller wouldn't matter since the buttons and axes are abstracted to a virtual controller that doesn't change from one physical controller to another, it's just an abstraction that SDL2 provides to make things easier.
In regards to point 3, #80 still provides the ability to remap, the only difference is that the config values stored are that of the abstracted controller and aren’t dependent on the physical pad connected.
In the event that the controller connected isn’t in gamecontrollerdb.txt, it will fallback to using the joystick interface as before
Awesome, thanks for the information and help on this.
I'll take a look at the pull request in the coming days. As you say, this may well be a better solution.
Merged #80 in - looks good!
Got to move on and get haptic working at some point when I have some spare time!
Hmm no sadly on further inspection #80 created two problems for me:
I will go back and review at a later date, but I've reverted as it left the codebase in a non-working state.
That’s weird, I didn’t try remapping the analog, but I did test with a 360 controller on Ubuntu 18.04 and it worked fine for analog controls
hopefully this is still useful though
Yes, I'll investigate a little further at some point.
It's another damn example of "works for me" - I couldn't see anything wrong with your code by eyeballing it (I didn't have time to go through with a debugger to track down the cause), but it unfortunately didn't work for me out of the box at least. 🙃
I had a short amount of time to look into this. Your implementation was pretty much there, but I made the following changes, which you can review in commit 711bbe7 - Improved Support for SDL 2 Controllers.
1/ The values returned by analog trigger buttons differs between the SDL Joystick and SDL Controller implementations.
With the XBox 360 pad, the trigger values returned are different depending on whether it's initialized as a controller or joystick. I guess this is to be expected, as the SDL controller class is designed to normalise input behaviour.
This caused the analog controls to get 'stuck' on in your initial implementation with the 360 pad.
I now detect between joystick and controller and scale those inputs appropriately. I assume that all controllers fall between the range specified above. I assume all joystick trigger buttons use the alternate range. The latter of these two assumptions could be incorrect and I would need to test on a wider range of non-controller joysticks.
Also, it's possible that the above behaviour is specific to Windows, and if you were testing on Linux, you may have not encountered the same issue!
2/ I made a minor change to avoid capturing controller insert/removal events as this caused the initialization code to be called twice. All controllers are caught by the joypad event.
It looks good, but you don't check if controller is set in handle_joy_hat
I'm not sure if you could get double inputs there or not since the hat would also be mapped by gamecontrollerdb.txt
Thanks, yep I spotted that (and changed it) shortly after writing to you.
It doesn't seem to impact anything, but I'd agree it's bad practice to leave it like that! :)
SDL2 has two ways to handle input from gamepads, the controller interface and the joypad interface, when reading joypad buttons, you get the raw button index from the controller, when reading the controller interface you get an abstracted button index mapped according to the gamecontrollerdb.txt file
The result of not using the controller interface is that the gamecontrollerdb.txt is effectively ignored and it uses the raw indexes.
Here's the SDL2 platform implementation for OpenLara to better show what I mean https://github.com/XProger/OpenLara/blob/master/src/platform/sdl2/main.cpp#L364
As you can see, it handles both controllers and joypads, this is because if there's no mapping for the controller, it will still be usable as a joypad.