netris icon indicating copy to clipboard operation
netris copied to clipboard

Controller Support

Open DatCaptainHorse opened this issue 10 months ago • 9 comments

We should have support for common game controllers.

DatCaptainHorse avatar Feb 20 '25 18:02 DatCaptainHorse

Controller Support Implementation Options

For Nestri - a Docker-based cloud gaming platform, we’re (internally) considering two approaches to handle controller input:

Option 1: In-Container Device Emulation (@danisla)

  • How it works: A program inside the container emulates virtual devices like /dev/eventX or /dev/jsX to mimic controller input.
  • Pros: Simple to implement, self-contained, and avoids host-level dependencies.
  • Cons: May face compatibility issues with games expecting direct hardware access or specific drivers.

Option 2: Host-Managed UInput Passthrough (@abeltramo)

  • How it works: A host-level program (outside the container) uses uinput to create virtual controllers, which are then passed into the container.
  • Pros: Better compatibility with games/controllers by leveraging Linux’s native input system.
  • Cons: Adds complexity (host setup, device mapping, permissions).

Key Trade-offs

  • Simplicity ➔ Option 1 is lightweight and easier to deploy.
  • Compatibility ➔ Option 2 aligns better with Linux input standards, future-proofing for diverse controllers.

Open Question: Given our scale (min. 3 containers/host) and Linux-only environment, should we prioritize rapid iteration (Option 1) or invest in long-term flexibility (Option 2)?

Would love to hear your take on this :D

cc @ehfd for more input :)

wanjohiryan avatar Mar 27 '25 00:03 wanjohiryan

I can't really compare the two since I haven't tried the other proposed solution, so I'm going to give you a different perspective.
Since your clients would be browsers, I'd start by identifying exactly what you can and can't do with joypads in that environment. Examples:

  • Can I access all types of joypads or are there limitations?
  • Does it work the same across browsers/OSes?
  • Is it possible to correctly identify what's being pressed? Ex: X on a PS pad is different than X on Xbox and X on Nintendo.
    • Would you be able to match any input device into another device on the server?
  • Can I detect when a device is plugged/unplugged?
  • Does it support multiple devices, and can I reliably map them when reconnecting?
  • Would "advanced" features be supported? Can I read acceleration and gyroscope events from joypads that support it? Can I trigger a rumble event when the server sends one? Can I distinguish a touchpad press on the joypad from a normal mouse input?

I'd say it's important to first define well what are the requirements and limitations client side before deep diving into the server, just my 2 cents 😉

ABeltramo avatar Mar 27 '25 04:03 ABeltramo

My take:

We still need multiple containers in a single node. Does Approach 2 have this ready right now?

On the host, if you can figure out which container intiated the uinput/uhid request and identify the subsequent /dev/input/event devices, then it's not too bad. The uinput-device-plugin (in Selkies) does this in Go. It still requires a dedicated service/root container running on the host to monitor all containers and all uinput/uhid events.

ehfd avatar Mar 27 '25 06:03 ehfd

Does Approach 2 have this ready right now?

In Wolf, we already support concurrently running multiple games across multiple containers with complete isolated inputs.

It's achieved with a combination of creating virtual devices on the host (uinput or uhid for more advanced features) and hotplugging them into the right container.
The result is that each container will only have access to the right /dev/input/event* (plus /dev/hidraw* for uhid) and will properly see them plugging/unplugging as they are attached/detached to the container.

ABeltramo avatar Mar 27 '25 20:03 ABeltramo

I'd say it's important to first define well what are the requirements and limitations client side before deep diving into the server, just my 2 cents 😉

You’re absolutely right – this are really good questions.

Browsers today restrict advanced controller features (gyro, vibration, device-specific mappings), which is why we’re prioritizing native apps later (PC, TV and mobile) for lower level access to devices on the client-side. We hope to even build custom controllers are on our someday damn! we need to update the roadmap.

Option 2 (@abeltramo) Makes Sense for the long term

  • Compatibility First: If we eventually want to support PS/Xbox/Nintendo nuances, vibration, or plug-and-play detection, Option 2’s host-managed approach aligns better with Linux’s native input stack.
  • Security/Scale Concerns: Managing devices across 3 containers/host is tricky.

We’d need:

  • Tight permission controls (udev rules, cgroups).
  • Static device mapping (--device=/dev/input/eventX flags).
  • Isolation (libinput or custom logic to avoid cross-container interference).

Let’s get practical, @Abeltramo could you share code/docs (links are alright) for:

  • How you create/passthrough uinput devices?
  • Handling hotplugging (e.g., a controller disconnects mid-game)?

@danisla / @ehfd: Does your in-container method support basic vibration?

Temporary Compromise? - This is more like a question rather than a conclusion😅 Since browsers only give us buttons/axes today, Option 1 might suffice short-term. But if Option 2’s overhead is manageable, it future-proofs us.

wanjohiryan avatar Mar 28 '25 01:03 wanjohiryan

Does your in-container method support basic vibration?

It's surely capable of it (including the web browser), but the code has to be added.

Note that with the web browser's Gamepad API doesn't have the advanced capabilities of DualSense, and the WebHID API should be used instead.

Our implementation is designed for Kubernetes clusters with no authority or privileges of the cluster (a user who has no control of the compute node, specifically like RunPod). We prioritize this condition over anything, including the gaming experience.

As long as live device provisioning into various running containers from the host is possible, it's an option to use Inputtino.

In conclusion, it's a matter of where you're 100% sure that you will continue to use VMs with full control to the Docker daemon, or you will use a service with only access to provisioning unprivileged containers through kubectl or similar.

ehfd avatar Mar 28 '25 03:03 ehfd

In conclusion, it's a matter of where you're 100% sure that you will continue to use VMs with full control to the Docker daemon, or you will use a service with only access to provisioning unprivileged containers through kubectl or similar.

Hmmm! Good point 🤔

wanjohiryan avatar Mar 28 '25 04:03 wanjohiryan

c62a22b552589353c90c7751f9f11a57c3dc980c adds initial support, with rumble and all.. gonna need to refine it before I consider this issue closed.

DatCaptainHorse avatar Oct 20 '25 08:10 DatCaptainHorse

d87a0b3 adds some fixes to multi-controller handling and better polling logic, should be much snappier now.

One remaining issue is with few specific games (i.e. Risk of Rain 2), they have weird controller support (native?) that doesn't seem to work yet with vimputti, I'm curious if new proton-cachyos-slr is lighter package, as they would offer PROTON_PREFER_SDL and PROTON_NO_STEAMINPUT variables which I reckon could be a quick workaround for time being 🤔

DatCaptainHorse avatar Nov 08 '25 11:11 DatCaptainHorse