ahungry / vader3

Flydigi Vader 3 Bluetooth driver for GNU/Linux
GNU General Public License v3.0
14 stars 1 forks source link

Idea: change udev rule to mock a dualsense edge controller #2

Open martindmtrv opened 8 months ago

martindmtrv commented 8 months ago

Hey there,

After looking into this project a little bit, I'm curious if changing the udev attributes for the Vader 3 to match the dualsense edge could allow native remapping in steam (at least for the 4 back buttons, not sure about c,z)

Dualsense edge udev rule is here: https://codeberg.org/fabiscafe/game-devices-udev/src/branch/main/71-sony-controllers.rules

Dualsense edge extra steam input mapping: https://m.youtube.com/watch?v=kuXs0GFjKMo

I'm not sure what steam uses to determine what the controller is but perhaps setting attributes in udev would be enough. As for getting the inputs to map correctly, I know for normal controllers you can go in input settings and configure all the mappings manually from the device so perhaps with this you could which hardware buttons map to which dualsense edge buttons (not sure if this is the case though I don't have a dualsense edge)

I've ordered a Vader 3 myself to give this a go with my steam deck but it may take awhile to arrive from aliexpress

martindmtrv commented 8 months ago

This could also probably be mocked as a Xbox elite controller since the buttons would be better defined and closer to Xbox layout

I found this code snippet in xpadneo repo that could be helpful

https://github.com/atar-axis/xpadneo/blob/master/hid-xpadneo/src/hid-xpadneo.c#L1127

It seems like in the .probe method defined for the hid_driver you can modify the product / version id to mock another device

ahungry commented 8 months ago

The xpadneo team (or primary maintainer) requested that I don't do this, as they've done a lot of work to make sure xpadneo probe output is the only output telling other systems that it's an xbox controller in this way.

martindmtrv commented 8 months ago

I don't think we'd need to use the windows pairing mode they mention, rather just some Xbox elite controller id so steam picks it up as one instead of PlayStation controller layout

martindmtrv commented 8 months ago

Got my controller in today, I installed the kernel module

Just off some quick experimentation, by running the setup device inputs in steam controller menu, I can remap the back buttons to the face buttons

If we can get the controller to appear as a xbox controller instead of a generic one then I'd say we'd be looking pretty good for having steam remaps

martindmtrv commented 8 months ago

Steam also detects C and Z but again just can't map them without replacing existing buttons with the generic layout

martindmtrv commented 8 months ago

Mocking the product version and vendor codes actually makes steam see it as a xbox pro controller with L4 L5 R4 R5 available. Now just need to map those buttons to what they should be according to the xbox spec image

martindmtrv commented 8 months ago

Take a look at the change here: https://github.com/ahungry/vader3/commit/f2641757d6ece032a59cb649558855a213fa579c

Was able to get it showing up in steam with paddle support.

I mapped C/Z to mirror the back middle buttons, since they are sorta hard to reach otherwise (and there isn't any other buttons available for the xbox controller to map to)

martindmtrv commented 8 months ago

Gonna try installing it on my steam deck!

martindmtrv commented 8 months ago

The changes I made work fine on my arch machine with steam. But when using it on the steam deck it seems like a conflicting kernel module loads and it's not able to work with it. Gotta do some more trial and error

martindmtrv commented 8 months ago

When using the steam deck, the mapping is read directly from SDL (regardless of what is outputted in the event handler).

Basically what this means is the output from evtest is what we are mapping. But when reading it in Steam input or some other SDL application the readings are all wrong since it is reading from hidraw directly

It looks like the only way to get this controller working without SDL taking matters into its own hands, would be to essentially parse the raw HID readings and convert it to the xbox compatible one.

martindmtrv commented 8 months ago

Not sure why it worked on my laptop but not the steam deck maybe since my laptop is using wayland and not X, or steamos has some forced handling with SDL at a kernel level

martindmtrv commented 8 months ago

in SDL source showing where some fixup is happening https://github.com/libsdl-org/SDL/blob/main/src/joystick/linux/SDL_sysjoystick.c#L191

martindmtrv commented 8 months ago

Oh nice I found a way around it!

https://forum.endeavouros.com/t/sdl2-breakage-changes/10551

You can disable SDL2 from reading hidraw directly by adding SDL_JOYSTICK_HIDAPI=0 to /etc/environment then rebooting

martindmtrv commented 8 months ago

I linked this post on the xpadneo repo as well. It may be a handy option since I don't see any other way to expose the paddles directly in steam

https://github.com/atar-axis/xpadneo/issues/458

kakra commented 8 months ago

This could also probably be mocked as a Xbox elite controller since the buttons would be better defined and closer to Xbox layout

I found this code snippet in xpadneo repo that could be helpful

https://github.com/atar-axis/xpadneo/blob/master/hid-xpadneo/src/hid-xpadneo.c#L1127

It seems like in the .probe method defined for the hid_driver you can modify the product / version id to mock another device

It is important to undo this change when at device shutdown time, otherwise things start to explode on next connection.

The xpadneo team (or primary maintainer) requested that I don't do this, as they've done a lot of work to make sure xpadneo probe output is the only output telling other systems that it's an xbox controller in this way.

This primarily concerned the way you hacked it into the driver. I also said if we can avoid changing the evdev mapping and instead rewrite the raw HID layer, we can integrate support for the Vader 3. I'd just prefer to do that after v0.10 because I'll try to avoid this mocking during development of v0.11.

You can disable SDL2 from reading hidraw directly by adding SDL_JOYSTICK_HIDAPI=0 to /etc/environment then rebooting

This should be documented somewhere in the xpadneo docs already.

martindmtrv commented 8 months ago

otherwise things start to explode on next connection

Good call-out not sure why it would explode but I suppose with C you can never be too careful

This should be documented somewhere in the xpadneo docs already.

I didn't see it in the README, perhaps it is just referenced in some issues (after searching this variable I see a few results in comments)

I also said if we can avoid changing the evdev mapping and instead rewrite the raw HID layer, we can integrate support for the Vader 3

So do you mean basically like translating the raw hid output from the controller to match that of an xbox controller? Doing it that way would make it simpler to build into xpadneo?

I can look into that once the v0.10 is released, in the meantime my forked module works for my purposes. I was even considering adding some additional features for the vader3 such as a shortcut to disable / enable c/z on the fly

kakra commented 8 months ago

otherwise things start to explode on next connection

Good call-out not sure why it would explode but I suppose with C you can never be too careful

The kernel caches devices somewhere in other layers. It's okay if it goes away, but if it comes back, strange things may happen, e.g. the device re-appears with the rewritten PID/VID. In case of xpadneo, this confuses xpadneo and it assigns wrong fixups. It may also confuse user-space (e.g. Steam may see the controller twice). And if it somehow bubbles into the hidraw interface, you may receive kernel panics.

This should be documented somewhere in the xpadneo docs already.

I didn't see it in the README, perhaps it is just referenced in some issues (after searching this variable I see a few results in comments)

I've discussed this in your xpadneo request.

I also said if we can avoid changing the evdev mapping and instead rewrite the raw HID layer, we can integrate support for the Vader 3

So do you mean basically like translating the raw hid output from the controller to match that of an xbox controller? Doing it that way would make it simpler to build into xpadneo?

Yes, that, or this device needs its own hidraw handler. If it wants to mock a Xbox controller, no button bits may be added in the first 16 buttons through the evdev structure, all additional buttons must be moved beyond the first trigger happy button (xpad already uses specific buttons here which SDL2 adapted). This is because user-space counts buttons in the keymap instead of looking at evdev symbols for gaming devices: If you insert additional buttons, buttons will shift in games. Windows XINPUT API supports exactly 12 gamepad buttons (16 bit word, including 12 buttons + 4 dpad positions), this means no more than 12 buttons in the BTN_GAMEPAD range to use for Xbox controllers if you want to prevent fixups in user-space. So everything after button 12 (Guide doesn't exists in this set of 12 buttons) must go to BTN_TRIGGER_HAPPY which is an extended gaming input range. Buttons must not bleed into other input bitmap ranges.

Here are my notes and thoughts on this: https://github.com/atar-axis/xpadneo/issues/286

I can look into that once the v0.10 is released, in the meantime my forked module works for my purposes. I was even considering adding some additional features for the vader3 such as a shortcut to disable / enable c/z on the fly

evdev has symbols for buttons C and Z, so you might just use that and see if SDL2 can handle it properly. The only purpose this driver is needed and you cannot properly use the hid-generic driver is probably because the HID descriptor of the Vader3 is somewhat broken or non-standard.

I think @ahungry moved all buttons to the trigger happy range, this should not be needed. the BTN_GAMEPAD range is not reserved for Xbox controllers. Essentially, it even swaps Y and X (it has BTN_NORTH which is X on old Nintendo controllers but Y on Xbox controllers), and Switch controllers have A and B swapped over what the kernel things should be at this position. The gamepad keymap was mostly designed by "physical position", not by "button symbol". But games look at symbols, or simply count bit positions in the keymap (more likely).