Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Qpadbridge

A free, open-source virtual gamepad for cloud-gaming pages in Chrome — Xbox Remote Play / xCloud, GeForce NOW, Amazon Luna. No physical controller needed. The project has two goals:

  1. Manual control — a full on-screen controller (draggable analog sticks, every button clickable, touch and mouse) for debugging and for playing cloud streams on the go with no hardware. The free answer to the paid virtual-gamepad extensions on the Chrome Web Store.
  2. A programmable WebSocket interface — drive the same controller from any language, for accessibility projects (map whatever input device you can use to a controller the game accepts) and cool home projects: bots, agents, custom hardware.
                                     Chrome
   MANUAL  🎮 on-screen pad ───────▶ ┌──────────────────────────────────┐
           (touch / mouse)           │ Qpadbridge extension             │
                                     │  overrides navigator.getGamepads │
   PROGRAMMATIC (any language)       │  → page sees a real controller   │
┌─────────────────────────┐   JSON   │                                  │
│  WebSocket server       │ ───────▶ │                                  │
│  (your bot / script /   │ ◀─────── │                                  │
│   custom input device)  │  rumble  └──────────────────────────────────┘
└─────────────────────────┘

Both paths feed input through the same native Gamepad API path a physical controller uses — so the stream never drops or ignores it, and you get full analog sticks and triggers, not just digital keys like keyboard-remapper extensions give you.

Why

  • Play anywhere — a Chromebook, a borrowed laptop, a touchscreen: open your stream, tap 🎮, play.
  • Debugging — poke any Gamepad API page by hand and watch how it reacts.
  • Accessibility — map any input device you can use (a switch, a head-tracker, a MIDI pedal, your phone) to a controller the game accepts.
  • Bots & agents — build AI that plays real console games through Remote Play: screenshot → decide → send controller input. (Qpadbridge was extracted from personal projects for playing Xbox remotely.)
  • Automation — script repetitive single-player grinds on your own console.

Install

  1. Clone this repo.
  2. Chrome → chrome://extensions → enable Developer modeLoad unpacked → select the extension/ folder.
  3. Open a matched page (e.g. xbox.com/play with your console or Game Pass). A small Qpadbridge pill appears bottom-right: red dot = no program connected, green = connected, yellow flash = input arriving.

To use it on another site that reads the Gamepad API, add the URL to matches in extension/manifest.json and reload the extension.

Manual mode (on-screen controller)

Click the 🎮 on the status pill to toggle the on-screen pad. You get the whole controller: two draggable analog sticks (full range, not just 8-way), d-pad, A/B/X/Y, bumpers and triggers, stick clicks (LS/RS), View ⧉, Menu ☰, and Guide ⌂. Works with touch (multi-touch: hold a stick while pressing buttons) and mouse. The pad only captures input on its controls — the stream between them stays clickable — and its visibility persists across reloads.

Manual mode needs no server running; the WebSocket side is entirely optional. When both are active they merge into the same controller state, which makes a nice debugging trick: pause your bot, take over by hand, resume.

Accessibility options

Tap the button at the right end of the pad's center strip to open the accessibility drawer — five toggles, tucked away since they're not always needed. Every setting persists across reloads and can also be set over WebSocket via the pad command; when the drawer is closed with a mode still active, the ♿ button glows yellow so active state is never invisible.

  • ⚡ Flick buttons — adds two arrow clusters that fire one-tap calibrated stick flicks (160 ms full deflection, same as the flick command). Precise menu/tile navigation with single taps instead of drag gestures.
  • 🔁 Turbo — while a button is held it auto-repeats (~8 presses/sec) instead of holding. Holding a flick arrow repeats the flick; turbo applies to keyboard keys too.
  • 📌 Latch — tap locks a button down, tap again releases it. For sustained inputs (hold-to-accelerate, hold-to-aim) without needing a sustained press. Combine with turbo for tap-on/tap-off auto-fire.
  • ⌨️ Keyboard — play on the keyboard. Defaults: WASD left stick, IJKL right stick (diagonals by combining keys), arrows d-pad, Space A, F B, E X, R Y, Q/T LB/RB, 1/2 LT/RT, 3/4 LS/RS, Backspace View, Enter Menu, G Guide, Esc exits. Remap anything by storing JSON at localStorage["qpadbridge.keymap"] (KeyboardEvent.code["btn", index] or ["lstick"|"rstick", dx, dy]).
  • 🎯 One-switch scanning — for single-input use: control clusters highlight in turn; your one switch (a tap anywhere on the stream, or Space/Enter) selects the highlighted cluster, then the highlighted button inside it. Fires a normal press — or a locked hold if latch is also on. Dwell time defaults to 1.1 s; tune via localStorage["qpadbridge.scanms"]. Falls back to cluster level after two idle loops; Esc exits.

Turning latch off, hiding the pad, or any reset releases everything — no input is ever left stranded pressed.

Quick start (Python)

pip install websockets
cd examples && python demo.py     # then open xbox.com/play
import asyncio
from qpadbridge import Qpadbridge

async def main():
    async with Qpadbridge() as pad:        # ws://localhost:8765
        await pad.wait_connected()
        await pad.press(Qpadbridge.A)              # tap A
        await pad.hold(Qpadbridge.RT, value=0.6)   # analog trigger
        await pad.stick("left", x=0, y=-1, ms=500)  # forward half a second
        await pad.flick("up")                     # right-stick flick

asyncio.run(main())

Node example: examples/server.mjs. Any WebSocket server in any language works — the protocol is a handful of JSON messages.

Testing locally

The repo ships a Gamepad API tester so you can verify everything without a console or cloud-gaming account (http://localhost/* is in the extension's matches for exactly this):

cd test && python3 -m http.server 8000    # then open http://localhost:8000

The page reads navigator.getGamepads() every frame and shows live stick positions and all 17 button values — poke the manual pad or run examples/demo.py against it and watch the state change. It also fires one test rumble so you can confirm the game→server haptics channel.

Protocol

Your program is the WebSocket server (default ws://localhost:8765 — a web page can't listen for connections, so the extension dials out to you). Messages are JSON objects with a type:

→ to extension fields effect
press button, ms=120, value=1 press a button, auto-release after ms
hold / release button, (value) press until released; value<1 = analog (triggers)
stick stick (left/right), x, y ∈ [-1,1], ms set stick; auto-center after ms, or hold if omitted
flick dir (up/down/left/right), stick=right, ms=160 quick directional stick flick
state axes [lx,ly,rx,ry], buttons [17 × 0..1] absolute state — stream this at frame rate for full control
reset everything to neutral
overlay show show/hide the status pill
pad show, flicks, turbo, latch, keys, scan show/hide the manual controller / set its accessibility options
ping replies pong
← from extension meaning
hello a page connected (page, version)
rumble the game played a haptic effect (params) — observable game feedback
pong ping reply

Standard-mapping button indices: 0 A · 1 B · 2 X · 3 Y · 4 LB · 5 RB · 6 LT · 7 RT · 8 Back/View · 9 Start/Menu · 10 LS · 11 RS · 12–15 d-pad up/down/left/right · 16 Guide.

If a connected program drops, the extension resets all input to neutral and retries every second — a crashed bot never leaves a stick pinned. (Failed retries while no server is running don't touch the state, so manual mode is unaffected.)

Scope & fair play

This tool is for your own console and account: accessibility, automation of single-player games, and AI/agent research. Don't use it to automate multiplayer or ranked play — that breaks platform rules and ruins games for other people, and platform holders can ban accounts for it.

License

MIT

About

Free, open-source virtual gamepad for cloud-gaming pages (Xbox Remote Play/xCloud, GeForce NOW, Luna): on-screen touch controller with accessibility modes + a WebSocket API to drive it from any language

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages