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

Re-implement hidraw patching #286

Open
kakra opened this issue Apr 4, 2021 · 1 comment
Open

Re-implement hidraw patching #286

kakra opened this issue Apr 4, 2021 · 1 comment
Labels
0 | type: enhancement New feature or request 0 | type: hardware support Support third-party hardware and clones 0 | type: third party bug
Milestone

Comments

@kakra
Copy link
Collaborator

kakra commented Apr 4, 2021

Note to myself: xpadneo should probably redo how we patch the hidraw interface, this may fix some of the problems:

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. Unfortunately, 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. Unfortunately, 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 controller db 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 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 Steam Link works: It may use SDL, then everything should work unless an awkward controllerdb entry is sitting somewhere.

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).

Originally posted by @kakra in #244 (comment)

@kakra kakra added 0 | type: enhancement New feature or request 0 | type: hardware support Support third-party hardware and clones 0 | type: third party bug labels Apr 4, 2021
@kakra kakra modified the milestones: v0.10, v0.11 Apr 4, 2021
kakra added a commit to kakra/xpadneo that referenced this issue Nov 13, 2021
Also fixes Steam Input which apparently also uses SDL2.

The bug shows up when SDL identifies the controller as being on USB
instead of Bluetooth (SDL Gamepad ID starts with `03` instead of `05`)
which then messes with SDL's expectations for the contents of hidraw.

This fixes two SDL problems:

  * Wrong mappings in hidraw (buttons shifted to other buttons)
  * SDL2 doesn't properly throttle rumble commands (endless rumble)

See-also: atar-axis#286
Maybe-fixes: atar-axis#303
Maybe-fixes: atar-axis#311
Maybe-fixes: atar-axis#314
Signed-off-by: Kai Krakow <[email protected]>
kakra added a commit that referenced this issue Nov 13, 2021
Also fixes Steam Input which apparently also uses SDL2.

The bug shows up when SDL identifies the controller as being on USB
instead of Bluetooth (SDL Gamepad ID starts with `03` instead of `05`)
which then messes with SDL's expectations for the contents of hidraw.

This fixes two SDL problems:

  * Wrong mappings in hidraw (buttons shifted to other buttons)
  * SDL2 doesn't properly throttle rumble commands (endless rumble)

See-also: #286
Maybe-fixes: #303
Maybe-fixes: #311
Maybe-fixes: #314
Signed-off-by: Kai Krakow <[email protected]>
kakra added a commit to kakra/xpadneo that referenced this issue Nov 17, 2021
Also fixes Steam Input which apparently also uses SDL2.

The bug shows up when SDL identifies the controller as being on USB
instead of Bluetooth (SDL Gamepad ID starts with `03` instead of `05`)
which then messes with SDL's expectations for the contents of hidraw.

This fixes two SDL problems:

  * Wrong mappings in hidraw (buttons shifted to other buttons)
  * SDL2 doesn't properly throttle rumble commands (endless rumble)

See-also: atar-axis#286
Maybe-fixes: atar-axis#303
Maybe-fixes: atar-axis#311
Maybe-fixes: atar-axis#314
Signed-off-by: Kai Krakow <[email protected]>
@kakra
Copy link
Collaborator Author

kakra commented Mar 12, 2022

More issues:

  • OpenRGB and ymk unconditionally open all hidraw device for world access. This has been fixed in ymk lately. This enables SDL to prefer hidraw and make wrong assumptions of our hidraw patching. There's currently no good way around it, OpenRGB overrides our hidraw permission fixup.
  • It seems, only the Elite 2 controller moved additional non-gamepad buttons ("Guide" in this case) to a separate device. Later firmwares (BLE) is back to the previous mapping, probably because lots of user-space assumptions are already widely deployed. We should probably follow example and move the Guide and Share buttons back into the main device - with proper positioning.

kakra added a commit that referenced this issue May 26, 2022
Also fixes Steam Input which apparently also uses SDL2.

The bug shows up when SDL identifies the controller as being on USB
instead of Bluetooth (SDL Gamepad ID starts with `03` instead of `05`)
which then messes with SDL's expectations for the contents of hidraw.

This fixes two SDL problems:

  * Wrong mappings in hidraw (buttons shifted to other buttons)
  * SDL2 doesn't properly throttle rumble commands (endless rumble)

See-also: #286
Maybe-fixes: #303
Maybe-fixes: #311
Maybe-fixes: #314
Signed-off-by: Kai Krakow <[email protected]>
kakra added a commit that referenced this issue May 30, 2022
A new SDL gamecontrollerdb entry allows us to get rid of the Xbox
button fixup we are carrying around. While this button is still not
exactly a button for games, all software expects it to be part of the
gamepad mapping anyways.

This leaves only the Share button left in the consumer control bits
which doesn't have an jsdev equivalent.

Affects: #286
Maybe-affects: #283
Fixes: #362
Fixes: #359
Closes: #301
Signed-off-by: Kai Krakow <[email protected]>
kakra added a commit to kakra/xpadneo that referenced this issue May 30, 2022
A new SDL gamecontrollerdb entry allows us to get rid of the Xbox
button fixup we are carrying around. While this button is still not
exactly a button for games, all software expects it to be part of the
gamepad mapping anyways.

This leaves only the Share button left in the consumer control bits
which doesn't have an jsdev equivalent.

Affects: atar-axis#286
Maybe-affects: atar-axis#283
Fixes: atar-axis#362
Fixes: atar-axis#359
Closes: atar-axis#301
Signed-off-by: Kai Krakow <[email protected]>
kakra added a commit that referenced this issue May 30, 2022
A new SDL gamecontrollerdb entry allows us to get rid of the Xbox
button fixup we are carrying around. While this button is still not
exactly a button for games, all software expects it to be part of the
gamepad mapping anyways.

This leaves only the Share button left in the consumer control bits
which doesn't have an jsdev equivalent.

Affects: #286
Maybe-affects: #283
Fixes: #362
Fixes: #359
Closes: #301
Signed-off-by: Kai Krakow <[email protected]>
@kakra kakra mentioned this issue Feb 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
0 | type: enhancement New feature or request 0 | type: hardware support Support third-party hardware and clones 0 | type: third party bug
Projects
None yet
Development

No branches or pull requests

1 participant