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

Different game controllers, different mappings, same GUID #3197

Closed
SDLBugzilla opened this issue Feb 11, 2021 · 20 comments
Closed

Different game controllers, different mappings, same GUID #3197

SDLBugzilla opened this issue Feb 11, 2021 · 20 comments
Assignees
Milestone

Comments

@SDLBugzilla
Copy link
Collaborator

SDLBugzilla commented Feb 11, 2021

This bug report was migrated from our old Bugzilla tracker.

These attachments are available in the static archive:

Reported in version: 2.0.5
Reported for operating system, platform: Linux, x86_64

Comments on the original bug report:

On 2019-03-12 18:22:36 +0000, landeel wrote:

Hello, as reported here: https://discourse.libsdl.org/t/different-game-controllers-with-the-same-guid/25773...
I have two devices that have the same GUID under Linux, same vendor/product id, but they’re not exactly the same. One is from Dragonrise, the other is actually from Microntek.

Bus 002 Device 012: ID 0079:0006 DragonRise Inc. PC TWIN SHOCK Gamepad
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x0079 DragonRise Inc.
idProduct 0x0006 PC TWIN SHOCK Gamepad
bcdDevice 1.07
iManufacturer 1 DragonRise Inc.
iProduct 2 Generic USB Joystick
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 41
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0 No Subclass
bInterfaceProtocol 0 None
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.10
bCountryCode 33 US
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 101
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 10
Device Status: 0x0000
(Bus Powered)



Bus 002 Device 013: ID 0079:0006 DragonRise Inc. PC TWIN SHOCK Gamepad
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x0079 DragonRise Inc.
idProduct 0x0006 PC TWIN SHOCK Gamepad
bcdDevice 1.07
iManufacturer 1 Microntek
iProduct 2 USB Joystick
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 41
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0 No Subclass
bInterfaceProtocol 0 None
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.10
bCountryCode 33 US
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 107
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 10
Device Status: 0x0000
(Bus Powered)

They have different "iManufacturer", "iProduct" and "wDescriptorLength".

Also they have differences in the right stick axis mappings, which is the cause of my problems.

Is it possible for SDL to tell them apart, so I could use both at the same time, with the different mappings?

On 2019-03-12 21:16:54 +0000, landeel wrote:

Maybe you could allow something like that:

"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick,platform:Linux,iManufacturer:DragonRise Inc.,iProduct:Generic USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,"

On 2019-03-13 14:24:44 +0000, Ismael Ferreras Morezuelas (Swyter) wrote:

See also this bug with more information about conflicting gamepads and their lsusb dumps: mdqinc/SDL_GameControllerDB#202

Matching SDL2 Discourse thread: https://discourse.libsdl.org/t/duplicated-conflicting-guids-for-the-dragonrise-pc-twin-shock-controllers/24112/5

I guess we could add some extra discriminators other than VID and PID, these cheap no-name Chinese DirectShow gamepads are everywhere.

Unfortunately the USB descriptor reports are almost completely identical in most of the cases. At least they should have used different strings or descriptor sizes so that we could checksum them, but they even botched that.

Let me know if you need more data dumps from my controller.

On 2019-03-13 21:05:03 +0000, landeel wrote:

Funny fact: retroarch can tell my gamepads apart using the udev driver.

On 2019-03-13 21:12:14 +0000, Ismael Ferreras Morezuelas (Swyter) wrote:

I think I have compared the lsusb dumps for five or six controllers and most of them are seemingly identical (minus their physical button layout), your controller is a bit of an outlier and a bit easier to make out, I think.

Maybe there's a different way of finding an universal discriminator that someone that knows more about HID or USB internals can help with.

On 2019-03-19 21:25:34 +0000, landeel wrote:

Those are the mappings:

03000000790000000600000010010000,Microntek 0079:0006,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,

03000000790000000600000010010000,DragonRise 0079:0006,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,

Another difference, the Dragonrise one has 7 axes and the Microntek one has 6 axes.

Other possible solution would be specifying axes in the reverse order, from last to first.
Maybe something like that:
...,dpup:-a-0,dpdown:+a-0,dpleft:-a-1,dpright:+a-1,rightx:a-3,righty:a-2,...

This way the same mapping would work for both.

On 2019-06-12 03:21:40 +0000, Sam Lantinga wrote:

@Ismael Ferreras Morezuelas (Swyter), do the different devices you have all have the same name as well? If so, is there any other way to differentiate them?

On 2019-06-12 16:20:35 +0000, Ismael Ferreras Morezuelas (Swyter) wrote:

Created attachment 3822
ngs-phantom-usb-descriptor-dump.zip

On 2019-06-12 16:44:22 +0000, Ismael Ferreras Morezuelas (Swyter) wrote:

Used Thesycon's USB Descriptor Dumper (File > Save to file, and File > Save config descriptor as binary file) and attached it here. Download the tool: https://www.thesycon.de/eng/usb_descriptordumper.shtml

I only own this NGS Phantom gamepad (https://www.ngs.eu/images/productos/G300/NGS_phantom.jpg), the other lsusb reports were provided by other SDL2 community members in the linked GitHub reports and forum threads.

I will try to get a HID report dump from Linux soon-ish, to see if there's something interesting in there that can be check-summed. As you can see, my gamepad seems to have extra spaces in the name, but the Trust CXT24 from @DanielGibson and the Topway faux-dualshock and Defender Cobra R4 from @Akaricchi are also like that.

My lsusb report for the same NGS Phantom is here, you can also see all the other lsusb reports I mentioned after that: mdqinc/SDL_GameControllerDB#202 (comment)

Let me know what you think.

On 2019-06-12 17:30:17 +0000, Ismael Ferreras Morezuelas (Swyter) wrote:

Also, notice the messed up physical button layout of this gamepad when compared to most of the others from the same chipset family.

2 SELECT START LB RB -NGS Phantom
1 4 9 10 5 6 http://web.archive.org/web/20190612172739if_/https://images-na.ssl-images-amazon.com/images/I/41WaDx-kLYL.jpg
3 7 8 http://web.archive.org/web/20190612172723if_/https://images-na.ssl-images-amazon.com/images/I/71042nE1UpL._SL1500_.jpg

1 SELECT START LB RB -Topway faux-dualshock models
4 2 9 10 ? ? and Trust CXT24 (?)
3 ? ?

@SDLBugzilla SDLBugzilla added bug waiting Waiting on user response labels Feb 11, 2021
@clebercasali
Copy link

clebercasali commented Jun 12, 2021

I have figured out a trick that gives me a very unique signature for each controller.
Could be useful for generating more unique GUIDs.
Pass the js number as parameter (0, 1, 2...)

#!/bin/bash
DIR=/sys/bus/usb/devices/$(ls -R /sys/bus/usb/devices/* | grep js$1 | cut -d$'\n' -f2 | cut -d: -f1 | awk -F/ '{print $NF}')
IMANUFACTURER=$(cat $DIR/manufacturer)
IPRODUCT=$(cat $DIR/product)
ISERIAL=$(cat $DIR/serial)
IVERSION=$(cat $DIR/version | xargs)
SIGNATURE="$IMANUFACTURER:$IPRODUCT:$ISERIAL:$IVERSION"
echo $SIGNATURE

@slouken slouken removed the bug label May 11, 2022
@earboxer
Copy link

earboxer commented Jun 1, 2022

I think I've also run into this problem when using a Wii U Pro Controller and a Wii Remote. My custom mapping for the Wii Remote messed up the mapping for the Wii U Pro Controller and I wasn't able to use both mappings simultaneously.

@Swyter
Copy link

Swyter commented Jul 21, 2022

Quick heads up. I looked into this yesterday and found a way of dumping the entire configurable memory block from DragonRise/PC Twin Shock gamepads through a simple USB string descriptor call.

Yes, really. ¯\_(ツ)_/¯

--

We need more samples/dumps of other pads to see if they are unique enough to hash them and make their GUIDs unique via SDL2 workaround.

Please take a look at the thread below for a script and instructions to dump your own board using only software, it's really easy and it can make a difference:

mdqinc/SDL_GameControllerDB#202 (comment)

CC @clebercasali

@slouken
Copy link
Collaborator

slouken commented Aug 23, 2022

Yep, this should do the trick. @Swyter, can you confirm?

@slouken slouken self-assigned this Aug 23, 2022
@slouken slouken added this to the 2.26.0 milestone Aug 23, 2022
@Swyter
Copy link

Swyter commented Aug 23, 2022

@slouken I don't think this will be enough in this case because from the lsusb dumps available on this thread (mdqinc/SDL_GameControllerDB#202) they seem to share everything naming-wise. I imagine you guys at Valve have other DragonRise pads and can try to dump their EEPROM using the method I found to see if hashing that will be enough.

At the very least I think maybe hashing the HID descriptor may be a step up. But we do need more samples to know if this is worthwhile.

@slouken
Copy link
Collaborator

slouken commented Aug 23, 2022

Your case should be handled where the DragonRise and Microntek controllers have different names.

I see the devices with duplicate names, mdqinc/SDL_GameControllerDB#202 (comment) even has one of them as a dualshock style and another as a flight stick, but otherwise identical. I'm not sure we can do much about this, unfortunately. We don't have access to the underlying HID descriptors on many configurations, and even if we did, we probably don't want to use those as identifying data in most situations. For example, we don't want to mark different Xbox controller firmware revisions as different devices.

We could special case that particular VID/PID, but if both are connected at the same time, I'm not sure how we would map USB device path to the event node in Linux, or the DirectInput handle to USB device path on Windows.

@slouken slouken removed the waiting Waiting on user response label Aug 23, 2022
@Swyter
Copy link

Swyter commented Aug 23, 2022

@slouken Here it says that you can call IDirectInputDevice8::GetProperty() with DIPROP_GUIDANDPATH, and later use that for HID calls:

I imagine you'd find something like that for Linux. EVIOCGPHYS seems to do the trick:

You could also potentially differentiate them by recording and matching their plugged-in timestamps under both back-ends, I suppose.

@clebercasali
Copy link

Sorry about the delay to answer.
I'm using a third party xbox controller now.
I have moved my hq and I can't remember where I put the old controllers.

@Swyter
Copy link

Swyter commented Aug 23, 2022

@slouken @icculus The thing is, I would prefer having more hard data from other devices first and then find a solution.

Because right now we don't even know if that is even different enough for the large subset of DragonRise devices where that recent pull request didn't make the trick.

You guys have physically more resources to acquire and test hardware; I only have a single DragonRise pad with me. And no one seems interested in helping so far. I can't really justify buying more controllers to diagnose this mess in my free time.

@slouken
Copy link
Collaborator

slouken commented Aug 23, 2022

We are reliant on community contributions just like you, in this case, getting exactly the right hardware to reproduce is almost impossible because of the age and how misleading sales pages are in what product you're actually getting.

I'll leave this bug open so people can contribute more data on what works and what doesn't and we can improve our solution from here.

@slouken
Copy link
Collaborator

slouken commented Aug 23, 2022

Out of curiosity, what does this script return for the various controllers? (thanks @clebercasali)

#!/bin/bash
DIR=/sys/bus/usb/devices/$(ls -R /sys/bus/usb/devices/* | grep js$1 | cut -d$'\n' -f2 | cut -d: -f1 | awk -F/ '{print $NF}')
IMANUFACTURER=$(cat $DIR/manufacturer)
IPRODUCT=$(cat $DIR/product)
ISERIAL=$(cat $DIR/serial)
IVERSION=$(cat $DIR/version | xargs)
SIGNATURE="$IMANUFACTURER:$IPRODUCT:$ISERIAL:$IVERSION"
echo $SIGNATURE

@Swyter
Copy link

Swyter commented Aug 23, 2022

For the NGS Phantom it outputs this, the serial one errors out because as shown here string index for iSerial is 0, and when we dump it manually it returns 04 03 09 04 in hexadecimal. Which when decoded with this seems invalid.

cat: /sys/bus/usb/devices/4-1/serial: No existe el fichero o el directorio
DragonRise Inc. :Generic USB Joystick ::1.00
# swy: install pyusb (pacman -S python-pyusb) and run python3 as sudo
>>> import usb.core, usb.control, usb.util, binascii
>>> dev = usb.core.find(idVendor=0x0079, idProduct=0x0006)

>>> binascii.hexlify(usb.control.get_descriptor(dev, 0x400, usb.util.DESC_TYPE_DEVICE, 0))
b'120100010000000879000600070101020001'
>>> binascii.hexlify(usb.control.get_descriptor(dev, 0x400, usb.util.DESC_TYPE_CONFIG, 0))
b'0902290001010080fa0904000002030000000921100121012265000705810308000a0705010308000a'

>>> binascii.hexlify(usb.control.get_descriptor(dev, 0x400, usb.util.DESC_TYPE_STRING, 0)) # iSerial                 0 
b'04030904'
>>> binascii.hexlify(usb.control.get_descriptor(dev, 0x400, usb.util.DESC_TYPE_STRING, 1)) # iManufacturer           1 DragonRise Inc.  
b'240344007200610067006f006e005200690073006500200049006e0063002e0020002000'
>>> binascii.hexlify(usb.control.get_descriptor(dev, 0x400, usb.util.DESC_TYPE_STRING, 2)) # iProduct                2 Generic   USB  Joystick  
b'3403470065006e006500720069006300200020002000550053004200200020004a006f00790073007400690063006b0020002000'
>>> binascii.hexlify(usb.control.get_descriptor(dev, 0x400, usb.util.DESC_TYPE_STRING, 3)) # swy: overflowed/out of bounds data, also works with 7 or 11
b'120100010000000879000600070101020001ffffffffffff0902290001010080fa0904000002030000000921100121012265000705810308000a0705010308000affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04030904ffffffff240344007200610067006f006e005200690073006500200049006e0063002e0020002000ffffffffffffffffffffffff3403470065006e006500720069006300200020002000550053004200200020004a006f00790073007400690063006b0020002000ffffffffffffffffffffffff05010904a101a10275089505150026ff00350046ff00093009310932093209358102750495012507463b0165140939814265007501950c2501450105091901290c81020600ff750195082501450109018102c0a1027508950746ff0026ff0009029102c0c0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff120100010000000879000600070101020001ffffffffffff0902290001010080fa0904000002030000000921100121012265000705810308000a0705010308000affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04030904ffffffff240344007200610067006f006e005200690073006500200049006e0063002e0020002000ffffffffffffffffffffffff3403470065006e006500720069006300200020002000550053004200200020004a006f00790073007400690063006b0020002000ffffffffffffffffffffffff05010904a101a10275089505150026ff00350046ff00093009310932093209358102750495012507463b0165140939814265007501950c2501450105091901290c81020600ff750195082501450109018102c0a1027508950746ff0026ff0009029102c0c0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'

That's how I found that index 3 returned a full memory dump. Probably some kind of side effect in the microcontroller.

@offalynne
Copy link
Contributor

offalynne commented Aug 23, 2022

I can test the above on a common N64 clone pad as well shortly.

Pinging @DanielGibson as well from mdqinc/SDL_GameControllerDB#202

@offalynne
Copy link
Contributor

offalynne commented Aug 23, 2022

VID 0x0079
PID 0x0011
is also common and may similarly benefit from disambiguation.

@earboxer
Copy link

In my case with the WiiU pro controller and the wii remote, the USB info reflects that of my USB card. (Broadcom Corp.:Bluetooth USB Host Controller::2.01 on laptop or :CSR8510 A10::2.00 on desktop with adapter)

Since they're not USB controllers, I don't think any USB dumps will be helpful.

Here are two mappings I created (the controllers are very different from eachother, so its very noticable when the mapping is confused)

050000007e0500003003000001000000,Nintendo Wii Remote,platform:Linux,a:b10,b:b0,x:b9,y:b1,back:b4,guide:b2,start:b3,dpup:b7,dpdown:b6,dpleft:b5,dpright:b8,
050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,

We don't have access to the underlying HID descriptors on many configurations, and even if we did, we probably don't want to use those as identifying data in most situations. For example, we don't want to mark different Xbox controller firmware revisions as different devices.

Maybe we could have a way of saying in a specific mapping that the name must match strictly? (That way, this only needs to be changed for these few overlapping controllers).

@slouken
Copy link
Collaborator

slouken commented Aug 24, 2022

Can you guys try creating mappings using the latest SDL code in git, with the controllermap test program?

@Swyter
Copy link

Swyter commented Aug 25, 2022

I easily bought a Trust GTX 24 compact gamepad (GTIN-13/EAN: 8713439174168, Trust item number 17416, so much about being «impossible»; when there's a will there's a way, especially with Valve's resources even for minor issues like this one) and unfortunately everything software and data-wise is identical to my NGS Phantom, except for the physical button layout, size, shape and lack of rumble motors. I don't think there is anything we can do to tell them apart programmatically.

  Trust GTX 24           NGS Phantom

[ 7 ]      [ 8 ]   |   [ 7 ]      [ 8 ]
[ 5 ]      [ 6 ]   |   [ 5 ]      [ 6 ]
                   |
             1     |                2
  9  10    4   2   |     9  10    1   4
             3     |                3

    (11)  (12)     |      (11)  (12)

They couldn't change a single byte by chance. I guess this settles it until someone finds a secret HID command that outputs some other motherboard or OEM version marker, albeit at this point that seems highly unlikely.

So yeah, for super easy cases where they differ by more than a single byte it should be easy to differentiate, in the case of this pair of Dragonrise pads and potentially way more they are essentially the same product, just wired slightly differently out of pure evilness.

Details with the HID report, lsusb, and memory dumps here: https://gist.github.com/Swyter/26c754c6f04b13ecb8a7cf145878d045#file-trust-gtx24-gamepad-dumped-output-txt

@offalynne
Copy link
Contributor

Still a worthwhile change for SDL since prior the Windows format lacked any fields besides VID and PID, and the Hori pads Sam wrote this change for are usually identifiable at least by name. Unfortunate but unsurprising re Dragonrise.

@slouken
Copy link
Collaborator

slouken commented Sep 1, 2022

Maybe we could have a way of saying in a specific mapping that the name must match strictly? (That way, this only needs to be changed for these few overlapping controllers).

That's exactly what the latest SDL code does. It includes a CRC of the controller name in the controller GUID. If a mapping has a CRC field, it matches any controller with that VID/PID and name. If the field isn't present, then it will match that VID/PID with any name.

@slouken
Copy link
Collaborator

slouken commented Oct 4, 2022

I think we've settled on using the CRC of the name and the USB VID/PID as the identifying information that we can use. We don't have access to the report descriptor generally, so any devices that don't change their name or VID/PID from the default for the chipset will have to be mapped by the end user.

As noted above, some controllers don't change the firmware at all, they simply wire up different connections on the hardware.

I'm closing this for now, feel free to reopen if new information becomes available.

@slouken slouken closed this as completed Oct 4, 2022
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

No branches or pull requests

6 participants