ValveSoftware / Proton

Compatibility tool for Steam Play based on Wine and additional components
Other
24.45k stars 1.07k forks source link

HitBox-style controller "last input priority" direction input behavior differs between games running natively and through Proton #5527

Open bsstephan opened 2 years ago

bsstephan commented 2 years ago

Please excuse the confusing title. I'm seeing a repeatable, predictable situation where games run through Proton do not register inputs properly on controllers with a certain type of axes behavior.

"HitBox" style controllers that use buttons for directions have "simultaneous opposite cardinal direction cleaners", which ensure that impossible direction combinations (e.g. left and right simultaneously) are not sent to the game. These cleaners also define the behavior that should happen instead --- one such option is last input priority, which sends the most recent button press, overriding the previous opposite button. The behavior of this method is different between native Linux games and games run through Proton, and the nature of the different, incorrect behavior is consistent across Proton games I have tested.

When I run Skullgirls (245170)'s native Linux version and enter training mode, if I...

  1. Hold left, I walk left;
  2. Simultaneously hold right, I walk right;
  3. Let go of right, I walk left.

This is also visible in e.g. the KDE Plasma Game Controller tester.

  1. Axis 7 = -32767
  2. Axis 7 = 32767
  3. Axis 7 = -32767

However, if I launch Skullgirls through Proton (forcing "Steam Play", version Proton-6.19-GE-2), I get this behavior:

  1. Hold left, I walk left;
  2. Simultaneously hold right, I walk right;
  3. Let go of right, I stand still, but can see in the Plasma Game Controller tester that Axis 7 = -32767.

Additionally,

  1. Hold right, I walk right;
  2. Simultaneously hold left, I stand still (and again can see Axis 7 = -32767),
  3. Let go of left, I walk right.

Similar behavior on the up/down:

  1. Hold up, I jump continuously;
  2. Simultaneously hold down, I crouch;
  3. Let go of down, I stand still (Axis 8 = -32767).

and

  1. Hold down, I crouch;
  2. Simultaneously hold up, I stand still (Axis 8 = -32767);
  3. Let go of up, I crouch.

I see this particular faulty behavior across Proton games I've tested: Skullgirls, BlazBlue Central Fiction (586140), Guilty Gear Xrd -REVELATOR- (520440), and DoDonPachi Resurrection (464450), and have confirmed expected behavior in native Linux Skullgirls, Corpse Party (251270), and Danganronpa: Trigger Happy Havoc (413410). I also tried running my system wine control and it looked like I was getting the expected behavior in the Windows-y tester, but I don't know how useful that is.

In all situations, if I use a traditional joystick lever instead of buttons, everything works as expected, native or Proton. If I had to make a guess, maybe somewhere in Proton/wine the stack is looking for the axis to return to neutral (-32767 > 0 > 32767) and falls back to some different behavior when it doesn't? I don't think an axis can be "depressed" and "pressed" in the sense that it'd be looking for me to depress the left button and press it again before it registered left again, but I don't know.

Frankly, I recognize this request is kind of deep in the weeds, but it definitely makes a lot of Proton games only kinda playable on my setup, as specialized as it is. I'd of course love it if someone skilled with Proton/wine knew exactly what to fix, but I can write C code and kinda understand what to do, if anyone has breadcrumbs for what I should just tinker with, I'd appreciate any help I can get.

Thanks.

bsstephan commented 2 years ago

Oh yeah, and I could take a desktop capture of this behavior, if anyone is curious and/or confused by my rambling.

bsstephan commented 2 years ago

I can't reproduce this anymore, so I'll close this issue. Possible explanations:

I did notice someone else reportedly experience this behavior in Guilty Gear Strive (https://www.protondb.com/app/1384160#M8efM5PGN5), I haven't tested any further since things work on my new install and I'd prefer not to mess with it. :)

TheDukeofErl commented 2 years ago

The issue is closed now but I have also investigated this issue and figure it's worth documenting some of the investigation I did into this issue a while ago.

I experienced the same issue with my Hitbox-esque controller (Brook Universal Fighting Board, to be specific) and spent quite a bit of time debugging the issue. Specifically, I noticed it with Proton-GE, which uses the Wine controller SDL gamepad patches rather than the Proton ones. Wine recently updated their implementation in the 7.0 release as well, which may be the cause, but I did not regression test 6.x: https://www.winehq.org/announce/7.0

Looking at that, I began to further investigate the issue. I compiled WINE from source and enabled the debug flags in the areas of the WINE code that handle controller input to try to determine where things were going wrong. There I still saw the behavior you were describing in the first post: the SOCD cleaning was not being handled correctly. WineHQ offers some suggestions for troubleshooting this issue in the useful registry keys section: https://wiki.winehq.org/Useful_Registry_Keys. Playing with these registry entries proved to be fruitful: disabling SDL or disabling the automatic SDL mapping of controllers fixed the issue within the Wine gampad screen. I was unable to fix the issue with a custom SDL mapping, though this may be due to me making a bad mapping, as I am not very familiar with the process.

With the SDL mapping disabled, a new problem was introduced. Using GE, BBCF no longer detected the controller at all, likely due to the lack of Wine mapping it, as it uses the Wine implementation of controller input, rather than the Proton one: https://github.com/GloriousEggroll/proton-ge-custom/releases/tag/6.18-GE-1.

At the end of the day, it appears to be an issue specifically with the way Wine is using SDL. The resolution for this issue for me was simply to go back to using regular Proton. GE wasn't necessary for me anymore since Valve began transcoding the WMA videos and injecting them into the game.

The next steps would likely involve trying to use the SDL mapping Wine uses without using Wine explicitly to verify the issue lies there, though I don't know how to go about that or if it's something that can feasibly be done.

If/when Valve decides to switch to the upstream version of Wine's controller mapping again this will likely become an issue again. It's possible that they tested the use of it briefly and subsequently reverted the code, which would have caused you to see this issue.

If for any reason you do decide to try to tinker with the code, hopefully this is helpful.

TheDukeofErl commented 2 years ago

Looking at the commits for Proton 7.0, I noticed that it appeared that the documentation behind the controllers has changed: https://github.com/ValveSoftware/Proton/commit/f3b9480b5f3d41aa974e1d36bf11d0ba3e72bd6f

A quick test of BlazBlue Centralfiction with Proton 7.0 revealed that this issue is present with the new version of Proton.

I have attached a video of this bug:

https://user-images.githubusercontent.com/9062191/154582912-f54dd905-2215-4836-bd05-75eef284390a.mp4

In the video, axis 8 is the vertical input of the controller (Hitbox-style Brook Universal Fighting Board). Inputs are as follows: DOWN: 32767 UP: -32767 In the video, you can see that up and down correlate to these values on axis 8. Near the end of the video, the following operation is performed:

  1. Down is pressed
  2. Up is pressed
  3. Up is released

When up is released, based on the inputs, it should be expected that the input in the game return to down, as it does in for the game controller axis. However, it returns to center.

@bsstephan, would you please re-open this issue?

bsstephan commented 2 years ago

I'm on vacation through the rest of Feb, so I can't play around with any code or patches, but the above sounds legitimate enough for me to reopen this.

Ilazki commented 2 years ago

I don't have a hitbox style controller, but I believe I was also triggering this same problem with Proton while attempting to play Guilty Gear Strive with a normal controller as well. I kept having problems with the super move inputs (half circle back, forward; e.g 632146 using numpad notation) so I went into training and checked. What I found there is that, if I did the motion quickly enough, it would treat the rapid change from back (4) to forward (6) as neutral instead, never sending the forward, which caused the motion to be incorrect.

I thought at first it was the controller I was using so I ended up testing with 3 controllers: nintendo switch pro controller, dual shock 4, and an 8bitdo pro 2 in three different modes (Switch, Playstation, and Xbox) and the behaviour was the same for all. Even though it's not actually possible to press simultaneous left+right on the dpad of those controllers, performing the inputs very quickly had the same effect as the original bug report, with a rapid left->right input being treated as simultaneous left+right, which then got cancelled out and treated as neutral.

LionHeartP commented 2 years ago

I have the same issue that I have only noticed on GE branch before Proton 7 came out.

My character will be stuck either stand blocking or crouching without blocking even though I'm holding down + back on various occasions during a match.

I have to let go of the button and press it again for it to register.

Edit: Using proton 6.3-8 does not detect my controller. There's literally no way to play "King of Fighters XV" on Linux on a hitbox without this bug affecting you, to my knowledge at least.

LionHeartP commented 2 years ago

I managed to find a workaround!

I mapped my "dpad" as left stick instead through Steam and now it works as intended.

TheDukeofErl commented 2 years ago

I managed to find a workaround!

I mapped my "dpad" as left stick instead through Steam and now it works as intended.

Interesting, then the correction must only being applied to the dpad axes, not to the stick. I generally don't use Steam input but will have to give this a shot.

TheDukeofErl commented 2 years ago

@LionHeartP's workaround is working for me as well. The configuration is a little obtuse though: you have to go into big picture mode, select the game in library, go to Manage Game, set Controller Options to Forced On if not using Steam Input otherwise, then go into Controller Configuration and set the dpad to Joystick Move. After that, you can exit big picture and things should start working as expected!

Note: it seems that for me Forced On doesn't work right: it's necessary to have the Xbox controller config on globally.

bsstephan commented 2 years ago

The workaround is interesting but definitely obnoxious, especially when not using Big Picture mode. Also interestingly, not sure if I'd lost my mind before vacation or what, but I fired up BlazBlue Central Fiction again today, and with the latest Proton Experimental... I have the same buggy behavior again.

LionHeartP commented 2 years ago

The workaround is interesting but definitely obnoxious, especially when not using Big Picture mode. Also interestingly, not sure if I'd lost my mind before vacation or what, but I fired up BlazBlue Central Fiction again today, and with the latest Proton Experimental... I have the same buggy behavior again.

You only need to set it once in Big Picture mode and then it works every time. It should automatically load that profile every time you plug in that specific controller.

namtsui commented 2 years ago

This is a regression in wine.

I have a hitbox controller from hitbox (the company). I see this behavior in Guilty Gear XX Accent Core Plus R on latest proton experimental. THE KING OF FIGHTERS '98 ULTIMATE MATCH FINAL EDITION is also affected. Skullgirls (native) does not have this problem and has correct behavior.

Steps to reproduce the problem:

  1. Press down and keep holding it
  2. Press up
  3. Release up

The character returns to neutral and is standing. This is incorrect behavior because I was holding down the entire time, so the character should be crouching.

When down and up are input at the same time, up is output on hitbox (SOCD cleaning).

When I test with Proton 5.13-6, it exhibits the correct behavior. The character crouches after jumping.

I tested melty blood actress again current code (outside of steam) with wine 7.0. It exhibits this bug where the character is standing after that sequence.

This refactoring commit could be to blame: https://github.com/wine-mirror/wine/commit/9cf1e8353cf05af1009e3e5d40b62f0e70761f3f

See the file: wine-7.0/dlls/winebus.sys/bus_sdl.c https://github.com/wine-mirror/wine/blob/6d4ec1255acceec7152ed98764ee29991ac04f10/dlls/winebus.sys/bus_sdl.c#L850-L855

I added print statements:

--- bus_sdl.c.orig  2022-04-19 01:48:03.404481969 -0700
+++ bus_sdl.c   2022-04-19 02:42:20.867910511 -0700
@@ -799,15 +799,19 @@
             switch ((button = ie->button))
             {
             case SDL_CONTROLLER_BUTTON_DPAD_UP:
+       FIXME("DPAD UP\n");
                 hid_device_set_hatswitch_y(iface, 0, ie->state ? -1 : 0);
                 break;
             case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
+       FIXME("DPAD DOWN\n");
                 hid_device_set_hatswitch_y(iface, 0, ie->state ? +1 : 0);
                 break;
             case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
+       FIXME("DPAD LEFT\n");
                 hid_device_set_hatswitch_x(iface, 0, ie->state ? -1 : 0);
                 break;
             case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
+       FIXME("DPAD RIGHT\n");
                 hid_device_set_hatswitch_x(iface, 0, ie->state ? +1 : 0);
                 break;
             case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: button = 4; break;

I have two clips from melty blood actress again current code, as mentioned above, to better show what is going on. The button GUI display isn't entirely accurate as it might show me releasing down and tapping up, but this is where the hardware SOCD cleaning comes in. When down + up are pressed simultaneously, this hitbox shows release of down and pressing up. I am holding down for the majority of the clips though.

In clip 1, I demonstrate SDL2 events when down and up are held simultaneously during a jump for a while:

  1. hold down (DOWN press event)
  2. hold up (DOWN release event. UP press event.)
  3. hold both for a while
  4. release all (UP release event. DOWN release event.)

[1] https://clips.twitch.tv/PlausibleSparklingButterJonCarnage-1nJQjUmS_kATb5Y6

In clip 2 the actual bug is shown.

  1. hold down (DOWN press event)
  2. press up (DOWN release event. UP press event.) steps 1 to 2 were demonstrated in clip 1.
  3. release up (DOWN press event. UP release event.)
  4. keep holding down

EDIT: replaced clip 2 with a new clip showing training mode input [2] https://clips.twitch.tv/FunnyPlayfulClintmullinsArgieB8-p3pUOVQuS-eA8oqi

The UP release event at the end in step 3 causes the axis to be reset to 0. This ignores the DOWN press event immediately preceding it.

I'll poke around some more. Maybe check if down is held before immediately setting the axis to 0 upon an UP release event.

SDL_GameControllerGetButton could be used. https://wiki.libsdl.org/SDL_GameControllerGetButton

namtsui commented 2 years ago

clip 3 shows a fix with the following patch applied. Compare it with clip 2 (before fix).

[3] https://clips.twitch.tv/RacyNeighborlyCookiePeteZaroll-2wwLnflwjAa3ZlFz

This patch seems to resolve this bug. Something similar should probably be applied to left and right (last input wins).

--- bus_sdl.c.orig  2022-04-19 01:48:03.404481969 -0700
+++ bus_sdl.c   2022-04-19 17:05:52.674063449 -0700
@@ -799,15 +799,25 @@
             switch ((button = ie->button))
             {
             case SDL_CONTROLLER_BUTTON_DPAD_UP:
-                hid_device_set_hatswitch_y(iface, 0, ie->state ? -1 : 0);
+       FIXME("DPAD UP\n");
+       if (ie->state) {
+           hid_device_set_hatswitch_y(iface, 0, -1);
+       } else {
+           if (!pSDL_GameControllerGetButton(impl->sdl_controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN)) {
+               hid_device_set_hatswitch_y(iface, 0, 0);
+           }
+       }
                 break;
             case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
+       FIXME("DPAD DOWN\n");
                 hid_device_set_hatswitch_y(iface, 0, ie->state ? +1 : 0);
                 break;
             case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
+       FIXME("DPAD LEFT\n");
                 hid_device_set_hatswitch_x(iface, 0, ie->state ? -1 : 0);
                 break;
             case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
+       FIXME("DPAD RIGHT\n");
                 hid_device_set_hatswitch_x(iface, 0, ie->state ? +1 : 0);
                 break;
             case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: button = 4; break;
namtsui commented 2 years ago

I opened a bug report with wine: https://bugs.winehq.org/show_bug.cgi?id=52841

I proposed this fix. Testing is welcome because my controller doesn't have the last input wins method for left && right. Left && right outputs neutral.

--- bus_sdl.c.orig  2022-04-19 01:48:03.404481969 -0700
+++ bus_sdl.c   2022-04-19 17:34:37.308329960 -0700
@@ -799,16 +799,44 @@
             switch ((button = ie->button))
             {
             case SDL_CONTROLLER_BUTTON_DPAD_UP:
-                hid_device_set_hatswitch_y(iface, 0, ie->state ? -1 : 0);
+                FIXME("DPAD UP\n");
+                if (ie->state) {
+                    hid_device_set_hatswitch_y(iface, 0, -1);
+                } else {
+                    if (!pSDL_GameControllerGetButton(impl->sdl_controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN)) {
+                        hid_device_set_hatswitch_y(iface, 0, 0);
+                    }
+                }
                 break;
             case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
-                hid_device_set_hatswitch_y(iface, 0, ie->state ? +1 : 0);
+                FIXME("DPAD DOWN\n");
+                if (ie->state) {
+                    hid_device_set_hatswitch_y(iface, 0, +1);
+                } else {
+                    if (!pSDL_GameControllerGetButton(impl->sdl_controller, SDL_CONTROLLER_BUTTON_DPAD_UP)) {
+                        hid_device_set_hatswitch_y(iface, 0, 0);
+                    }
+                }
                 break;
             case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
-                hid_device_set_hatswitch_x(iface, 0, ie->state ? -1 : 0);
+                FIXME("DPAD LEFT\n");
+                if (ie->state) {
+                    hid_device_set_hatswitch_x(iface, 0, -1);
+                } else {
+                    if (!pSDL_GameControllerGetButton(impl->sdl_controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) {
+                        hid_device_set_hatswitch_x(iface, 0, 0);
+                    }
+                }
                 break;
             case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
-                hid_device_set_hatswitch_x(iface, 0, ie->state ? +1 : 0);
+                FIXME("DPAD RIGHT\n");
+                if (ie->state) {
+                    hid_device_set_hatswitch_x(iface, 0, +1);
+                } else {
+                    if (!pSDL_GameControllerGetButton(impl->sdl_controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT)) {
+                        hid_device_set_hatswitch_x(iface, 0, 0);
+                    }
+                }
                 break;
             case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: button = 4; break;
             case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: button = 5; break;
namtsui commented 2 years ago

wine upstream fixed this. see: https://github.com/wine-mirror/wine/commit/e2936702a47247f806478f16d4631516ca2c3e9f

The wine release >7.10 will have the fix.

LionHeartP commented 2 years ago

wine upstream fixed this. see: wine-mirror/wine@e293670

The wine release >7.10 will have the fix.

Yeah it's already fixed for me on GE or experimental. Not sure which one but I haven't had to do this for like a couple of weeks or so.

namtsui commented 2 years ago

Specifically, I noticed it with Proton-GE, which uses the Wine controller SDL gamepad patches rather than the Proton ones.

If/when Valve decides to switch to the upstream version of Wine's controller mapping again this will likely become an issue again.

yeah good notes. So, proton experimental uses older controller mapping and GE uses upstream wine's. In my testing I was able to reproduce this bug using proton experimental in blazblue centralfiction, kof 98, melty blood type lumina and melty blood actress again current code.

EDIT: I might be incorrect about proton experimental using older controller mapping because I was able to reproduce bug in proton experimental but proton 5.13-6 restores controls.

mauruco commented 2 years ago

I can't get it to work. Nothing works. Whenever I jump the game loses the down input. On gamepad-testercom it works fine. Detail that with the raspberry pico (FeralAI/GP2040) it works in all the proton versions that I tested in the "left stick" mode.

Brook PS4+ Audio Fighting Board Fw 1.9 (DP & LS [left stick]) Street Fighter V Arch 5.19.6-arch1-1 Ryzen 5 PRO 4650G Nvidia 1070Ti Zotac, Nvidia Propietary Drivers Proton 7.0-4 & Pronto 6.38 & Proton Experimental

GoLD-ReaVeR commented 2 years ago

Is there an ETA on a fix for this? A friend of mine wants to play with me and this is preventing that from happening.

Etaash-mathamsetty commented 2 years ago

wine upstream fixed this. see: wine-mirror/wine@e293670

The wine release >7.10 will have the fix.

it probably could be easily back ported then, somebody (a proton dev) just has to see this thread

monigira commented 2 years ago

As of the most recent Proton experimental release, and today's date, the problem is mostly fixed, really awesome job!, or perhaps there's a game-specific bug.

Across Street Fighter V, Ultra Street Fighter IV, Guilty Gear Xrd Revelation, Guilty Gear Strive, Guilty Gear Accent Core +R, BlazBlue Centralfiction, Samurai Shodown V Special, Killer Instinct, Dead or Alive 6, Tekken 7, Them's Fightin' Herds (though this may be a native Linux port I'm not sure), Ultra Fight Da Kyanta 2, King of Fighters 13, King of Fighters '98 Ultimate Match, King of Fighters 2002 Unlimited Match, and Punch Planet it behaves as expected: left + right = neutral up + down = up

But out of my testing, King of Fighters XV exclusively has this issue: up + down = up, but after releasing up, you get a neutral input and down is not registered until down is released and pressed again.

bsstephan commented 2 years ago

I had a chance to mess around with BlazBlue Central Fiction and I found that the desired "last input priority" behavior is present now as well, yay! Hopefully KOF15 gets sorted out and this remains stable for everyone.

GoLD-ReaVeR commented 2 years ago

I've tested this and the input issue is still there for me. When I hold up and down and release up the game registers the controller as having gone to center instead of registering the down button. I've tried with all experimental branches that were relevant, including the shared-resources, bleeding edge as well as the base one.

bsstephan commented 2 years ago

All on Proton Experimental, the following all now have proper last input priority:

Not sure what's going on with the person above, but it's looking good for me.

GoLD-ReaVeR commented 2 years ago

Are you using steam input enabled or disabled?

monigira commented 2 years ago

@GoLD-ReaVeR I have steam input enabled!

FrozenFish24 commented 1 year ago

I switched to hitbox recently (Brook UFB) and I'm seeing the same issue on Proton Experimental:

Press and hold down Tap up Stick reads neutral instead of down

KDE Game Controller dialog shows correct values like OP.

GoLD-ReaVeR commented 1 year ago

Yeah, if you switch to steam controller input rather than direct controller input this problem goes away. It's a bit on the hacky side but I guess it works. I'd rather see the SOCD behavior fixed properly in wine.

WaffleSlapper commented 1 year ago

As mentioned in previous comments... You can use Proton-GE to have proper Wine implementation for SOCD inputs. This works for every game modern or old.

Alternatively, if the game can run on Proton 5.13, you can use that instead since that version uses the correct SOCD implementation properly ran through Wine.

Switching to Steam Controller input did not work for me other than any issues the game itself had detecting my controller in the first place.

FrozenFish24 commented 1 year ago

@GoLD-ReaVeR @WaffleSlapper I see, if I enable "Xbox Configuration Support" with the default "Gamepad" mapping then the problem disappears. Vanilla and GE act the same for me.