libsdl-org / SDL

Simple Directmedia Layer
https://libsdl.org
zlib License
9.79k stars 1.82k forks source link

SDL and Steam fight over state of Switch Pro Controller #3450

Closed SDLBugzilla closed 1 year ago

SDLBugzilla commented 3 years ago

This bug report was migrated from our old Bugzilla tracker.

Reported in version: HG 2.1 Reported for operating system, platform: Windows 10, x86

Comments on the original bug report:

On 2019-11-13 22:34:53 +0000, Austin Palmer wrote:

When Steam is running it will try to set the state of a Switch controller in either extended or normal mode based on whether the current focused window is opted in or out of Steam Input. The reason this is done is that over USB the device doesn't send input reports at all until initialized but when the controller is in the extended mode Dinput will be broken and receive lots of random buttons/axis inputs. We want games to be able to read from the device when required without breaking other games by leaving the device in the wrong state.

SDL right now always tries to set the state of the controller to extended mode - which provides gyro and an extended format for the joystick. Since SDL doesn't read the gyro it'd be nice if it detected the state when opening the controller and only ran initialization when required - which to my understanding should only be if the device is connected over USB and not yet initialized by Steam. The shutdown code might also need to conditionally not run if another process is trying to use the controller.

Bug report from dev about Steam/SDL fighting: https://steamcommunity.com/groups/steamworks/discussions/22/1676938384243676229/

On 2019-11-17 06:53:03 +0000, Sam Lantinga wrote:

Any suggestions on how to detect whether initialization is necessary?

SortaCore commented 2 years ago

Getting this issue still, with SDL 2.0.20 on Windows. Switch controller is inconsistent in its input - with Steam open, the Switch Pro controller gets input for a couple seconds, loses it for a couple (the input values, like axis freeze), then it gets input back for a couple seconds, repeat. There doesn't appear to be device add/remove events. This only affects Switch Pro when it's on USB; Bluetooth works consistently on both Steam and my SDL app.

I can't view the Steam community link above, members only, so I'm not sure what's gone on there.

icculus commented 2 years ago

Tossing this to Sam for 2.24.0, but feel free to bump this out of the milestone if we don't have time. It's possible we fixed this, too..this seems like it would generate a lot of noise if we hadn't...

slouken commented 2 years ago

Steam and SDL have both made changes to improve this. Are you still seeing this with the latest version of Steam and SDL main code?

SortaCore commented 2 years ago

Yes, seems to still happen using current master 5d85c7d300e91d89431f5b12221cd1e5655aa33b. Steam seems to see the controller connecting and disconnecting, whereas the second SDL app using 5d85c7d300e91d89431f5b12221cd1e5655aa33b keeps it connected, but keeps freezing input in time with Steam's disconnects and reconnects.

https://user-images.githubusercontent.com/1324301/181034334-456aed47-c0ec-47eb-9028-abdcb629f35a.mp4

Here's a screen recording demonstrating. If the Steam window doesn't have focus in the controller settings, it will start the bug, regularly freezing input to the other app, although the other app doesn't seem to be seeing a controller disconnect, just an input freeze. The other app is using SDL statically, and doesn't use an SDL window, just the joystick/haptic system.

If neither of the apps have focus, Steam causes the bug as well.
When you exit Steam settings, the bug sticks around, affecting the other app with a regular loss of input.
Once Steam is closed entirely, the other app loses access to the joystick entirely, freezing indefinitely, even though it's using SDL statically and so shouldn't share anything with Steam's SDL.
Restarting the other app restores normal input to its SDL joysticks, but restarting Steam after restarting the other app, causes the bug again, even before you enter Steam settings.

slouken commented 2 years ago

It looks like this is purely a Steam issue.

If you watch Steam, even with no other programs running, it will occasionally disconnect the controller after alt-tabbing away from the controller settings window. It's being disconnected because it stops receiving reports from the controller.

SortaCore commented 2 years ago

The other program doesn't seem to get controller disconnected events, though, which I would have expected if another SDL program closed it on OS level. What could Steam be doing that will make the other SDL program lose the controllers silently?

If it is Steam, I can't see the discussion, due to the group discussion permissions. Are they any closer to fixing it or do they have any relevant details?

slouken commented 2 years ago

It seems to be happening when Steam switches the controller to simple report mode. Something about that process seems to occasionally wedge the controller so it doesn't generate inputs until it's reinitialized - either by Steam or by another SDL program opening the controller.

I'll update this bug report when there's a Steam beta client with a fix available.

slouken commented 2 years ago

Actually Steam is just disabling reports entirely so DirectInput and WGI games don't get spammed with garbage input. Fortunately, this is easy to fix for SDL applications.

SortaCore commented 2 years ago

Actually Steam is just disabling reports entirely so DirectInput and WGI games don't get spammed with garbage input. Fortunately, this is easy to fix for SDL applications.

Latest commit, if Steam is open, now sends no input at all - is that what you meant?

slouken commented 2 years ago

Nope, it's working here. Are you able to repro with testgamecontroller? That's what I've been testing.

SortaCore commented 2 years ago

testgamecontroller works great, but in my app, both the Joystick and GameController interfaces are either working fine, or no input through when Steam is open, although they recognise the controller is connected and can get the controller name, number of buttons and axes, and so on; but they can't get any button states, axis states, etc. At one point, was working fine, I switched windows around (without switching to Steam), and it lost input. testgamecontroller was unaffected.

slouken commented 2 years ago

Can you debug and see why testgamecontroller works and your app doesn't?

slouken commented 2 years ago

Is this still an issue with the Steam beta update dated 8/4 or newer?

SortaCore commented 2 years ago

(Sorry, my attention's been pulled by other projects.)

Yes, still an issue with 5th Aug build. The statistics are available, everything else missing.

When Switch was connected, there's a small freeze, it sends statistics like num of axis, and sometimes the initial values of the sticks. Curiously, controller disconnect gets a much longer freeze, on deleting the device, main thread waiting on rumble thread, and rumble thread stuck with a high request->device->rumble_pending (34k rumble_pending on one test), even though no rumble is sent by my app, and the request->device->dev is null.

slouken commented 2 years ago

Can you debug why it's an issue in your application and not in testgamecontroller?

SortaCore commented 2 years ago

I will look into it, but it may be a couple months before I can. I have limited access to my dev environment for the next couple of weeks.

I'm using SDL static, and disabling some SDL features with CMake, since the plan is only using joystick related features. I think I was pretty safe with my choices, but is there any that may be needed for this to work properly? https://github.com/SortaCore/SDLJoystick-priv/ has my configuration for a previous SDL in the README.

slouken commented 2 years ago

Threads are the only thing off the top of my head that are needed, but it looks like you have those enabled.

By the way, I highly recommend shipping SDL2.dll as it will allow developers and end users to easily update the SDK with future SDL controller support. For example, we're about to add Joy-Con support, and if a developer has statically linked SDL, customers won't be able to take advantage of that when the developer has moved on to other projects.

slouken commented 2 years ago

I'm bumping this out of the current milestone so you have time to investigate in more detail.

SortaCore commented 1 year ago

@slouken Just used SDL3, and while the new commit bb5b130be81aeee288cbd8493a39a3ac20917158 doesn't fix it, it's very close. The only issue is async write to change the reporting mode doesn't go through; the Rumble thread doesn't seem to send the request, but just queues indefinitely. This also makes the Switch freeze the application on joystick close, while the rumble_pending count is slowly decremented by rumble thread, while main thread waits for it.

I found a fix for it by adding some lines around the ForceUSB to make it always switch on main thread:

/* Steam may have put the controller back into non-reporting mode */
SDL_bool oldSyncWrite = ctx->m_bSyncWrite;
ctx->m_bSyncWrite = SDL_TRUE;
WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE);
ctx->m_bSyncWrite = oldSyncWrite;

Then that seems to fix it for both disconnects and connects.

slouken commented 1 year ago

Great, thanks!

Squall-Leonhart commented 8 months ago

Steam and SDL have both made changes to improve this. Are you still seeing this with the latest version of Steam and SDL main code?

I can still replicate this issue with Cemu, built with SDL 2.30

Cemu started while Steam is running will show the Switch Pro controller for a second and then the list of controllers blanks and no longer picks it up, kill steam and load cemu back up and the control is fine, even if you open steam back up.