Allegro.cc - Online Community

Allegro.cc Forums » Allegro Development » Controllers configuration

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Controllers configuration
Max Savenkov
Member #4,613
May 2004
avatar

Instead of re-inventing the wheel, it might be easier to ask SDL for permission to use their list and re-implement their hash algorithm. We'll also be contributing back to them by populating their list as we see new ones.

Well, it's open source, so we don't even need a permission. Allegro borrows a some code from SDL already, from what I see :)

That does not exclude a special app for extending SDL database, though. It would be useful anyway. But it would have to be cross-platform, preferably for all supported platforms, which makes it somewhat harder.

Also: on platforms where vendor/device ID is unavailable, SDLs way of using first letters of device name is still a bad idea and should probably be fixed.

EDIT: I've looked at things a bit close and noticed a very bad thing. My gamepad is in XInput mode, and is reported as XInput device. All XInput devices should have the same controller configuration ("xinput" entry in SDL's db). However, I'm pretty certain my gamepad does not match this configuration at all! For example, according to SDL's db, A button should have index 10, but in my experience, it have index 0. Also D-Pad is 4 buttons for purposes of SDL's db, but Allegro sees my D-pad as a stick! So maybe my Logitech is a bad XInput device, or Allegro and SDL handle joysticks too differently. In any case, more investigation is needed before any commitment to be made on this plan.

EDIT2: Ah, so Allegro already does some reverse mapping for XInput devices in joyxi_convert_state (wjoyxi.c). So that's why I'm seeing differences in Allegro buttons/sticks indexes and mappings from SDL's db file. That's going to make things harder unless we can change it to coincide with the "xinput" string from SDL, and we probably wouldn't want to, since some older code may already depend on it. One solution would be to create a different default "xinput_allegro" string.

EDIT3: I ported SDL code for generating joystick GUID to Allegro, but encountered another problem: SDL treats "hats" (including D-pads) as buttons, but Allegro treats them as digital sticks. I'm presently somewhat stumped about what to do here.

SiegeLord
Member #7,827
October 2006
avatar

I'm confused how those things matter for the GUID side of things... wouldn't they be only of issue for decoding the mappings?

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

beoran
Member #12,636
March 2011

@Max, Yes, Allegro maps joysticks differently then SDL does it. That is because in many cases, IMHO, SDL's mapping is wrong. Especially for XInput, I think Allero's maping is better, since I wrote that driver. :) This means that we'll need our own mapping database. It could be just an .ini file as Alero laready has an excellent .ini parser.

@SiegeLord: you are right. The only thing we need to add in Allegro's core is a al_get_joystick_guid() API. What Max proposes should go into an official or unofficial add-on library.

Max Savenkov
Member #4,613
May 2004
avatar

Oh, I just got a little ahead and started writing an addon too (since I really need it for my purposes right now, and just GUIDs without it would be useless to me).

For now, I'm still considering using SDL database, but do some tricks to make it compatible with Allegro, for the simple reason that building and maintaining another database is beyond scope of my interests. Anyway, when we have GUIDs, everyone could make their own database :)

Chris Katko
Member #1,881
January 2002
avatar

We could as a compromise, support both.

Have two lists. The SDL list*, and the Allegro list. The Joystick handler searches for Allegro entries, and failing that, uses an SDL-friendly parser on the SDL list.

That way, we only use their data as a fallback, and things like his controller saying "Xinput" when it should be PS3/4/whatever will would work. But we still have their database for legacy controllers.

*(letter-for-letter, or, write a small tool that converts it, so we won't have to do it by hand every time they update.)

I was going to suggest a tool to convert their mapping to our mapping, but since we build data differently, it likely wouldn't work.

[edited, sorry bro]

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

Thomas Fjellstrom
Member #476
June 2000
avatar

It could be handy to have a script that converts the sdl mapping to allegro compatible mapping. That way we can have the best of both worlds :D

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Max Savenkov
Member #4,613
May 2004
avatar

I'm still stuck with hats. They pose a problem. We can only convert them to Allegro terms in runtime, or not at all. For Allegro, "hX" should mean "Xth digital stick" and "aY" "Yth analog stick". Since Allegro keeps all the sticks in the same array, it's not possible to map SDL values to Allegro stick indices until we have ALLEGRO_JOYSTICK (i.e. not during loading of database file), and even then it's not straightforward.

SiegeLord
Member #7,827
October 2006
avatar

Can we put all digital sticks first followed by the digital ones? So hX would be the X's stick, and aY would by the max(X) + Y's stick?

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Max Savenkov
Member #4,613
May 2004
avatar

Well, yes, but we'll have to change the way Allegro fills sticks arrays for all platforms and, preferable, store max(X) for quick reference somewhere. Might as well have a different arrays for digital and analog sticks, then.

SiegeLord
Member #7,827
October 2006
avatar

I guess I still don't understand the issue. If you map the Allegro axis indicies to descriptive names, it doesn't matter what order they are. Conversely, mapping descriptive names (enum constants in this case) to axis indices is also possible regardless of order. All we have to rely on is that SDL's way of filling out the b's and a's is consistent, so we can interpret the database correctly.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Max Savenkov
Member #4,613
May 2004
avatar

Maybe I'm just slow, but let's talk pseudocode here.

So, we have a structure where mapping information is stored, like this:

struct Mapping
{
   ALLEGRO_CONTROLLER_BUTTON buttons[ MAX_BUTTONS ]; // simple index -> name map
   ALLEGRO_CONTROLLER_AXIS axes[ MAX_AXES ]; // here, troubles begin
};

Then, we read configuration from file:

#SelectExpand
1if ( button ) // Button mapping with format "bIndex:Name" 2{ 3 mapping.buttons[ Index ] = Name; 4} 5else if ( axis ) // Analogue stick with format "aIndex:Name" 6{ 7 // What to we do here? 8 // We can't simple write mapping.axes[ Index ] = Name 9 // because we don't know how to translate "Analogue stick #Index" into Allegro index 10} 11else if ( hat ) // Digital stick with format "hIndex.Direction:Name" 12{ 13 // What to we do here? 14 // We can't simple write mapping.axes[ Index ] = Name 15 // because we don't know how to translate "Digital stick #Index" into Allegro index 16}

Then, when user asks us to map index to meaningful name, we do this:

ALLEGRO_CONTROLLER_BUTTON al_get_controller_button( ALLEGRO_JOYSTICK *joy, int button )
{
   Mapping *mapping = _al_find_mapping_for_joystick( joy );
   return mapping->buttons[ button ];
}

ALLEGRO_CONTROLLER_STICK al_get_controller_stick( ALLEGRO_JOYSTICK *joy, int stick )
{
   Mapping *mapping = _al_find_mapping_for_joystick( joy );
   // What do we do here?
}

The best I can come up with, is to store mapping for analogue and digital sticks separately, and do this:

#SelectExpand
1ALLEGRO_CONTROLLER_STICK al_get_controller_stick( ALLEGRO_JOYSTICK *joy, int stick ) 2{ 3 Mapping *mapping = _al_find_mapping_for_joystick( joy ); 4 bool isDigital = ( al_get_joystick_stick_flags( joy, stick ) & ALLEGRO_JOYFLAG_DIGITAL ) != 0; 5 int indexInMapping = -1; 6 for ( int i = 0; i= < stick; ++i ) 7 { 8 bool testStickIsDigital = ( al_get_joystick_stick_flags( joy, i ) & ALLEGRO_JOYFLAG_DIGITAL ) != 0; 9 if ( isDigital == testStickIsDigital ) 10 ++indexInMapping; 11 } 12 13 if ( isDigital ) 14 return mapping->digitalSticks[ indexInMapping ]; 15 else 16 return mapping->analogueSticks[ indexInMapping ]; 17}

I don't like this, because of linear search for each call to al_get_controller_stick. On the other hand, the cycle is actually pretty small, and this function should not be called too often anyway (ah, this is a dangerous supposition...).

If you see a better way, I'd be glad to see it.

SiegeLord
Member #7,827
October 2006
avatar

I was thinking just reverse engineering Allegro's and SDL's joystick codes and creating the mapping that way.

But anyway, if your only issues are the ones you mention, then you could just cache the mapping when you invoke one of those functions. I.e.

#SelectExpand
1Mapping *_al_find_mapping_for_joystick(ALLEGRO_JOYSTICK* joy) 2{ 3 Mapping *mapping = /* Find mapping by GUID somehow */; 4 5 al_lock_mutex(mapping_mutex); 6 if (!mapping->initialized) { 7 int digital_idx = 0; 8 int analogue_idx = 0; 9 for (int ii = 0; ii < al_get_joystick_num_sticks(); ii++) { 10 if (( al_get_joystick_stick_flags( joy, stick ) & ALLEGRO_JOYFLAG_DIGITAL ) != 0) { 11 mapping->sticks[ii] = mapping->digital_sticks[digital_idx]; 12 digital_idx++; 13 } 14 else { 15 mapping->sticks[ii] = mapping->analogue_sticks[analogue_idx]; 16 analogue_idx++; 17 } 18 } 19 mapping->initialized = true; 20 } 21 al_unlock_mutex(mapping_mutex); 22 23 return mapping; 24} 25 26ALLEGRO_CONTROLLER_STICK al_get_controller_stick( ALLEGRO_JOYSTICK *joy, int stick ) 27{ 28 Mapping *mapping = _al_find_mapping_for_joystick( joy ); 29 return mapping->sticks[stick]; 30}

By the way, what happens to al_get_controller_stick when the joystick doesn't have a mapping?

Also, have you considered having an ALLEGRO_JOYSTICK_MAPPING as a public type? I'm not necessarily saying it's better, but it does fit more nicely into some of these issues.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Max Savenkov
Member #4,613
May 2004
avatar

I didn't thought of caching sticks on the first access, thanks.

SiegeLord said:

By the way, what happens to al_get_controller_stick when the joystick doesn't have a mapping?

ALLEGRO_CONTROLLER_STICK_INVALID is returned. But there is al_has_controller_mapping( ALLEGRO_JOYSTICK *joy ), so you can check if mapping is present for this controller.

Quote:

Also, have you considered having an ALLEGRO_JOYSTICK_MAPPING as a public type? I'm not necessarily saying it's better, but it does fit more nicely into some of these issues.

Well, it's actually quite a big structure, with both forward and reverse mappings, and now, with cached values for digital/analog sticks... I don't know about exposing it, it seems a bit too complicated for user-accessible type.

EDIT: Surprise! Why does Allegro always think the first stick on DirectInput device always has 3 axes? This leads to a rather funny effect on my Logitech gamepad in ex_joystick_events, and also completely throws off mapping for sticks+axes.

EDIT2: You know what? I'll just make a patch that adds GUIDs for joysticks, and create exactly two mappings for my game, in my own code: one for generic XInput gamepad, and one for generic DirectInput. Everyone else will have to suffer. I don't want to waste any more time on gamepad support right now :(

SiegeLord
Member #7,827
October 2006
avatar

Hah, that's a shame... do publish the incomplete addon code though, in case somebody wants to continue your work. It occurs to me that we can add an allegro5.cfg flag for perhaps changing the weird inconsistencies like that.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Max Savenkov
Member #4,613
May 2004
avatar

I've attached the code for it, and also a patch for al_get_joystick_guid (because addon won't work without it). Both addon and patch are not in good shape, i.e. they don't conform to Allegro code standard (because I was writing them with the default Visual Studio settings, with a plan to indent them correctly later) and may contain bad and/or temporary code.

Also of note: one of the worst problems is D-Pad. On some gamepads, it's a stick, and on others it's a set of four buttons, so it's hard to map it consistently (the same goes for triggers). Also, Logitech gamepads has "Mode" button, which helpfully swaps D-Pad and the first analogue stick without telling your program anything (so the D-pad becomes analogue, and the first stick becomes digital). Have fun.

Seriously, though. I never thought that gamepads are so badly messed up. And don't forget flight controllers! Actually, DO forget them, because there is no way to distinguish them from gamepads (lacking a guid database), but you'd need a completely separate set of graphic icons and button/stick names if you want to show them to user. So unless you're writing a flight simulator, I think it's safe to leave them unsupported (I still remember playing Batty (an advanced Arcanoid clone on ZX Spectrum) with a joystick; it was an awful experience, but I was too young to know better and use keyboard).

beoran
Member #12,636
March 2011

Oh yes, implementing joystick and haptics (force feedback) drivers for Allegro taught me a thing or two. Game controllers are seriously messed up.

Not only do the different operating systems each map axes and buttons differently, Windows and OSX have several incompatible API's to deal with them (DirectInput, XInput, etc) . And the hardware is all over the place, especially if you take the bewildering variety of joypads, joysticks, steering wheels, flight controllers, train controllers, etc. into consideration.

That's why what SDL is doing is verly simplistic, really. A true game input device database should take all of these details into consideration. Which would be an epic effort, no doubt. We will always have to program a "configure joystick" screen to let the user map their own device as they like it. Just providing an UUID for every joystick and giving some additional support for the "most popular" ones is probably the best you can do.

Max Savenkov
Member #4,613
May 2004
avatar

I looked into FIFA 14 resources and discovered that EA still maintains their huge database of gamepads. Of course, being a soccer sim, they do not offer support for anything BUT gamepads, which simplifies things a little.

I wish I could just grab EA's database and plug it into my game (or SDL, or Allegro), but it would violate copyright law, no doubt :( Also, it would only be usable on Windows. Also, they use device names for mapping instead of any kind of other IDs.

Chris Katko
Member #1,881
January 2002
avatar

I wish I could just grab EA's database and plug it into my game (or SDL, or Allegro), but it would violate copyright law, no doubt :(

Are phone number listings copyrighted? I don't know. I mean, if I post a bunch of phone numbers on my page for other people I'm not affiliated with, and you repost them, are you infringing? Now, instead of phone numbers, we're listing numbers of buttons.

But side stepping that, are there any other public domain games/projects that have joystick data? Certainly some other GPL (is Allegro 5 GPL?) projects should exist somewhere.

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

Max Savenkov
Member #4,613
May 2004
avatar

Actually, a simple search for "Logitech Wingman" (or other gamepad name) in open-source code search engines brings some results, though nothing really comprehensive. Most such databases are hidden inside game codebase, or in game resources, so I don't quite know how to search for them. Maybe if we knew one game or library that have a REALLY good support for various gamepads? :) Nothing comes to mind right now...

beoran
Member #12,636
March 2011

I looked for such a thing too but there doesn't seem to be an in-depth open source database of game controllers out there. A well-structured ini file and some image files with schematics of the device would probably be enough to store the data. But we'd need a lot of people to supply information for their hardware/OS/API combination... Not an easy task, I'd say, but I'd applaud anyone who'd give it a go.

Chris Katko
Member #1,881
January 2002
avatar

If you made a cross-platform app (binary!) that sucked all the information from people's computers as long as they had the joysticks plugged in, I'm sure many people wouldn't mind running it.

Also, REMEMBER, Gameports are depreciated on many systems (Windows since what... Vista?). So that knocks out the majority of the hardcore gaming market boom.

I've got 360 controllers with the wireless receiver (they can also be USB, supposedily). I've got tons of old gameport joysticks, pedals, and steering wheels I've picked up second-hand but who knows if that matters. Just make sure you can specify a custom entry and I'll be happy, because I plan on doing custom HID work.

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

SiegeLord
Member #7,827
October 2006
avatar

Alright, this now lives in a branch in my Allegro5 fork on github: https://github.com/SiegeLord/allegro5/tree/controller_database . This is sort of low priority for me to get around to (compared to other things, not because I don't think this would be a great addition), but eventually I'll try to take another look.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

 1   2 


Go to: