Turn your phone into a wireless game controller for your PC.
This project creates a browser-based controller that connects your phone to your laptop over the local Wi-Fi/LAN and translates touch controls into real keyboard and mouse input.
No internet or cloud service is required.
- ๐ฎ Virtual joystick for W/A/S/D
- ๐ฑ๏ธ Touch-based mouse/look control
- โ๏ธ Attack button โ left mouse click
- ๐๏ธ Use button โ right mouse click
- ๐ฆ Jump button โ Space
- ๐ Vertical scroll wheel
- โก WebSocket-only communication for low latency
- ๐ฑ Designed for mobile landscape mode
- ๐๏ธ Fully customizable controller layout
- ๐พ Layout settings saved locally on the phone
- ๐ง Adjustable look sensitivity
- ๐ Automatically releases held keys when the phone disconnects
- ๐ Works entirely over your local network
โโโโโโโโโโโโโโโโโโโโโโ
โ ๐ฑ Phone โ
โ โ
โ ๐ฎ Touch Controls โ
โโโโโโโโโโโฌโโโโโโโโโโโ
โ
โ WebSocket
โ Local Wi-Fi
โผ
โโโโโโโโโโโโโโโโโโโโโโ
โ ๐ป Laptop โ
โ โ
โ Node.js Server โ
โ โ โ
โ nut.js โ
โ โ โ
โ Keyboard / Mouse โ
โโโโโโโโโโโฌโโโโโโโโโโโ
โ
โผ
๐ฎ Game
The phone sends small control events to the Node.js server.
The server then converts those events into real operating-system keyboard and mouse inputs using @nut-tree-fork/nut-js.
- Node.js
- Express
- Socket.IO
- @nut-tree-fork/nut-js
- HTML
- CSS
- JavaScript
phone-controller/
โ
โโโ public/
โ โโโ index.html # Controller interface
โ โโโ style.css # UI styling
โ โโโ app.js # Touch controls & Socket.IO logic
โ
โโโ server.js # Node.js server & OS input handling
โโโ package.json
โโโ package-lock.json
โโโ README.md
- Node.js 18 or newer
- A laptop/PC
- A smartphone
- Both devices connected to the same Wi-Fi/LAN
Node.js 22+ is recommended.
Clone the repository:
git clone https://github.com/not-rajharsh/phone-controller.git
cd phone-controllerInstall dependencies:
npm installRun:
npm startThe server will display something similar to:
=== LAN Game Controller Server ===
Local: http://localhost:3000
Network (Wi-Fi): http://192.168.1.42:3000
- Connect your phone and laptop to the same Wi-Fi network.
- Start the server with
npm start. - Find the LAN address printed in the terminal.
- Open that address on your phone.
For example:
http://192.168.1.42:3000
- Rotate your phone into landscape mode.
- Open your game on the laptop.
- Make sure the game window has focus.
- Use your phone as the controller.
| Phone Control | PC Input |
|---|---|
| Joystick Up | W |
| Joystick Left | A |
| Joystick Down | S |
| Joystick Right | D |
| Jump | Space |
| Attack | Left Mouse Button |
| Use | Right Mouse Button |
| Look Pad | Mouse Movement |
| Scroll Wheel | Mouse Wheel |
The controller includes an editing mode that allows you to:
- Move controls
- Resize controls
- Change look sensitivity
- Enable/disable the scroll wheel
- Reset the layout
Your customized layout is stored in the phone's browser using:
localStorage
The layout is therefore preserved when you reopen the controller.
The project was designed specifically for responsive game controls.
Socket.IO is configured to use:
transports: ['websocket']instead of starting with HTTP long-polling.
Small controller packets don't benefit much from compression, so per-message compression is disabled.
Keyboard and mouse events are only sent when their state changes.
For example:
Touch joystick
โ
Direction changes
โ
key-down
โ
W pressed
The application doesn't continuously spam W packets every frame.
If the phone disconnects while holding a button, the server releases the corresponding keyboard/mouse inputs.
This prevents situations where a game continues receiving a stuck key after the phone loses connection.
For the best experience:
Router โโโ Ethernet โโโ Laptop
โ
โโโโโโโ Wi-Fi โโโโโ Phone
This reduces wireless jitter on the laptop side.
Prefer 5 GHz or 6 GHz instead of 2.4 GHz when possible.
Distance and obstacles can increase packet loss and latency.
Pause large downloads, uploads, or streaming on the same network while playing.
Power-saving features can sometimes introduce additional latency.
The joystick calculates direction based on where the user's thumb initially touches rather than requiring the thumb to land exactly in the center.
The controller uses different thresholds for engaging and releasing a direction.
This helps prevent rapid switching when the thumb is near a directional boundary.
The look pad sends movement deltas rather than absolute cursor positions:
Swipe โ ฮX, ฮY
โ
Node.js
โ
Current cursor
โ
New cursor position
Vertical swipes are converted into discrete mouse-wheel events rather than continuous scrolling.
Keyboard mappings are defined in:
server.js
The main mapping is:
const KEY_MAP = {
w: Key.W,
a: Key.A,
s: Key.S,
d: Key.D,
space: Key.Space,
};You can modify this mapping to change the keyboard controls.
Button actions can be customized through:
public/index.html
public/app.js
Works without additional accessibility permissions.
Node.js may require Accessibility permission.
Go to:
System Settings
โ Privacy & Security
โ Accessibility
and allow the terminal/Node process.
The project currently requires an X11 environment for OS-level input simulation.
Check:
- Both devices are on the same network.
- The server is running.
- You're using the laptop's LAN IP rather than
localhost. - Port
3000isn't blocked by your firewall.
Example:
http://192.168.1.42:3000
Make sure:
- The game window has focus.
- The Node.js process has the required OS permissions.
npm installcompleted successfully.
On Windows, you may need:
- Python
- Visual Studio Build Tools
- Desktop C++ workload
On Debian/Ubuntu:
sudo apt install build-essential libx11-dev libxtst-dev libpng-devSome ideas for future versions:
- ๐ฎ Multiple controller profiles
- ๐ฏ Game-specific layouts
- ๐ก Connection/latency indicator
- ๐ Optional pairing/authentication
- ๐จ Custom themes
- ๐ค Voice/chat controls
- ๐น๏ธ Analog joystick support
- ๐ฑ PWA installation
- ๐ Automatic device discovery
- ๐ Real-time latency statistics
Add your preferred license here.
Harsh Raj
Computer Science student interested in:
- Cybersecurity
- AI/ML
- AI-assisted problem solving
- Systems & networking
- Building practical projects
GitHub:
https://github.com/not-rajharsh