Recommended Posts

Hello all-
I'm writing a game engine (of course) and I want to support gamepads.
The most common use case will be various common gamepads (PS2, Xbox, etc.) plugged in via a USB port, and that's what I'll support for now. Other connection methods can be supported later.
I've got a couple of PS2 gamepads, and a few USB adapters for testing.
I've found that SDL works great to find the gamepads, and get input.
However, SDL models each gamepad as multiple joysticks and lots of independent buttons. I guess that kind of makes sense: the PS2 gamepad has two joysticks and 16 buttons, for instance.
However, every USB adapter seems to map them differently! For instance, I have a single-gamepad USB adapter, and it maps a single gamepad as two joysticks and 16 buttons (duh).
I have another USB adapter which supports two gamepads. It produces 4 joysticks and 32 buttons. However, the joystick and button mapping is very different than the other USB adapter! And the joystick and button indices are interleaved.
To put it simply, I can't figure out what's going on with a gamepad unless I add my own mapping layer that accounts for the quirks of different USB adapters.
Is this already solved? Is there a good multi-platform library that just presents gamepad objects, and hides all the details underneath? Or have people had to solve gamepad joystick/button mapping on their own?
-Thomas

Share this post

Link to post

Share on other sites

I am not sure, but there may be better libraries to accomplish what you're after. However, I do not see why SDL could not accomplish this with some extra support.

Why can't you have a user calibration? Say you have 10 needed buttons (for example): up, down, left,right, jump, fire, super attack, etc, etc. You can then have a user calibration process. Since via SDL you can detect all the gamepad inputs, you can just ask the user what button should be associated with what action. For example, tell the user press the fire button... you detect something via SDL; assign this detection to be action, "fire".

So who cares if you detect 4 joysticks and 20 buttons or 8 joysticks and 32 buttons, you will simply ask the user to map them. And this should be possible unless SDL has a problem with detecting some gamepad input.

You can then save this input as a user configuration so that it is not required to be entered every time the user wishes to play. Of course you can have a default 'guess' configuration and the user can use this if it works or use the gamepad calibration process outlined above if it doesn't.

This may not be the most elegant solution, but maybe it's all SDL can do. That's what I could come up with. I'd be interested in a more elegant solution, if one exists, with SDL or without. Hope this helped a little.

0

Share this post

Link to post

Share on other sites

Yes, autoconfiguring the mapping layer is a good fallback. It is surprisingly complicated, though, and could be error-prone. Multi-gamepad adapters will have a large variety of buttons, and it gets confusing with additional gamepad options such as rumblepads and the Analog mode on PS2 pads, for instance.

I guess what has surprised me has been the lack of conformity among different USB adapters. I was hoping I could write quick gamepad layer and be done with it! But what I've found is that every adapter is different, and either I need to build a registry of USB adapter mappings (ugh) or ask players to configure and build this registry themselves.

I think a good model may be the unix printing system (CUPS). They distribute a bunch of common printer configurations with their base package, but also make it easy for people to upload and download new configurations as needed.

And for gamepads, autoconfiguration is probably a better option, since many players won't have the skills or patience to build out adapter files on their own.

The bottom line: it sounds like there is no good gamepad library today! I may try to start one, built as a thin layer on top of SDL...

-Thomas

0

Share this post

Link to post

Share on other sites

signal explained it pretty well, normally what you do is on your page to configure your controls, when you select a control for you game to configure, the user presses the button/axis they want to use and you save that mapping. It doesn't really matter how many analog sticks, buttons or whatnot the gamepad has, or that different adapters order the buttons differently, most gamepads don't have anywhere near the same ordering anyways. The reason the adaptors are all different is because it doesn't particularly matter what order the buttons are presented in, and they just happened to choose the ordering differently when they were built.

I guess maybe we're not understanding what your issue is

0

Share this post

Link to post

Share on other sites

This is a problem with no real solution as of yet. Microsoft caved on the whole issue and built the XInput API to handle it after the action mapping in DInput didn't take, in a "conform to our ways, or else" type of strategy.

The XInput API maps best to the consoles, if that's your concern. The controllers themselves differ enough to warrant a little rethink of how the controls are working, though (SIX-axis, rumble, wii-nunchuck, etc.).

If you want to support the "other" APIs on PC, that'll be a lot of work, because nothing conforms to anything. The config screen suggested would probably be best.

There are hundreds of different controllers/drivers for PC on the market, and nothing matches up.

Share this post

Link to post

Share on other sites

There are hundreds of different controllers/drivers for PC on the market, and nothing matches up.

Thanks Morten! Good to get some of the backstory. That is indeed what I've found.

Quote:

The controllers themselves differ enough to warrant a little rethink of how the controls are working, though (SIX-axis, rumble, wii-nunchuck, etc.).

Yes, I think I'll have some sort of base gamepad object (standard buttons and sticks supported by most common controllers), and then people who need additional capabilities (six-axis, rumble, etc.) can query to see if it's supported. And exotic controllers like nunchucks may require a different interface.

Quote:

I guess maybe we're not understanding what your issue is

Raptor: the main problem is that different USB adapters (and the controllers themselves) represent inputs differently. As a programmer, it is hard to figure out which axis corresponds to which stick on the gamepad, and button mapping is (as far as I can tell) completely random.

Here's an example: One of the USB controllers I've got supports two Playstation 2 gamepads. It's great: I can plug the two gamepads in, and see axis/button values in SDL. However, the way all this information is exposed is completely random. There are 8 axis variables (x,y values for 2 sticks on each of 2 controllers), but they aren't in any particular order. You'd think there'd be some ordering (first 4 axis variables are for the first controller, second 4 axis variables are for the second) but there isn't. You have to wiggle each controller's sticks to find out which axis index corresponds to which stick.

Likewise, I get 32 button values back from SDL. But they aren't ordered at all. The button values for the 16 buttons on the two gamepads are completely intermingled, and in a different order. The only way you can tell which button value maps to which physical button on a particular gamepad is by testing.

Once I figured it out for that USB adapter, I plugged in a different one. Again, all the axis/button mappings were different! So all of the mapping I did for the first controller had to be redone for the second. I can't code the mapping into my game, because if someone plugs in a different USB controller and tries to use a gamepad, I'll get axis/button values wrong. The mapping changes by model and manufacturer.

So there is a lot of work (mapping) to do, just to figure out how all the random axis/button values from SDL map to what's actually happening with the gamepads (and I don't think this is SDL's fault).

The annoying thing for players is that there may be two configuration steps required. The first step is just to figure out how to interpret the player's controller. That's the new, difficult configuration step required here.

Once you do that, you have the second, more common configuration (invert y-axis, reassign buttons to game actions, etc.).

Hopefully that made some sense.

0

Share this post

Link to post

Share on other sites

I don't know if this will be of any use to you, but I was accepting PS2 controller input using joyGetPosEx. As far as I know, this is the "generic" way of accepting game pad input in Windows - and for as long as I've used it, the values have been fixed each time (e.g. JOY_BUTTON8 is always R1, .dwYpos is always altered by moving the left stick up or down, etc).

It's very simple to use, though the one complication I came across was that calling joyGetPosEx for the first time doesn't return JOYERR_UNPLUGGED or any of the listed messages if the pad isn't plugged in... so if you're checking for that like you're "supposed" to, you'd detect the controller every time. I instead made it check for JOYERR_NOERROR and then proceed if true.

Hopefully this helps some.

0

Share this post

Link to post

Share on other sites

The key mappings on game controllers are just all over the place. You aren't going to find some kind of standard where 'A' = 'X' = '1' on different controllers. It would be nice if the regular d pad and four normal buttons mapped the same on every controller but it just isn't there. You are going to have to have the user map the buttons how they want them to work rather then expect every button to match up. I think most PC users who play with a gamepad are pretty used to doing this. I know I always check out the button bindings the first time I play a game.

I'm sure if you wanted to you could make some kind of gamepad API where it gets what controller is attached and has a button dictionary so when you query 'left top trigger' you get the correct button no matter what the actual physical button is. Something like this would probably be quite usefull actually (if it doesn't already exist).

0

Share this post

Link to post

Share on other sites

As Morten was alluding to, the state of joysticks and gamepads on the PC is increadibly unstandardized. That's why DInput was such a bloody mess (that and having to support everything from a 2-button gamepad, all the way up to a full flight-sim cockpit.), which is why proctically no one save the flight-sim crowd supported it.

3 - Limit support to just a few controllers/adapters and hard-code support for them.

With Xbox360 controllers, the XInput API is well unified. You won't see differences between first or third-party controllers or even peripherals like DDR dance mats or RockBand/GH peripherals -- Up is always up, and red is always red.

I believe also, that PS3 controllers can be supported on PCs with blueTooth as a BlueTooth HID device, and that should be standard across all wireless PS3 controllers. Of course, the number of people with Bluetooth installed in their gaming PC (usually desktops) are limited -- that said, BlueTooth is fairly common on laptops, so if your engine targets games that would be at home on a laptop, putting in this support might be worthwhile.

I'd honestly not try to support the multitude of console-to-USB adapters unless that's through a general re-mapping system, there's just far too many variations, as you've seen already.

0

Share this post

Link to post

Share on other sites

I have found SDL to be pretty sweet 9/10. But, always a but: I have found that under Linux vs under Windows, the same pad, on the same computer, will be exposed differently by SDL between Linux and Windows. However, this in not exactly SDL's fault: it is just a wrapper over some other deal: in Windows it is DirectX in Linux it is the joystick library (reading from /dev/input/js*) and for the console-to-USB adapters I have seen oddball things (like extra axis and such). What really smells bad is that there is this standard called HID, and the pads are supposed to be following it, so how on earth does Linux get an extra (non-existent) axis that Windows does not?!

In my experience, SDL has modeled a fixed pad(like a PS2 look alike or PS2-USB adapter) with many axis's as one joystick with many axis, but depending on the OS, the D-pad gets mapped to an axis or a hat. For PS2-USB adapters, it is often a random function, and highly OS dependent (one I have I think is exposed as one pad under one OS but as two pads under another). Sighs.

I totally agree with others advice here, to implement a remapping, ala controller settings, in your application (not taking into account anything exotic like motion sensitive stuff) and present each direction of each axis of application as configurable. Some games that I thought did this really well where Descent 3, Descent Freespace 2, X-Men Legends. Another good example of a good mapping UI and methodology are console emulators. I *hate* it when games are hard wired to a few controllers (Devil May Cry 3 for PC was quite guilty) Especially for those PS2-USB adapters the axis and button mappings are often just odd ball, yet those old PS/PS2 controllers are absolutely wonderful to use to play. Also a good idea is to use the joystick name, not the number when saving the mapping, as the number is dependent on the order the joystick was plugged in).