[PR #327] ReversePuck Deck app: run without sudo, clearer touchscreen UI, and a Game Mode AppImage #288

Open
opened 2026-10-26 11:09:47 +00:00 by roman · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/safijari/openpuck/pull/327
Author: @MisterAnderson91
Created: 10/25/2026
Status: 🔄 Open

Base: main ← Head: reversepuck-deck-app-appimage


📝 Commits (2)

  • 7ddc806 ReversePuck app: run without sudo, hand the Deck pad back reliably, per-pad haptics, touchscreen UI
  • 0ad3c45 ReversePuck: Steam Deck app as an AppImage that runs from Game Mode, built by CI

📊 Changes

12 files changed (+705 additions, -64 deletions)

View changed files

➕ .github/workflows/reversepuck-appimage.yml (+101 -0)
📝 README.md (+1 -1)
📝 ReversePuck/README.md (+37 -13)
📝 ReversePuck/ReversePuck (+3 -2)
📝 ReversePuck/frame.py (+10 -0)
📝 ReversePuck/input_source.py (+106 -15)
📝 ReversePuck/openctrl.py (+26 -2)
➕ ReversePuck/packaging/AppRun (+11 -0)
➕ ReversePuck/packaging/build-appimage.sh (+162 -0)
➕ ReversePuck/packaging/make_icon.py (+53 -0)
➕ ReversePuck/packaging/reversepuck.desktop (+10 -0)
📝 ReversePuck/ui.py (+185 -31)

📄 Description

ReversePuck Deck app fixes and a one-file AppImage: the app runs without sudo ./setup.sh, reliably hands the Deck's controls back, plays trackpad haptics and has a clearer touchscreen UI; as an AppImage it launches from Game Mode with no uv or network.

One of three independent ReversePuck PRs (firmware fixes, pairing commands, Deck app + AppImage). They touch separate files and can be merged in any order. Trackpad haptics need the firmware fixes PR; with older firmware everything else works and the haptics just don't arrive.

Summary

  • 7ddc806 Deck app: no sudo, reliable hand-back, haptics, new touchscreen UI
  • 0ad3c45 The fixed Deck app as a standalone AppImage (no install needed) that runs from Game Mode, built by CI for every change

Commits in detail

1. ReversePuck app: run without sudo, hand the Deck pad back reliably, per-pad haptics, touchscreen UI (ReversePuck/*.py, launcher comment, README)
These apply to the existing ReversePuck (uv) script as well as the AppImage in commit 2.

  • No sudo: SteamOS's Steam udev rule already gives the session user every 28DE device, the dongle's CDC included, so setup.sh isn't needed.
  • Robustness:
    • Never pick the Deck pad's own CDC (28DE:1205, /dev/ttyACM0) as the dongle.
    • grab() fails loudly instead of forwarding a dead neutral pad.
    • Hand the pad back on SIGTERM/SIGHUP (Steam's "Exit game").
    • Re-attach pad interfaces a crashed run left detached.
    • Keep the pad out of lizard mode while forwarding, using hid-steam's heartbeat. Its watchdog otherwise turns lizard mode, and its own haptic ticks, back on within seconds.
  • Haptics: plays the firmware's new PULSE frames with the Deck's 0x8F pulse (the Deck ignores the 0xEB rumble).
  • Touchscreen UI:
    • Tiles fill the screen (one, or two columns), with the state as the headline ("slot 0 - available - tap to connect"), and the wording is connect/disconnect.
    • The log is a fixed 4-line box.
    • Screen timeout: when a forward's link comes up, the screen counts down 5 s and goes black; a tap keeps it on, and later taps toggle it. Hold still disconnects whether the screen is on or black.
    • Touches are taken from finger events only, since SDL also synthesises a mouse click for each.
  • Instructions: setup.sh is only needed off SteamOS.

2. ReversePuck: Steam Deck app as an AppImage that runs from Game Mode, built by CI (ReversePuck/packaging/, new workflow, READMEs)
Builds on commit 1: it packages that app, unchanged.

  • AppImage: ReversePuck/packaging/build-appimage.sh bundles a portable Python 3.12 with the manylinux wheels for pygame, pyserial and pyusb. It uses uruntime (pinned, SHA-256 checked) instead of the stock runtime: Steam starts Game Mode games with no_new_privs, which stops fusermount, and the stock runtime then just exits. uruntime falls back to extract-and-run.
  • CI: .github/workflows/reversepuck-appimage.yml builds the AppImage for every push/PR touching ReversePuck/ (an Actions artifact) and attaches it to releases.
  • READMEs: how to get and use the AppImage; the uv script stays the alternative.

Testing

Hardware: Steam Deck OLED with a ReversePuck (Pro Micro nRF52840), an OpenPuck on 0.9.51, and the host running Steam on macOS.

  • The AppImage launches from Game Mode with no launch options, and the pad is handed back on exit.
  • Trackpad haptics arrive within ~0.4 s of connecting and tick on the correct pad (with the firmware fixes PR).
  • The screen timeout and hold-to-disconnect were checked on the Deck and in a headless pygame test.
  • The AppImage workflow passes on this branch.

Not tested: the uv script from Game Mode, and hosts other than macOS.

🤖 Generated with Claude Code


🔄 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/safijari/openpuck/pull/327 **Author:** [@MisterAnderson91](https://github.com/MisterAnderson91) **Created:** 10/25/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `reversepuck-deck-app-appimage` --- ### 📝 Commits (2) - [`7ddc806`](https://github.com/safijari/openpuck/commit/7ddc806a3aff9d99f316b65db24ee22da829615a) ReversePuck app: run without sudo, hand the Deck pad back reliably, per-pad haptics, touchscreen UI - [`0ad3c45`](https://github.com/safijari/openpuck/commit/0ad3c45b20ffd814210f4fc30c8fd0d145e5f43a) ReversePuck: Steam Deck app as an AppImage that runs from Game Mode, built by CI ### 📊 Changes **12 files changed** (+705 additions, -64 deletions) <details> <summary>View changed files</summary> ➕ `.github/workflows/reversepuck-appimage.yml` (+101 -0) 📝 `README.md` (+1 -1) 📝 `ReversePuck/README.md` (+37 -13) 📝 `ReversePuck/ReversePuck` (+3 -2) 📝 `ReversePuck/frame.py` (+10 -0) 📝 `ReversePuck/input_source.py` (+106 -15) 📝 `ReversePuck/openctrl.py` (+26 -2) ➕ `ReversePuck/packaging/AppRun` (+11 -0) ➕ `ReversePuck/packaging/build-appimage.sh` (+162 -0) ➕ `ReversePuck/packaging/make_icon.py` (+53 -0) ➕ `ReversePuck/packaging/reversepuck.desktop` (+10 -0) 📝 `ReversePuck/ui.py` (+185 -31) </details> ### 📄 Description ReversePuck Deck app fixes and a one-file AppImage: the app runs without `sudo ./setup.sh`, reliably hands the Deck's controls back, plays trackpad haptics and has a clearer touchscreen UI; as an AppImage it launches from Game Mode with no `uv` or network. One of three independent ReversePuck PRs (firmware fixes, pairing commands, Deck app + AppImage). They touch separate files and can be merged in any order. Trackpad haptics need the firmware fixes PR; with older firmware everything else works and the haptics just don't arrive. ## Summary - 7ddc806 Deck app: no sudo, reliable hand-back, haptics, new touchscreen UI - 0ad3c45 The fixed Deck app as a standalone AppImage (no install needed) that runs from Game Mode, built by CI for every change ## Commits in detail **1. ReversePuck app: run without sudo, hand the Deck pad back reliably, per-pad haptics, touchscreen UI** (`ReversePuck/*.py`, launcher comment, README) These apply to the existing `ReversePuck` (`uv`) script as well as the AppImage in commit 2. - **No `sudo`:** SteamOS's Steam udev rule already gives the session user every `28DE` device, the dongle's CDC included, so `setup.sh` isn't needed. - **Robustness:** - Never pick the Deck pad's own CDC (`28DE:1205`, `/dev/ttyACM0`) as the dongle. - `grab()` fails loudly instead of forwarding a dead neutral pad. - Hand the pad back on SIGTERM/SIGHUP (Steam's "Exit game"). - Re-attach pad interfaces a crashed run left detached. - Keep the pad out of lizard mode while forwarding, using hid-steam's heartbeat. Its watchdog otherwise turns lizard mode, and its own haptic ticks, back on within seconds. - **Haptics:** plays the firmware's new `PULSE` frames with the Deck's `0x8F` pulse (the Deck ignores the `0xEB` rumble). - **Touchscreen UI:** - Tiles fill the screen (one, or two columns), with the state as the headline ("slot 0 - available - tap to connect"), and the wording is connect/disconnect. - The log is a fixed 4-line box. - Screen timeout: when a forward's link comes up, the screen counts down 5 s and goes black; a tap keeps it on, and later taps toggle it. Hold still disconnects whether the screen is on or black. - Touches are taken from finger events only, since SDL also synthesises a mouse click for each. - **Instructions:** `setup.sh` is only needed off SteamOS. **2. ReversePuck: Steam Deck app as an AppImage that runs from Game Mode, built by CI** (`ReversePuck/packaging/`, new workflow, READMEs) Builds on commit 1: it packages that app, unchanged. - **AppImage:** `ReversePuck/packaging/build-appimage.sh` bundles a portable Python 3.12 with the manylinux wheels for pygame, pyserial and pyusb. It uses uruntime (pinned, SHA-256 checked) instead of the stock runtime: Steam starts Game Mode games with `no_new_privs`, which stops `fusermount`, and the stock runtime then just exits. uruntime falls back to extract-and-run. - **CI:** `.github/workflows/reversepuck-appimage.yml` builds the AppImage for every push/PR touching `ReversePuck/` (an Actions artifact) and attaches it to releases. - **READMEs:** how to get and use the AppImage; the `uv` script stays the alternative. ## Testing Hardware: Steam Deck OLED with a ReversePuck (Pro Micro nRF52840), an OpenPuck on 0.9.51, and the host running Steam on macOS. - The AppImage launches from Game Mode with no launch options, and the pad is handed back on exit. - Trackpad haptics arrive within ~0.4 s of connecting and tick on the correct pad (with the firmware fixes PR). - The screen timeout and hold-to-disconnect were checked on the Deck and in a headless pygame test. - The AppImage workflow passes on this branch. Not tested: the `uv` script from Game Mode, and hosts other than macOS. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <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 labels
pull-request
wontfix
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
safijari/openpuck#288
No description provided.