> For the complete documentation index, see [llms.txt](https://docs.kouch.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kouch.dev/docs/adr/0023-vigembus-second-target-for-rumble.md).

# 0023: An optional ViGEmBus rumble upgrade on Windows, using the driver's second pad type

* Status: accepted (the owner confirmed it on 2026-09-29: "yes, as an optional upgrade for a better experience in windows")
* Plan: `docs/RUMBLE_PLAN.md` (R2); extends `docs/VPAD_PLAN.md`
* Relaxes: ground rule 1 (no third-party console brand names), in one line of code only

## Context

A game's rumble can't get back to Kouch over DSU: no DSU client we checked has a rumble output. So the emulator has to rumble a pad it can see.

* **The default mode (`steam`, RUMBLE\_PLAN):** Steam's virtual pads carry the rumble with no driver. It covers players 1–4 only. After a reorder in a game, rumble keeps following the old order until the game restarts.
* **The upgrade (`vpad` on Windows):** Kouch opens its own virtual pad per seat and forwards each pad's rumble to that seat's real controller. It covers every seat, and a reorder takes effect at once.
  * The driver's standard target counts against the 4 XInput slots and competes with Steam's pads.
  * ViGEmBus has a second target type outside XInput, which avoids both limits.

That second target brings three problems:

1. The `vigem-client` crate names that target after a third-party console's pad, so ground rule 1 forbids the name in Kouch's code.
2. The crate doesn't expose that target's rumble notification. Without it, Kouch can't hear the emulator's rumble.
3. The emulator sees the device under that pad's brand name.

## Decision

* **The exception is one line.** `crates/kouch-vpad/src/vigem.rs` imports the crate's second-target type under a neutral alias: a single `use … as SecondTarget;` line. From there on, Kouch's code uses only `SecondTarget`.
  * `docs/brand-blocklist.txt` gets one `allow:` line for exactly that file and that term. The file is owner-reviewed, and this ADR is the owner's approval.
  * This is the second exception to ground rule 1 in code, after Steamworks identifiers inside `crates/kouch-steam/`.
  * Everything else stays brand-free: every other file, Kouch's docs, assets, UI strings, identifiers, comments and commit messages (the commit-msg hook still applies).
* **The rumble notification lives in a vendored, patched crate.** `vendor/vigem-client` is wired in through `[patch.crates-io]`, like `vendor/steamworks`. The patch adds the second target's rumble-notification IOCTL. Its `unsafe` stays inside that third-party crate; Kouch gains no new unsafe island, and ground rule 4's list is unchanged.
* **The device name** the emulator shows is the pad's brand name. It appears only in private test profiles under `profiles/` (the binding templates), which brand-lint skips. Before the repo goes public, those bindings are rewritten or removed (`docs/GO_PUBLIC_CHECKLIST.md` gains the item).
* **Opt-in, never fetched.**
  * Settings › Controllers shows whether the driver is present and has a switch; it's off by default.
  * Kouch never downloads or installs ViGEmBus. Settings says where to get it, in words, with no link to a download.
  * Without the driver, or with the switch off, the mode stays `steam`.
* **Kouch ignores its own virtual pads** as input: they never take a seat, never show on the connect screen, and never navigate.
* **The 8-pad check** (can 8 second-target pads be open at once) runs on the owner's PC with Kouch closed and the owner idle. Its result is recorded in `docs/EARLY_TESTS.md` row 16.

## Consequences

* A second brand term in code, confined to one line and one `allow:` rule. Any wider use needs a new ADR.
* **ViGEmBus is archived upstream.** The upgrade may stop working on a future Windows, and nobody fixes the driver. The default `steam` mode stays the supported path.
* **We maintain the patched crate**, and re-apply the patch on any version bump (tell the other agents first, as with any workspace dependency).
* While a game runs with the upgrade on, users see an extra virtual pad per seat in Windows and in the emulator. The profile binds it for rumble only, so it never doubles input.
* The Deck and Linux need none of this: uinput pads already carry rumble with no driver (VPAD\_PLAN V2).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kouch.dev/docs/adr/0023-vigembus-second-target-for-rumble.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
