Use your smartphone browser as a dual-stick joystick pad with face buttons and send inputs to a virtual controller on your PC.
- Left virtual stick for steering (X axis)
- Right virtual stick for throttle and brake (Y axis)
- Gamepad-style face buttons and shoulder buttons
- Full Xbox-style action set (face, shoulders, triggers, start/back, stick clicks, d-pad)
- Assetto Corsa drive profile curves
- Real-time WebSocket input streaming
- Output modes: Virtual Gamepad or Keyboard mapper
- Automatic host detection from page URL and server config endpoint
- Xbox and PlayStation virtual controller profiles
- Multi-joystick sessions (up to 4 simultaneous phone clients)
- Watchdog safety reset on connection/input timeout
- Mobile-first joystick dashboard UI
- server.py: Python host app (HTTP + WebSocket + vgamepad bridge)
- index.html: Mobile UI layout
- style.css: Dashboard styling
- app.js: Virtual stick, button, networking, and UI logic
- Windows PC (recommended for virtual gamepad support)
- Python 3.10+
- Smartphone connected to the same local network as the PC
- ViGEmBus driver (required by vgamepad for virtual controller output)
python -m pip install -r requirements.txtpython server.pyOn startup the server logs your local IP and ports:
- HTTP app: port 8000
- WebSocket: port 5005
If cert.pem and key.pem exist in the project root, it also starts:
- HTTPS app: port 8443
- Secure WebSocket: port 5443
Open on phone:
http://PC_IP:8000
Example:
http://192.168.1.10:8000
- Start server.py on your PC.
- Open the HTTP URL on your phone.
- Host IP auto-fills and app auto-attempts connect.
- If needed, edit IP manually and tap Connect.
- Use left stick for steering.
- Use right stick vertically:
- Up for gas
- Down for brake
- Pick profile: Xbox, PlayStation, or Assetto.
- Xbox: A/B/X/Y + LB/RB layout
- PS5: Cross/Circle/Square/Triangle + L1/R1 layout
- Assetto: Shift/handbrake/assist quick actions
- Pick output mode:
- Gamepad: virtual controller via vgamepad
- Keyboard: sends arrow keys (Left/Right/Up/Down) for games like older NFS titles
- Pick driving profile: Balanced or Assetto Corsa.
Use this when phone connects directly to your PC hotspot.
- Enable Windows Mobile Hotspot on PC.
- Connect phone to that hotspot.
- Start server.py.
- Open
http://PC_HOTSPOT_IP:8000once on phone. - App reuses detected host automatically on next launches.
Common hotspot IP on Windows is 192.168.137.1.
Use HTTPS mode when you want encrypted local-network traffic.
- Create local certificate files in project root:
cert.pemkey.pem
- Restart server.py.
- Open
https://PC_IP:8443on your phone. - Trust the certificate warning for local testing.
- Connect from the app as usual.
The app automatically switches to secure WebSocket (wss://) when opened over HTTPS.
No OpenSSL required. The script auto-falls back to Python generation and installs required package automatically.
One command (recommended):
powershell -ExecutionPolicy Bypass -File .\generate-certs.ps1Manual OpenSSL command:
openssl req -x509 -newkey rsa:2048 -sha256 -days 365 -nodes -keyout key.pem -out cert.pem -subj "/CN=JoystickLocal"Then restart server.py.
- Steering -> Left joystick X axis
- Gas -> Right trigger
- Brake -> Left trigger
Keyboard mapper mode:
- Steering left -> Left Arrow
- Steering right -> Right Arrow
- Gas -> Up Arrow
- Brake -> Down Arrow
Controller action buttons in app:
- South / East / West / North face buttons
- LB1 / RB1 shoulder buttons
- LB2 / RB2 trigger buttons
- Back and Start
- Left-stick click and Right-stick click
- D-pad Up / Down / Left / Right
Each connected phone gets its own virtual controller slot automatically (up to 4 active at the same time).
Client sends CSV packets over WebSocket:
steering,gas,brake- Example:
0.32,0.80,0.00
Profile switch packet:
P:xboxP:ps
- Sends only changed values to reduce network traffic
- Applies deadzone and curve shaping for smoother stick feel
- Intended for local Wi-Fi use (low-latency LAN)
If no input is received for about 10 seconds, the server watchdog resets controller state:
- Steering centered
- Gas released
- Brake released
Install dependencies again:
python -m pip install -r requirements.txt- Ensure ViGEmBus is installed properly.
- Restart server.py.
- Test with Xbox profile first.
- Try Output Mode = Keyboard for games that do not detect virtual gamepads.
- Run both server.py and the game with same privilege level (both normal user or both admin).
- Verify phone and PC are on same Wi-Fi
- Confirm Windows firewall allows Python on ports 8000 and 5005
- Use PC LAN IP, not
localhost - In hotspot mode, try
192.168.137.1
- Ensure you are touching inside the stick pads or button circles
- Reconnect from the app if packets seem delayed
- Keep phone and PC on the same Wi-Fi band when possible
This project is intended for trusted local networks only. It does not include authentication or encryption by default.