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

Controller reconnection does not emit joy_connection_changed signal on Steam Deck #76879

Closed
tcoxon opened this issue May 9, 2023 · 18 comments · Fixed by #76961
Closed

Controller reconnection does not emit joy_connection_changed signal on Steam Deck #76879

tcoxon opened this issue May 9, 2023 · 18 comments · Fixed by #76961

Comments

@tcoxon
Copy link
Contributor

tcoxon commented May 9, 2023

Godot version

3.5.1.stable

System information

Steam Deck

Issue description

Steam Deck owners who have played Cassette Beasts report that the only way they can get external controllers to reconnect after a disconnection is to restart the whole game.

Cassette Beasts connects to the Input.joy_connection_changed signal and logs when controllers are connected or disconnected. It also logs the controllers already available when the game starts. From the logs players have sent me I can see that:

  • controllers connected while the game starts up are detected (via Input.get_connected_joypads)
  • controller disconnection events are detected
  • no controller connection events are detected

It seems like the engine does not seem to detect controller connection events. However I don't know whether this is a Steam issue or an engine issue.

I did some additional testing around this (with bluetooth controllers, but not any wired controllers):

  • Reconnection is not detected in Gaming Mode
  • Reconnection is not detected in Desktop Mode, when launched from the Steam client
  • Reconnection is correctly detected in Desktop Mode, when launched from the install directory, or the Godot editor.
  • The issue is unaffected by whether I use the stock linux 64-bit export template or my modified engine binaries
  • The issue is unaffected by the model of controller. It happens with xbox and PS5 controllers at the very least
  • Although the engine doesn't detect the reconnected controller, there are no problems using it to navigate Steam
  • Adding a Godot project to Steam as a non-Steam game for testing is not enough to trigger the bug. It seems like the game actually has to be published through Steam (or overwrite the pck and binary of a project that has been published through Steam)
  • Whether Steam Input is enabled or not for the controller and game makes no difference

Steps to reproduce

  1. Install a Godot game with controller support on a Steam Deck.
  2. Connect a bluetooth controller to the Steam Deck
  3. Launch the game
  4. Check whether the controller has been detected by the game
  5. Shut down the controller, and then power it on again
  6. Check whether the controller has been detected by the game

Minimal reproduction project

Attach this script to a scene, export the project, publish it through Steam (or overwrite the pck and executable in the install directory of a Godot project already published through Steam), then launch it through Steam:

func _ready() -> void:
	for joypad in Input.get_connected_joypads():
		print("Detected joypad device: ", joypad)
	Input.connect("joy_connection_changed", self, "_on_joy_connection_changed")

func _on_joy_connection_changed(device: int, connected: bool) -> void:
	if connected:
		print("Detected joypad connection: ", device)
	else:
		print("Detected joypad disconnection: ", device)
@Calinou
Copy link
Member

Calinou commented May 9, 2023

  • Can the issue be reproduced on Steam Decks running Windows?
  • Can the issue be reproduced on Linux binaries compiled with udev=no (yes is the default)?

@akien-mga
Copy link
Member

Can the issue be reproduced on Linux binaries compiled with udev=no (yes is the default)?

As a side check to this, running the engine with the verbose flag should show whether udev is found or not:

JoypadLinux: udev enabled and loaded successfully.

@tcoxon
Copy link
Contributor Author

tcoxon commented May 9, 2023

I haven't checked if it can be reproduced on Steam Decks running Windows. Don't really want to risk bricking my sole Steam Deck test device.

Before rebuilding the engine (i.e. with default udev) the verbose log did indeed contain JoypadLinux: udev enabled and loaded successfully.

If the engine is built udev=no it detects controller reconnection events, and the log contains JoypadLinux: udev disabled, parsing /dev/input to detect joypads.

I found this comment in an issue raised against the Steam runtime. It seems to suggest that udev just cannot be relied upon in a Steam Linux Runtime or Flatpak context.

Would I lose anything important by switching all my builds to udev=no?

@akien-mga
Copy link
Member

If the engine is built udev=no it detects controller reconnection events, and the log contains JoypadLinux: udev disabled, parsing /dev/input to detect joypads.

I found this comment in an issue raised against the Steam runtime. It seems to suggest that udev just cannot be relied upon in a Steam Linux Runtime or Flatpak context.

That's interesting, the comment by @smcv does sound directly related to our problem. Godot's joypad hotplugging code is current either/or, using udev if found, and falling back to parsing /dev/input/ manually otherwise.
But apparently udev is unusable in a sandbox so indeed we'd have to do like SDL2 and do a best attempt at detecting whether we're sandboxed, to fallback to manual probing of /dev/input/ (ref: https://github.com/libsdl-org/SDL/blob/6d9ccbb3c77f42be13933d3ad9fa2dd9219e3894/src/core/linux/SDL_sandbox.c#L28-L45).

Would I lose anything important by switching all my builds to udev=no?

I'm not sure. I believe using udev is actually supposed to be more reliable, but I don't know the details. @27thLiz's original (re)implementation of Linux joypad support used udev, and she later added support for opting out of it in #3708.


For context, did some testing too:

I can reproduce the issue on Steam Deck, while it works fine on my Linux desktop (distro package for Steam, not Flatpak).

I guess Steam on the Steam Deck / Holo runs in a different way to what it does on other Linux desktop distros.

Here's what I see in the logs on the Deck:

Device 0 connected: Steam Virtual Gamepad 03000000de280000ff11000001000000
Device 1 connected: Steam Virtual Gamepad 03000000de280000ff11000001000000
Device 2 connected: Xbox Wireless Controller 050000005e040000130b000015050000
# Disconnect Xbox gamepad
Device 2 disconnected
Device 0 disconnected
# Reconnect Xbox gamepad (nothing)

(This duplicated Device 0 was also probably a source of input issues we've had at GDC on Steam Decks with those same wireless controllers. Device 1 should be the Steam Deck itself.)

On my Linux desktop:

Device 0 connected: Xbox Series X Controller 050000005e040000130b000015050000
# Disconnect Xbox gamepad
Device 0 disconnected
# Reconnect Xbox gamepad
Device 0 connected: Xbox Series X Controller 050000005e040000130b000015050000

@smcv
Copy link

smcv commented May 10, 2023

Godot's joypad hotplugging code is current either/or, using udev if found, and falling back to parsing /dev/input/ manually otherwise. But apparently udev is unusable in a sandbox so indeed we'd have to do like SDL2 and do a best attempt at detecting whether we're sandboxed

Yes, SDL's approach is the least-bad way to deal with this. The Steam container runtime cannot make this work more transparently than it already does, because we're constrained by how udev and evdev were designed. If Godot doesn't use SDL, then it'll be necessary to reinvent essentially the same logic that SDL uses, including having a heuristic to decide which input devices are gamepads suitable for your game and which ones are accelerometers or other weird things which should be ignored unless supported, based on their evdev capabilities and/or the information in /sys.

Another possible route would be to treat SDL as being a "platform library" on Linux, analogous to how you presumably use DirectX interfaces on Windows, and build higher-level interfaces over the top of it where needed. Some other game engines already work that way, and so does Proton.

I've thought about providing a shim/modified libudev that fakes the information you would have seen on the host system by using IPC to a service running the real libudev outside the container; but libudev's API is really at too low a level for that to be particularly feasible, so this is unlikely to happen.

The reason this is different on Steam Deck is that the Steam Deck's operating system is a fast-moving rolling release based on Arch Linux, so it's too much of a moving target to be reasonable for games to run on it directly or via the legacy LD_LIBRARY_PATH Steam Runtime - that would come with a high risk of games working in 2023, but failing to work in 2025 or 2030 when the operating system has changed too much for them to keep up with. Instead, by default native Linux games on Deck run in the Steam container runtime (specifically the scout-on-soldier version, which provides ABI compatibility with the legacy LD_LIBRARY_PATH runtime). That's designed to be more a stable thing to support for years to come.

It is also possible to opt-in to using the newer, legacy-free Steam Runtime 3 "sniper" container runtime by editing a game's metadata, but at the moment there's no interface for that in Valve's partner web-UI, so that change can only be done with help from a Valve developer. When sniper becomes available on a self-service basis, I suspect that the developers of games based on open source engines like Godot will want to start targeting that preferentially, with binaries built in a sniper container.

On desktop Linux, you can force a game to use the same runtime as on the Deck via Properties -> Compatibility -> Force the use of -> Steam Linux Runtime (behind the scenes, that's the scout-on-soldier container runtime). You should find that you get the same results as on Deck: if you're relying on udev for device enumeration, then controllers that are already there at startup (in particular the built-in controls) will often work, but hotplugging USB controllers or connecting Bluetooth controllers during gameplay usually won't, because the notification that says a new controller was connected doesn't arrive in your game code.

Running a game as a Flatpak app, or inside a Flatpak app like the unofficial Flatpak version of Steam (even without using the Steam container runtime), would have exactly the same issues as in the Steam container runtime for essentially the same reasons. That's why SDL detects both.

Would I lose anything important by switching all my builds to udev=no?

The main thing that you get from udev, beyond what you can get from /dev and /sys, is that udev rules can mark devices with metadata like ID_INPUT_JOYSTICK and ID_INPUT_ACCELEROMETER according to a heuristic and/or a database of known devices. When accessing devices directly, you don't get access to that information, so either game, engine or library code needs to implement a heuristic to figure out what each device is, so that you won't accidentally treat an accelerometer/gyro as a joystick and move the player character around when the device is tilted. I would personally recommend SDL's approach: use libudev when running directly on the host system, or access /dev and /sys directly when a container is detected.

I have some merge requests open in SDL to improve its heuristic. If Godot isn't using SDL, then it might be necessary to track changes like those and apply the equivalent in Godot.

(PS: I haven't got much further with Cassette Beasts than the point the demo ended at, but I'm enjoying it and will be recommending it to friends :-)

@smcv
Copy link

smcv commented May 10, 2023

falling back to parsing /dev/input/ manually otherwise

The key thing here is not just parsing /dev/input and /sys, but also using inotify to ask the kernel to wake you up when a new input device appears, again like SDL does. (Or you could poll /dev/input every n seconds, but getting into the habit of using event-based interfaces like inotify where possible is better for CPU-efficiency and battery life.)

@smcv
Copy link

smcv commented May 10, 2023

if you're relying on udev for device enumeration, then controllers that are already there at startup (in particular the built-in controls) will often work

Note that because udev doesn't guarantee compatibility between one version of udevd and a different version of libudev, this cannot actually be guaranteed. In practice it usually works now, so the Steam container runtime doesn't go out of its way to break this interface; but we can't be confident that in 2025 or 2030 it will still work.

I've been thinking about maybe adding a "strict mode" to the Steam container runtime, which would intentionally break as many as possible of the compatibility interfaces that we try to keep working even though they're unsupported/unsupportable, but I'm not sure how well that would actually work in this case.

@akien-mga
Copy link
Member

akien-mga commented May 10, 2023

Thanks for your detailed input, that's very helpful! We'll definitely have to go with a SDL like approach (or give up and integrate SDL, but we try to keep our thirdparty dependencies as lean as possible).

The current non-udev fallback code indeed polls /dev/input every second currently:
https://github.com/godotengine/godot/blob/master/platform/linuxbsd/joypad_linux.cpp#L214-L235

And then we have some barebones checks to validate what may or may not be a joystick:
https://github.com/godotengine/godot/blob/master/platform/linuxbsd/joypad_linux.cpp#L323-L386

It's relatively old code which has been improved a bit over the years but still has some issues (#59412). Things mostly work, until they don't as seen here :)

When sniper becomes available on a self-service basis, I suspect that the developers of games based on open source engines like Godot will want to start targeting that preferentially, with binaries built in a sniper container.

As a side note, to ensure maximum portability in Godot, we typically link all our thirdparty dependencies statically, aside from the ones which are too close to the OS, which we instead dlopen (and have fallback code when missing), such as X11, pulseaudio, alsa, dbus, udev.

So Godot's requirements on the host system are fairly low, and in my experience Godot games don't require the Steam Linux Runtime at all:

$ ldd /media/data/Games/Steam/steamapps/common/Cassette\ Beasts/CassetteBeasts.x86_64 
        linux-vdso.so.1 (0x00007ffd275e3000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f0f1eeb9000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f0f1f0c1000)
        libXcursor.so.1 => /lib64/libXcursor.so.1 (0x00007f0f1eead000)
        libXinerama.so.1 => /lib64/libXinerama.so.1 (0x00007f0f1eea8000)
        libXext.so.6 => /lib64/libXext.so.6 (0x00007f0f1ee94000)
        libXrandr.so.2 => /lib64/libXrandr.so.2 (0x00007f0f1ee87000)
        libXrender.so.1 => /lib64/libXrender.so.1 (0x00007f0f1ee79000)
        libX11.so.6 => /lib64/libX11.so.6 (0x00007f0f1ed3a000)
        libXi.so.6 => /lib64/libXi.so.6 (0x00007f0f1ed27000)
        libGL.so.1 => /lib64/libGL.so.1 (0x00007f0f1eca1000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f0f1ec9c000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f0f1ec97000)
        libsteam_api.so => not found
        libm.so.6 => /lib64/libm.so.6 (0x00007f0f1ebb9000)
        libXfixes.so.3 => /lib64/libXfixes.so.3 (0x00007f0f1ebb1000)
        libxcb.so.1 => /lib64/libxcb.so.1 (0x00007f0f1eb8a000)
        libGLdispatch.so.0 => /lib64/libGLdispatch.so.0 (0x00007f0f1ead1000)
        libGLX.so.0 => /lib64/libGLX.so.0 (0x00007f0f1ea9b000)
        libXau.so.6 => /lib64/libXau.so.6 (0x00007f0f1ea96000)
        libXdmcp.so.6 => /lib64/libXdmcp.so.6 (0x00007f0f1ea8e000)

With Godot 4 we even load X11, GL, or Vulkan dynamically (and soon Wayland), so the dependencies are very lean:

$ ldd ~/Projects/godot/stable/4.0/Godot_v4.0.2-stable_linux.x86_64 
        linux-vdso.so.1 (0x00007ffe587f9000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f1e56b79000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f1e56b74000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f1e56a98000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f1e568c6000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f1e56bb4000)

So those binaries should be fairly portable, whether running in Steam or standalone (and users typically don't build them against the Steam Runtime, but just use our prebuilt portable binaries)... At least until glibc's next soname change :P

Note that because udev doesn't guarantee compatibility between one version of udevd and a different version of libudev, this cannot actually be guaranteed. In practice it usually works now, so the Steam container runtime doesn't go out of its way to break this interface; but we can't be confident that in 2025 or 2030 it will still work.

Yeah that's where for Godot specifically, not using libudev from the Steam Runtime but dlopen'ing the one from the host OS which would match udevd should hopefully work better.

@smcv
Copy link

smcv commented May 10, 2023

This duplicated Device 0

I think this is part of Steam Input's support for remapping controllers, so that users can tell Steam to alter how controller data is presented to the game. Steam tries to tell the game "ignore device x, use device y instead", but the way it communicates that information is primarily designed for SDL (the SDL_GAMECONTROLLER_IGNORE_DEVICES and SDL_GAMECONTROLLERCONFIG environment variables). If Godot doesn't use SDL, it might be a good idea to look at those anyway.

@akien-mga
Copy link
Member

This duplicated Device 0

I think this is part of Steam Input's support for remapping controllers, so that users can tell Steam to alter how controller data is presented to the game. Steam tries to tell the game "ignore device x, use device y instead", but the way it communicates that information is primarily designed for SDL (the SDL_GAMECONTROLLER_IGNORE_DEVICES and SDL_GAMECONTROLLERCONFIG environment variables). If Godot doesn't use SDL, it might be a good idea to look at those anyway.

We parse SDL_GAMECONTROLLERCONFIG (and use the same mapping format as SDL does), but we're not checking SDL_GAMECONTROLLER_IGNORE_DEVICES. Thanks for the hint, I'll look into this.

@smcv
Copy link

smcv commented May 10, 2023

we typically link all our thirdparty dependencies statically, aside from the ones which are too close to the OS, which we instead dlopen (and have fallback code when missing), such as X11, pulseaudio, alsa, dbus, udev

That's fine up to a point, but you do need to make some assumptions about the versions of those libraries that are available, and one of the purposes of the Steam Runtime (both LD_LIBRARY_PATH and container) is to guarantee some minimum versions of libraries like those that you can count on having.

Of course this is "a simple matter of programming", and you could dlsym() for individual symbols and have fallback code paths for if each one is missing - but that's a lot of code that will end up being very rarely-tested, and as we have learned from bitter experience, untested code doesn't actually work.

So those binaries should be fairly portable, whether running in Steam or standalone (and users typically don't build them against the Steam Runtime, but just use our prebuilt portable binaries)

What you ship is between you and game developers, but I should note here for the record that Valve cannot really provide support for Steam game binaries that were not built in the Steam Runtime environment, beyond "recompile in the supported environment and try again". If they happen to work by coincidence, great, but the Steam Runtime is our only supportable environment. We have to pick something to align on, and the Steam Runtime is it; Linux distributions don't have an agreed-on cross-distro baseline ABI (LSB tried to be this, but basically failed) so Valve/Steam is filling that gap by providing one.

scout-on-soldier is basically Debian 10, with selected upgrades (for key libraries like SDL and Vulkan) and a few unavoidable downgrades (for legacy ABI compatibility in e.g. libcurl), while sniper is basically Debian 11 with selected upgrades.

I'm hoping that over time we can get "most" actively-maintained games to be 64-bit binaries on sniper, to escape from the legacy ABI baggage seen in scout (which we need to keep around essentially forever for the long tail of older games, but it's more than 10 years old now, so it's increasingly difficult to do anything useful beyond preserving it in amber on an as-is basis). If you're developing on a typical semi-modern OS like Debian, Ubuntu or Fedora, then sniper is going to be the most similar to that.

for Godot specifically, not using libudev from the Steam Runtime but dlopen'ing the one from the host OS which would match udevd should hopefully work better

Sorry, we will often be using the host's libudev in practice, but we can never guarantee that. If the host OS is relatively old, so that the container runtime is strictly newer (for example a Debian 10 LTS or Ubuntu 18.04 LTS host OS, running the Debian-11-based sniper container) then there is a non-negotiable technical constraint: we must use the container runtime's libudev in preference to the host OS's libudev, because the host OS's libudev could be missing symbols that libudev-dependent libraries in our container environment require in order to load correctly.

Whether you're using dlopen or "ordinary linking" doesn't matter a whole lot here: either way, there can only be one that comes first in the runtime linker's search path (and if it's the wrong one, that will often make games not start at all). Even if you ignore the search path and dlopen by absolute path, because of the fine details of how ELF symbol resolution is done, you might not get symbols from the object you expected to get them from (the more I work on the Steam Runtime, the more I dislike the ability to interpose symbols).

we have some barebones checks to validate what may or may not be a joystick

I'm gradually collecting evdev data for a selection of increasingly weird joysticks and other game controllers to use as test data, so at some point I'll try to plug the equivalent of your heuristic into that and report issues for any devices in my test data set that seem like the wrong answer (as I've started to do for SDL).

@akien-mga
Copy link
Member

I really appreciate the input! And indeed I've been following your work on the Steam container runtimes and well... I really value that work and wouldn't want to have to do it myself :D

The approach we take for Godot binaries to maximize compatibility is definitely less reliable than the Steam container runtimes, and I wouldn't guarantee it to work 10+ years from now. But so far it's showing good results where Godot binaries typically run on anything with decently up-to-date GL and Vulkan drivers.

For bigger projects using Godot wanting to maximize their compatibility on Steam, building Godot manually against the Steam container runtime is definitely a good option.

Our goal on the Godot side is to make shipping Linux games easy, and for most indie developers making portable Linux builds against a given runtime is far from trivial. The lack of a baseline Linux ABI really doesn't help us to democratize Linux as an easy publishing target, but so far our "one click deploy and it Just Works™" approach works fairly decently.

@akien-mga
Copy link
Member

#76961 should fix this for 4.x (4.0.3 and 4.1), and #76962 for 3.x (3.5.3 and 3.6).
I tested the 3.x version successfully with Cassette Beasts, wrote some details in #76962.

We parse SDL_GAMECONTROLLERCONFIG (and use the same mapping format as SDL does), but we're not checking SDL_GAMECONTROLLER_IGNORE_DEVICES. Thanks for the hint, I'll look into this.

I still plan to look into this for another PR.

akien-mga added a commit to akien-mga/godot that referenced this issue May 12, 2023
udev doesn't work in sandboxes, notably the new Steam container runtime
as found notably on the Steam Deck, and in Flatpak/Snap packages.

Like SDL does, when we detect such a containerized environment, we fall
back to parsing `/dev/input` directly.
See smcv's comments in godotengine#76879 for details.

Fixes godotengine#76879.

(cherry picked from commit 788cb74)
@akien-mga akien-mga added this to the 4.1 milestone May 12, 2023
akien-mga added a commit to akien-mga/godot that referenced this issue May 12, 2023
udev doesn't work in sandboxes, notably the new Steam container runtime
as found notably on the Steam Deck, and in Flatpak/Snap packages.

Like SDL does, when we detect such a containerized environment, we fall
back to parsing `/dev/input` directly.
See smcv's comments in godotengine#76879 for details.

Fixes godotengine#76879.

(cherry picked from commit 788cb74)
@Eoin-ONeill-Yokai
Copy link
Contributor

Eoin-ONeill-Yokai commented May 15, 2023

We parse SDL_GAMECONTROLLERCONFIG (and use the same mapping format as SDL does), but we're not checking SDL_GAMECONTROLLER_IGNORE_DEVICES. Thanks for the hint, I'll look into this.

@akien-mga I think that my merge request #76045 will solve this issue as it adds controller ignore behavior. Just might want to test with that merge request applied.

BTW there's a general bug in the SteamOS builds as of today that causes double inputs still when paired with an Xbox Series X controller even with device ignoring added that I believe valve is working on -- My presumption is that valve is doing some virtual controller shenanigans to trick the first bluetooth controller connected to echo commands as the deck controller itself so that the bluetooth controller can act as player one in certain games but have forgotten to pass device ignore flags in the environment variable. This is present even in some other AAA games and can be worked around by disabling steam input (for now, valve should fix this eventually.)

@akien-mga
Copy link
Member

akien-mga commented May 15, 2023

We parse SDL_GAMECONTROLLERCONFIG (and use the same mapping format as SDL does), but we're not checking SDL_GAMECONTROLLER_IGNORE_DEVICES. Thanks for the hint, I'll look into this.

@akien-mga I think that my merge request #76045 will solve this issue as it adds controller ignore behavior. Just might want to test with that merge request applied.

Oh that's amazing! I'll try it out asap.

BTW there's a general bug in the SteamOS builds as of today that causes double inputs still when paired with an Xbox Series X controller even with device ignoring added that I believe valve is working on -- My presumption is that valve is doing some virtual controller shenanigans to trick the first bluetooth controller connected to echo commands as the deck controller itself so that the bluetooth controller can act as player one in certain games but have forgotten to pass device ignore flags in the environment variable. This is present even in some other AAA games and can be worked around by disabling steam input (for now, valve should fix this eventually.)

Yeah I was hoping that this would be a case of Steam registering a new virtual input via SDL_GAMECONTROLLERCONFIG while excluding the original physical controller via SDL_GAMECONTROLLER_IGNORE_DEVICES which we failed to honor. But if you still reproduce the bug with your PR implementing the latter it's more complex than I presumed.

Is there an upstream bug report about this? If it happens also in non Godot games that's indeed pretty relevant for Valve to look into.

@Eoin-ONeill-Yokai
Copy link
Contributor

Eoin-ONeill-Yokai commented May 15, 2023

Is there an upstream bug report about this? If it happens also in non Godot games that's indeed pretty relevant for Valve to look into.

I could only find a pretty lengthy thread on Steam forums about this when I was looking it up last, as I was confused to why it was working through my desktop steam client w/ steam input but uniquely not on the Steam Deck. However, I can't find it right now -- I'll comb through my laptop history to see if I can find it again.

What I do know is that the existing MR fixes this bug when launching a game through steam that has steam input enabled and also gives preferential treatment to the users desired keybinds (as in, it prefers the steam input rebindings first and foremost, and ignores the original hardware.) There might be ways to work around this issue if we create a work around for STEAM_DECK=1, but I haven't found a clean solution yet. I'll keep you updated.

edit: I didn't find the exact thread I saw but I found this thread which seems to be a similar unresolved issue occurring on multiple (non-godot) games. I think Valve will probably fix it once they add proper controller "order" reassignment, as I think their current external controller support is a bit of a band-aid to the fact that the deck controller is always considered the "first player" by order at which the controllers are connected. The problem is that Valve can be kind of hard to know what they plan with regards to their roadmap, so it might be worth me making a thread on the bugs section to highlight this particular issue (or perhaps bring it up with people of interest via direct email.)

@smcv
Copy link

smcv commented May 16, 2023

BTW there's a general bug in the SteamOS builds as of today that causes double inputs still when paired with an Xbox Series X controller even with device ignoring added

Please do report this, especially if it affects non-Godot engines too (particularly anything SDL-based, since that's the platform library that Valve tends to treat as a reference implementation). I believe the issue tracker is https://github.com/ValveSoftware/SteamOS/issues for Steam Deck / SteamOS specifics, or https://github.com/ValveSoftware/steam-for-linux/issues for Steam client issues that are reproducible on ordinary desktop OSs (Debian, Fedora, Arch and so on).

I don't actually have a Deck myself, so I won't be able to reproduce this or follow up on it if it's Deck-specific.

@smcv
Copy link

smcv commented May 16, 2023

it prefers the steam input rebindings first and foremost, and ignores the original hardware

I'm not a Valve or Steam Input developer, but I believe this is how Valve want games/engines/middleware to deal with Steam Input legacy mode bindings.

(What they would ideally like games to do is the action-based API, where the game uses the Steamworks API to tell the Steam Input layer what "actions" the game has, in terms of game-specific abstract verbs like "jump" and "talk to NPC" rather than game controller buttons like A and X, and then receive events from Steam Input in terms of those abstract game-specific actions, with the player able to remap those abstract actions to a button of their choice. But I suspect that's probably something that can only usefully be implemented per-game, and difficult to do in a generic game engine that can't know what gameplay mechanics the game will have.)

akien-mga added a commit to akien-mga/godot that referenced this issue Aug 18, 2023
udev doesn't work in sandboxes, notably the new Steam container runtime
as found notably on the Steam Deck, and in Flatpak/Snap packages.

Like SDL does, when we detect such a containerized environment, we fall
back to parsing `/dev/input` directly.
See smcv's comments in godotengine#76879 for details.

Fixes godotengine#76879.

(cherry picked from commit 788cb74)
(cherry picked from commit 8a23fa4)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants