[PR #39] feat(joypad): add recreate_device() to rebuild a virtual device in place #42

Open
opened 2026-10-15 12:51:33 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/games-on-whales/inputtino/pull/39
Author: @JBailes
Created: 6/16/2026
Status: 🔄 Open

Base: stable ← Head: fix/recreate-device


📝 Commits (1)

  • 6f7cc0d feat(joypad): add recreate_device() to rebuild virtual device in place

📊 Changes

8 files changed (+173 additions, -7 deletions)

View changed files

📝 include/inputtino/input.hpp (+22 -0)
📝 src/uhid/include/uhid/protected_types.hpp (+6 -0)
📝 src/uhid/joypad_ps5.cpp (+42 -2)
📝 src/uinput/include/inputtino/protected_types.hpp (+14 -0)
📝 src/uinput/joypad_nintendo.cpp (+28 -1)
📝 src/uinput/joypad_ps.cpp (+28 -1)
📝 src/uinput/joypad_utils.hpp (+5 -2)
📝 src/uinput/joypad_xbox.cpp (+28 -1)

📄 Description

Problem

We share one virtual joypad between containers by mknod-ing the node and faking udev events, then rm-ing it on unplug. Removing the node doesn't close an fd another process already has open, so anything that opened the device keeps reading it. There's no way to evict that reader from outside short of destroying the device.

Change

Add Joypad::recreate_device(): tear the underlying device down (UI_DEV_DESTROY / UHID_DESTROY, which invalidates the stale fd) and build a fresh one in its place, keeping the object and its callbacks (rumble, LED, triggers) intact.

  • uinput (Xbox/Switch/PS) stash their DeviceDefinition and bump a per-state generation so the detached rumble listener on the old device exits on its own.
  • uhid DualSense keeps its report pump joinable (the move ctor now carries it) so it stops before the device it writes to is destroyed, then rebuilds from the stashed uhid definition with the same MAC so get_sys_nodes() matching stays stable. This also closes a latent race in the old destructor, which could reset the device while a detached pump was still writing.

Base class default is a no-op.

Used by Wolf to stop gamepad input leaking across lobby switches (games-on-whales/wolf#435).


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/games-on-whales/inputtino/pull/39 **Author:** [@JBailes](https://github.com/JBailes) **Created:** 6/16/2026 **Status:** 🔄 Open **Base:** `stable` ← **Head:** `fix/recreate-device` --- ### 📝 Commits (1) - [`6f7cc0d`](https://github.com/games-on-whales/inputtino/commit/6f7cc0df09bf849878b6f6fffac9b75716cbb094) feat(joypad): add recreate_device() to rebuild virtual device in place ### 📊 Changes **8 files changed** (+173 additions, -7 deletions) <details> <summary>View changed files</summary> 📝 `include/inputtino/input.hpp` (+22 -0) 📝 `src/uhid/include/uhid/protected_types.hpp` (+6 -0) 📝 `src/uhid/joypad_ps5.cpp` (+42 -2) 📝 `src/uinput/include/inputtino/protected_types.hpp` (+14 -0) 📝 `src/uinput/joypad_nintendo.cpp` (+28 -1) 📝 `src/uinput/joypad_ps.cpp` (+28 -1) 📝 `src/uinput/joypad_utils.hpp` (+5 -2) 📝 `src/uinput/joypad_xbox.cpp` (+28 -1) </details> ### 📄 Description ## Problem We share one virtual joypad between containers by mknod-ing the node and faking udev events, then rm-ing it on unplug. Removing the node doesn't close an fd another process already has open, so anything that opened the device keeps reading it. There's no way to evict that reader from outside short of destroying the device. ## Change Add `Joypad::recreate_device()`: tear the underlying device down (UI_DEV_DESTROY / UHID_DESTROY, which invalidates the stale fd) and build a fresh one in its place, keeping the object and its callbacks (rumble, LED, triggers) intact. - uinput (Xbox/Switch/PS) stash their `DeviceDefinition` and bump a per-state generation so the detached rumble listener on the old device exits on its own. - uhid DualSense keeps its report pump joinable (the move ctor now carries it) so it stops before the device it writes to is destroyed, then rebuilds from the stashed uhid definition with the same MAC so `get_sys_nodes()` matching stays stable. This also closes a latent race in the old destructor, which could reset the device while a detached pump was still writing. Base class default is a no-op. Used by Wolf to stop gamepad input leaking across lobby switches (games-on-whales/wolf#435). --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
games-on-whales/inputtino#42
No description provided.