atar-axis / xpadneo

Advanced Linux Driver for Xbox One Wireless Controller (shipped with Xbox One S)
https://atar-axis.github.io/xpadneo/
GNU General Public License v3.0
1.95k stars 112 forks source link

Can't map some buttons on Steamlink on RPi3 and Xbox One Controller #244

Closed bserem closed 3 years ago

bserem commented 3 years ago

Version of xpadneo

0.8.3

Severity / Impact

Describe the bug

Controller model: 1708 with an updated firmware. Using Steamlink on RaspiOS I can't map X button, left stick button, right stick button (and possibly others, steamlink crashes after some failures)

Steps to Reproduce

Install Steamlink on RPi3 Install xpadneo Connect controller Try to map controller from steamlink, some buttons fail

Expected behavior

Be able to map all buttons (like it works for USB connection).

Screenshots/Gifs

System information

# uname -a
Linux raspberrypi 5.4.51-v7+ #1333 SMP Mon Aug 10 16:45:19 BST 2020 armv7l GNU/Linux
# xxd -c20 -g1 /sys/module/hid_xpadneo/drivers/hid:xpadneo/0005:045E:*/report_descriptor | tee >(cksum)
xxd: /sys/module/hid_xpadneo/drivers/hid:xpadneo/0005:045E:*/report_descriptor: No such file or directory
4294967295 0

Controller and Bluetooth information

Additional context

I know this is an extreme case and very few will probably be interest. I am not sure whether I will keep experimenting with Steamlink either, but I thought of sharing this since I stumbled upon it.

kakra commented 3 years ago

The xxd command failed, are you sure the controller was connected (and the driver actually loaded)? But I'm guessing we don't need the descriptor anyways.

Please check if the buttons show correctly when running evtest on the RPi.

kakra commented 3 years ago

Is this still an issue with latest master? Otherwise, this is probably an issue with Steam Link and I'm even not sure if Steam Link is still actively supported by Valve, there's a support page but it refers to the community for anything that's not exactly in their list of supported devices, and xpadneo doesn't belong to it (because we are exposing mappings a little differently but not in an incompatible way): https://support.steampowered.com/kb_article.php?ref=6153-IFGH-6589

With xpadneo, the controller should just look and behave like the original Xbox 360 controller connected via USB for games and applications - just that we use Bluetooth.

If there's no feedback on this issue when v0.10 is released, I'm closing this as abandoned.

bserem commented 3 years ago

I can't really provide much more info on this. steamlink was full of problems and I dumped it after a couple of months.

I guess we can close this.

kakra commented 3 years ago

Thanks for the feedback, let's close this then.

FelixZY commented 3 years ago

@kakra I actually have this exact issue. I'm running steam link on a RPi3b+ and using a wireless xbox controller.

I originally installed the machine ~1 year ago but decided to update my software yesterday. I updated steam link (there was a new version available so I assume it is maintained), xpadneo and controller firmware via the xbox accessories app on windows. After starting back up, steam link recognizes both my controllers as "xbox one s controller" but the mappings were all wrong. While attempting to correct the mappings I found that the X button, left stick button, right stick button, right shoulder button and guide button could not be mapped at all. Note that this is in the steam link app on the RPi itself, before connecting to the computer on which steam is running.

My guess is that my controller is recognized as another controller type but I am yet to determine how to address that - or even which specific software component is responsible.

FelixZY commented 3 years ago

Update: jstest-gtk responds to all buttons except guide button so it looks more like a steam link problem. I will post an update if I manage to solve it.

FelixZY commented 3 years ago

Using USB cable to the pi solves the issue completely but wireless over bluetooth still does not work.

Before the update one of my controllers was recognized by steam link as "XInput Controller" (one of them, not both - I'm guessing different firmware). In /home/pi/.local/share/Valve Corporation/SteamLink/controller_map.txt I managed to find both this older config and my new one (from trying to correct the config in steamlink's ui). What's interesting is that it seems like some buttons have changed place since the software updates (still not sure which is responsible). E.g. "y" used to b4, now it is b2.

I'm not very well versed in drivers and gamepads but I'm leaning towards the controller firmware update causing xpadneo to interpret the controller as the wrong controller type which would in turn make steam link interpret the controller as this wrong type and attempt to map keys which work differently between controllers. Could this be the case or do you have any other ideas about how to continue debugging? For the time being I'll just have to use a cable instead I guess.

XInput Controller ``` 050000005e040000e002000008040000 XInput Controller platform:Linux a:b0 b:b1 x:b3 y:b4 back:b15 guide:b12 start:b11 leftstick:b13 rightstick:b14 leftshoulder:b6 rightshoulder:b7 dpup:h0.1 dpdown:h0.4 dpleft:h0.8 dpright:h0.2 leftx:a0 lefty:a1 rightx:a2 righty:a3 lefttrigger:a5 righttrigger:a4 ```
Xbox One S Controller ``` 030000005e040000e002000000006800 Xbox One S Controller platform:Linux a:b0 b:b1 y:b2 back:b9 start:b10 leftshoulder:b3 dpup:b11 dpdown:b12 dpleft:b13 dpright:b14 leftx:a0 lefty:a1 rightx:a2 righty:a3 lefttrigger:a4 righttrigger:a5 ```
kakra commented 3 years ago

Well, let me explain some things, it's a mess:

The first Xbox controller had a simple button mapping with 10 (or 11) consecutive bits for buttons, both SDL and games assumed exactly that:

Bit       0  1  2  3  4  5  6   7   8  9  (10)
Button    A  B  X  Y  LB RB Sel Str LS RS (Gui)

Games simply count buttons, and SDL did that too. Everything worked fine. The Guide button (Gui) is actually button 11 and not supposed to be used by games. It was still in the bitmap but in later controllers, MS would remove the button from the bitmap. It is meant to be read by the OS only anyways, for the sole purpose getting back to a global menu or dashboard.

But then came the Bluetooth-enabled Xbox controller which were supposed to support Android. As Android is based on Linux and had no special driver for the gamepad, MS had to use a sparse bitmap to skip the buttons from the Linux event interface that are missing on the controller:

Bit       0  1 (2) 3  4 (5) 6  7  8   9    10  11 (12)  (13)
Button    A  B (C) X  Y (Z) LB RB Sel Str  LS  RS (Gui) (Shr)

As you can see, it counts a C and Z button which the controller does not have. But it makes Android happy as each bit maps to the correct event number the kernel expects, and Android games actually use event numbers instead of counting bit positions. So the controller does work there but has 12 buttons (or even 13 including the Share button which does not even map properly to a Linux event number because Linux has no such button in its description). Due to how the Linux event interface maps bits to buttons, games would actually see 15 buttons, see below.

The Guide button is actually no longer part of this bitmap in later firmware versions of the controller - probably because it messes the ordering of buttons Linux games expect:

Position  0  1  2  3  4  5  6  7  8   9    10  11  12    13  14
Event     A  B  C  X  Y  Z  LB RB LB2 RB2  Sel Str Gui   LS  RS

This is what the Linux kernel expects when mapping bits to button events. A sane controller would offer a sparse bitmap, and everything maps properly, and software using the event symbols would be happy. Apparently, the HID descriptor has no way of saying which buttons do actually exist, so games would see 15 buttons now (with the Share button mapping at a strange position). But that's a minor cosmetic issue at that layer.

If you look at the ordering of buttons, this is completely out of order: Games back that day expected 10 buttons, counting from position 1, so without a proper driver removing buttons C, Z, LB2, RB2, and Gui from the position list, games are still messed up.

Also, the old joydev interface (/dev/js*) did the same dumb thing as games and simply counts positions, so you would see 15 buttons, where only A and B are in correct position, and all the other buttons are unreachable, misplaced, or dead. Games that could not re-assign buttons for gamepads (or didn't expect more than 10 buttons) would not work. And then, you'd have to repeat the process for every game.

So xpadneo stepped in and fixed that: Removing the dead positions and re-assigning the event symbols, so we ended up with this order:

A,B,X,Y,LB,RB,Select,Start,Guide,LS,RS

Hmm? Yes, that looks correct you might say. But it isn't: Games expect the first 10 buttons to be gamepad buttons, Guide does not belong there, if anything it belongs into the last position. But the Linux kernel would not let us do that: It always orders button positions by the event number, and Guide comes before LS/RS in that list. :-(

So xpadneo removed the Guide button, as Microsoft also did in newer firmware versions. Now the gamepad has 10 buttons for games. Instead, both xpadneo and MS moved the Guide button to a separate input application so applications could still read it. Apparently, Steam simply ignores that.

So, xpadneo did its thing and properly made the controller work when SDL stepped in to redo this for the models we support (probably because Bluetooth support for the controller has been added to hid-microsoft in the kernel).

SDL sits between the Linux event interface and a game and re-assigns each position a new position, it doesn't even look at event symbols. And this is where we end in a big mess: Suddenly, Y would become X because SDL thinks that the third position is a blind button C - even when using xpadneo. If it looked at the event name instead, everything would work. It actually uses its community-updated controllerdb to match position back to button symbols (not event names!), which it then exposes to games in the correct expected order (as initially mentioned in the very first table).

So we added a hack to xpadneo which would bypass the controllerdb by pretending we would be a model that SDL does not support. SDL then just falls back to a generic controller layout it calls "XInput Controller" which matches the very first table - exactly what we expose (minus the Guide button because it would have a wrong event name otherwise, if we include it, buttons Guide/LS/RS are swapped).

So what you actually want is that SDL does not detect a mapping for the controller, or uses a mapping from its table that matches exactly a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,(guide:b10).

With current SDL and xpadneo, xpadneo maps to exactly one such entry but the Guide button will be dead (we send it as a keyboard event instead from the consumer control page, I wish Steam would simply add support for that, it would have no conflicts with existing configurations).

I'm not sure how Steamlink works: It may use SDL, then everything should work unless an awkward controllerdb entry is sitting somehwere.

SDL gained some support for using hidraw devices lately, which messes with a lot of the above assumptions, and Steam/Proton may detect the gamepad twice as two different devices, one with correct mappings (evdev) and one with wrong mappings (hidraw). I fixed that lately with two commits: One prevents SDL to find the gamepad twice (it's a bugfix in xpadneo), and one removes user access to hidraw (which works around the SDL issue). If you are running Steamlink as root user, or Steamlink is able to read from the hidraw device, you may still see this issue: Mappings are wrong in the way you described. You could try running with SDL_JOYSTICk_HIDAPI=0, or you revoke read access from hidrawXX completely (look at dmesg when xpadneo connects to find the name, it changes with every connect, but a rule could be added to udev).

BTW: Using a USB cable means you do not use xpadneo.

kakra commented 3 years ago

Note to myself: xpadneo should probably redo how we patch the hidraw interface, this may fix some of the problems. I'll leave this open until done.

kakra commented 3 years ago

Can you test if https://github.com/atar-axis/xpadneo/pull/292 fixes your issues?

FelixZY commented 3 years ago

@kakra I've only tested using the steam link interface but the results are bad:

![Xbox One Wireless Controller front](https://compass-ssl.xboxlive.com/assets/c1/95/c19568c4-c7b8-4b5f-beec-6a7202778cba.jpg?n=xbox-one-wireless-controller-front.jpg) ![Xbox One Wireless Controller back](https://compass-ssl.xboxlive.com/assets/31/50/3150e4aa-de45-4e0b-816d-0af85861adbc.jpg?n=xbox-one-wireless-controller-back.jpg) Image source: https://support.xbox.com/en-US/help/hardware-network/controller/xbox-one-wireless-controller | Button | Mapping | |--|--| | left stick (directions) | left stick (directions) | | left stick (press) | unbound | | 2 | X | | 3 | unbound | | 5 | unbound | | 6 | unbound | | 7 | unbound | | 8 (up) | 6 | | 8 (down) | 5 | | 8 (left) | left stick (press) | | 8 (right) | right stick (press) | | right stick (directions) | right stick (directions) | | right stick (press) | unbound | | 11 | 14 | | 14 | 11 | | X | unbound | | Y | unbound | | A | A | | B | B |
FelixZY commented 3 years ago

Just after posting the above I remembered that this issue was about whether it is possible to map the controller buttons, not if they map correctly - my bad. Still, I cannot map X, left stick (press), right stick (press), 7 or 5 in the steam link interface (nothing happens when I press them). Other buttons can be mapped as expected.

kakra commented 3 years ago

Closing as queued in #291

Mskeffington commented 2 years ago

Steamlink is using the hidraw device. It inserts a udev rule to expose hidraw directly. If you create a udev rule at priority < 56 containing the following it will bypass the Steamlink rule and prevent Steamlink from accessing the hidraw for any xpadneo devices. If Steamlink cant access the hidraw, it will use the uevent instead.

50-xpadneo_fixup_for_steamlink.rules

KERNEL="hidraw*", DRIVERS=="xpadneo", MODE:="0600"

kakra commented 2 years ago

If you create a udev rule at priority < 56 containing the following

Oh this is interesting. That explains something... I'll fix it up in #292 - thanks.