DanielOgorchock / joycond

userspace daemon to combine joy-cons from the hid-nintendo kernel driver
GNU General Public License v3.0
340 stars 68 forks source link

Add Switch SNES controller support. #54

Closed ChadSikorra closed 3 years ago

ChadSikorra commented 3 years ago

I created a PR to add support for the Switch SNES wireless controller in hid-nintendo (well, this repo of it anyway):

https://github.com/nicman23/dkms-hid-nintendo/pull/27

To get it to work I had to add it here too. Leaving it out here in case someone thinks it's worth merging.

DanielOgorchock commented 3 years ago

thanks, looks good to me

nfp0 commented 2 years ago

What function of joycond benefits the Switch SNES controller exactly. Sorry if I misunderstand the purpose of joycond, but I'm under the impression it's purpose is to combine two joy-cons into a virtual input device.

emilyst commented 2 years ago

What function of joycond benefits the Switch SNES controller exactly. Sorry if I misunderstand the purpose of joycond, but I'm under the impression it's purpose is to combine two joy-cons into a virtual input device.

I also find this a little confusing. Honestly? It feels like a bug. joycond has no business touching the NSO controllers, IMO. It's not as if it makes sense to combine two SNES controllers, and even if it did, it won't map the inputs properly.

Furthermore, since the NSO Sega Genesis controller has the same product ID as the NSO SNES controller when connected via Bluetooth (thanks, Nintendo), joycond also grabs that device. Since that controller lacks triggers, it effectively disables the controller entirely.

Luckily, there's a workaround. You can create a custom udev rules file to override the tags on the devices you want joycond to ignore. To do so, create /etc/udev/rules.d/99-joycond-ignore.rules with the following contents:

# ignore Switch Pro controller by overriding tags
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="2009", TAG="uaccess"
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="2009", TAG+="seat"

# ignore NSO SNES controller by overriding tags
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="2017", TAG="uaccess"
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="2017", TAG+="seat"

# ignore NSO N64 controller by overriding tags
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="2019", TAG="uaccess"
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="2019", TAG+="seat"

# ignore NSO Genesis controller by overriding tags
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="201e", TAG="uaccess"
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="201e", TAG+="seat"

This adds rules to ignore the Pro controller, the SNES controller, the N64 controller (just in case it this gets added in the future for some reason), and the Genesis controller (when connected via USB, also just in case it comes up in the future).

Note that, unfortunately, there's no way using udev rules to tell joycond to ignore the NSO NES controllers, since they use the same product ID as the Joy-Con controllers. See this comment below to ignore the NSO NES controllers as well.

Also, note that this will override any other tags applied by any other rules in the system. I recommend you use udevadm monitor -k -u -p before applying these to see if any other relevant tags should be added. This is unfortunate but unavoidable, as Poettering et al. decided upstream that udev tags should be "sticky" and therefore cannot be modified once added, except by assignment as I've done here.

nfp0 commented 2 years ago

@emilyst Thanks!

Furthermore, since the NSO Sega Genesis controller has the same product ID as the NSO SNES controller when connected via Bluetooth (thanks, Nintendo)

Yeah, I have no idea why Nintendo did that. It makes it more difficult to distinguish them on Windows. But RetroArch can distinguish them by their name on udev on Linux. Can't the same be applied here?

emilyst commented 2 years ago

Furthermore, since the NSO Sega Genesis controller has the same product ID as the NSO SNES controller when connected via Bluetooth (thanks, Nintendo)

Yeah, I have no idea why Nintendo did that. It makes it more difficult to distinguish them on Windows. But RetroArch can distinguish them by their name on udev on Linux. Can't the same be applied here?

Ah, I bet you're right. That wouldn't be hard to do.

For the case of SNES versus Genesis controllers, that's probably not terribly useful since we want the same behavior for each case. There's no real need to distinguish.

But this does suggest there's a way to disable joycond handling for the NES controllers, which I mentioned above could not be distinguished. Instead of matching by product ID (which would be the same in the case of either the NES Joy-Cons or the regular Joy-Cons), we can match by the name.

I just tested this out, and it works well! The amended file /etc/udev/rules.d/99-joycond-ignore.rules would contain the following (note the last two lines added):

# ignore Switch Pro controller by overriding tags
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="2009", TAG="uaccess"
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="2009", TAG+="seat"

# ignore NSO SNES controller by overriding tags
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="2017", TAG="uaccess"
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="2017", TAG+="seat"

# ignore NSO N64 controller by overriding tags
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="2019", TAG="uaccess"
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="2019", TAG+="seat"

# ignore NSO Genesis controller by overriding tags
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="201e", TAG="uaccess"
ACTION=="add", SUBSYSTEM=="input", ATTRS{id/vendor}=="057e", ATTRS{id/product}=="201e", TAG+="seat"

# ignore NES Joy-Con by overriding tags
ACTION=="add", SUBSYSTEM=="input", ATTRS{name}=="NES Controller*", TAG="uaccess"
ACTION=="add", SUBSYSTEM=="input", ATTRS{name}=="NES Controller*", TAG+="seat"

If there's some reason to need to distinguish Genesis from SNES in this case, let me know, and I can suggest rules which do so.

nfp0 commented 2 years ago

@emilyst Nice, looks good! Thanks.