From a button press to a virtual gamepad.
You don't have to read any of this to use Dish. It just works. But if you want to know what your input is doing between your thumb and the game, this is the whole trip: input, encryption, transport, injection, and the return path.
- 1
You press a button on Dish
Maybe it's a tap on Dish for Android's touch overlay. Maybe it's a DualSense L1 Bluetooth-paired to your phone and bridged through Dish. Either way Dish grabs the input event from the OS the moment it fires. Not at the next vsync, not on the next frame. Now.
- 2
Dish builds a 12-byte XUSB report
The controller state goes into Satellite's compact wire format: two bytes of buttons, one byte per trigger, two bytes per analog stick axis. Twelve bytes total. Binary-compatible with Windows' XINPUT report, so the receiver doesn't have to translate anything.
- 3
It encrypts the packet
Dish prepends a 4-byte session token and a 4-byte counter, then seals the payload with ChaCha20-Poly1305 IETF using the 32-byte symmetric key both ends derived from the X25519 key exchange at pair time. The counter doubles as nonce and as replay defence; the token is authenticated as AAD so it can't be tampered with.
- 4
It's sent over UDP
Dish opens one UDP socket on port 9876 and calls
sendtostraight from the input thread. No queue, no async runtime, no ring buffer. The packet is tagged DSCP EF (Expedited Forwarding, 0xB8), so any QoS-aware router or AP on your LAN jumps it ahead of bulk traffic. - 5
Satellite receives and verifies
On your Windows gaming PC, Satellite is parked on its UDP socket on a time-critical thread waiting. The instant a packet lands it's MAC-verified, decrypted, and checked against the highest counter we've already accepted on this connection. Anything stale, forged, or tampered is dropped silently, so your game never sees a corrupt input.
- 6
Satellite injects a virtual pad
Satellite hands the report to the ViGEmBus kernel driver in a single
DeviceIoControlcall. You choose per controller whether to plug in an Xbox 360 pad or a DualShock 4. DS4 gets the full surface: motion, touchpad fingers, lightbar, and battery, all reported back to the game. - 7
The game responds, and answers back
The game reads the new pad state on its next input poll, usually inside one frame at 60 fps. When the game writes rumble back, or paints the lightbar a new color, Satellite encrypts and ships
MSG_RUMBLEorMSG_LIGHTBARback to the right Dish, which actuates haptics and LED in your hand. Total finger-to-pixel latency: a handful of milliseconds plus whatever your monitor's frame time adds.
Pairing happens once
The first time a Dish meets a new Satellite, you tap "Generate PIN" in Satellite's tray menu or web UI. Satellite shows a 4-digit code that lives for 5 minutes. Dish posts its X25519 public key plus that PIN to https://<your-pc>:9443/api/pair. Satellite verifies the PIN, computes the shared secret, returns its public key, and both sides cache the resulting 32-byte symmetric key. From then on the pad reconnects silently. No PIN, no UI, no thinking.
"But what about Sunshine and Moonlight?"
Sunshine and Moonlight are still the gold standard for streaming video from your gaming PC to another screen, like your TV, a phone, or a Steam Deck. They include controller forwarding, but it assumes the controller and the screen live on the same device. Dish handles a different model:
- Decoupled input. Stream video to the TV with Moonlight, hold your phone as the controller. Satellite makes that feel native.
- Couch co-op. Multiple Dish clients pair to one Satellite, each with its own virtual gamepad, even when only one device is streaming the video.
- No video at all. Plenty of people use Dish to play their PC on the same monitor with their phone as a wireless gamepad. No streaming required.
The names nod at the same lineage. See why "Dish" and "Satellite".
Try it for yourself.
Five minutes from install to first input.
Download Dish