docs(clients/pads): say that an X-Box virtual pad has nowhere to put motion

G17's motion half. The docs described what the CLIENT sends and stopped there, which
made a promise the host does not always keep.

The support matrix said a desktop client forwards motion from any pad SDL exposes a gyro
on "and the host injects it into the matching virtual pad". The first clause is true; the
second is only true when the virtual pad has a motion plane. The X-Box 360 and One
backends do not — no gyro in their HID contract — so the host parses every sample and
discards it. That is where *Automatic* lands anything it does not recognise as Sony or
Valve, an 8BitDo with a perfectly good gyro included, and where a Switch Pro lands on a
Windows host with no `hid-nintendo` backend to fold it into.

A reader following the old text would conclude their gyro was broken. The failure has no
other symptom: motion just does nothing.

So both pages now say what to do about it — pick a DualSense-class type — and the
client-settings page says it where the choice is actually made, next to the degrade
paragraph that explains why a session ends up on an X-Box pad in the first place.

The Deck's Steam-Input requirement moves out of Decky's settings blurb, which is the one
place a Deck user streaming FROM the Deck would never look. With Steam Input on, Steam
hands the app its own virtual X-Box pad, so no controller-type choice can help: there is
no gyro on the pad the client can see.

The picker help text now mentions motion on GTK and Android, which is where it was
missing — Windows already said it and Apple says it in its own words. One sentence, the
same sentence, so the four clients answer the question the same way.

This is the doc side of the on-screen notice that shipped earlier in this branch. The two
exist for the same reason and now agree: the client says it when it detects the case, the
docs say it when someone goes looking.

Not covered: the preset COUNTS in note 1 ("Android and the console home offer six …
Windows and Apple offer five") are still unverified against the four pickers, and the
Apple picker's missing Steam Deck entry is a code gap rather than a doc one. Both are
noted in the plan and left for their own change rather than guessed at here.

Gate: Linux CI image fmt + `clippy --locked --all-targets -D warnings` on
punktfunk-client-linux (the GTK string is compiled) plus the core crates and their tests;
Android `:app:compileDebugKotlin` + `:app:testDebugUnitTest`. Green.
This commit is contained in:
2026-08-07 20:11:28 +02:00
parent 1eab4b6626
commit 979ed8f426
4 changed files with 27 additions and 2 deletions
@@ -850,7 +850,8 @@ private fun ControllerSettings(s: Settings, update: (Settings) -> Unit, onOpenCo
field = "gamepad",
enabled = s.gamepadForwarding,
caption = "The virtual pad the host creates. Automatic matches your controller; " +
"every connected one is forwarded as its own player.",
"every connected one is forwarded as its own player. An X-Box type has no " +
"gyroscope, so pick a DualSense-class one if you want motion.",
) { g -> update(s.copy(gamepad = g)) }
SettingDropdown(
label = "Guide button",
+2 -1
View File
@@ -1575,7 +1575,8 @@ pub fn show_scoped(
&dialog,
inline,
"Gamepad type",
"The virtual pad on the host — Automatic matches your controller",
"The virtual pad on the host — Automatic matches your controller. An X-Box type has no \
gyroscope, so pick a DualSense-class one if you want motion.",
&[
"Automatic",
"Xbox 360",
+14
View File
@@ -189,6 +189,20 @@ explicit choice declares your choice — and the host builds each virtual pad fr
host has no backend for degrades to an Xbox 360 pad rather than failing: Xbox One on a Windows host,
for instance, or any Sony pad on a Linux host that can't open `/dev/uhid`.
That degrade is the one thing worth knowing about **motion**. An Xbox-class virtual pad has no
gyroscope in its HID contract, so a session that ends up on one throws every motion sample away —
your controller's gyro simply does nothing, which from the couch is indistinguishable from a broken
sensor. Automatic lands there for any controller punktfunk doesn't recognise as Sony or Valve (an
8BitDo with a gyro, say), and so does a Switch Pro streaming to a Windows host, which has no
Nintendo backend to build. **If you want motion, pick a DualSense-class type** — DualSense,
DualSense Edge, DualShock 4, Switch Pro or Steam Deck all carry a motion plane. The clients detect
this case and say so on-screen for a few seconds when it happens; the setting applies from the next
session, not the one you are in.
On a **Steam Deck as the client**, motion also needs Steam Input switched off for punktfunk — with
it on, Steam hands the app its own virtual Xbox pad, which has no gyro to forward no matter which
type you pick.
**Forwarded controller** (*Use controller* on Apple and the console home) — *default: Automatic*,
which forwards *every* connected controller, each as its own player, on Linux, Windows, Apple and the
console home. Pinning one restricts the session to that controller alone — single-player. The Android
+9
View File
@@ -450,6 +450,15 @@ macOS, iOS/iPadOS and tvOS. Android is one app, with Android TV being the same a
host injects it into the matching virtual pad; the Deck's trackpads ride the same touchpad
surface. On the Apple clients rich capture is gated to the DualSense/DualShock 4 family, so
other pads there really do get rumble only.
**But motion only lands if the virtual pad the host builds has somewhere to put it.** The Xbox
360 and Xbox One backends have no gyro in their HID contract, so a session that resolves to one
parses every motion sample and discards it. That is what *Automatic* does for any controller it
doesn't recognise as Sony or Valve — an 8BitDo with a perfectly good gyro included — and it is
also where a Switch Pro lands on a Windows host, which has no `hid-nintendo` backend to fold it
into. Set **Controller type** to a DualSense-class preset to get motion in those cases; the
clients now say so on-screen when they detect it, rather than leaving you to guess why tilting
does nothing. See [Gamepad type](/docs/client-settings#gamepad-type).
3. No desktop client sends pen input, even though the desktop hosts can inject it.
4. All three touch modes exist in the shared code and the picker is there, but nobody has confirmed
them on a Windows 2-in-1. Only meaningful on a touchscreen anyway.