Control your Windows PC with the LG Magic Remote — point, click, scroll, and type from your couch.
Forked from Cathwyler/MagicRemoteService. Tested on LG C2 (webOS 25), LG C1 (webOS 6.0), Windows 10/11.
git clone https://github.com/roko-tech/MagicRemoteService.git
cd MagicRemoteService
install.bat
Run as Administrator. The installer handles everything:
- Installs all prerequisites automatically (Node.js, webOS CLI, Build Tools, .NET 4.7.2)
- Builds and registers the PC service
- Auto-detects your PC's IP, MAC, and subnet
- Deploys the TV app to your LG TV
- Adds firewall rules
Only prerequisite: Developer Mode enabled on your TV.
- Download from Releases and extract
- Install Node.js and run
npm install -g @webos-tools/cli - Register the service (admin command prompt):
sc create MagicRemoteService binPath= "C:\MagicRemoteService\MagicRemoteService.exe" start= auto net start MagicRemoteService netsh advfirewall firewall add rule name="MagicRemoteService" dir=in action=allow protocol=TCP localport=41230 netsh advfirewall firewall add rule name="MagicRemoteService Web" dir=in action=allow protocol=TCP localport=41231 - Run
MagicRemoteService.exe— configure TV in the Settings UI → click Install on TV - Open http://localhost:41231 to configure key bindings
| Action | How |
|---|---|
| Move cursor | Point and wave the Magic Remote |
| Left click | Short press the OK/wheel button |
| Right click | Long press the OK/wheel button |
| Scroll | Roll the scroll wheel (smooth momentum) |
| Arrow keys | Press the D-pad directions |
| Enter | Press OK |
| Escape | Press Back |
| Copy | Volume + |
| Paste | Volume - |
| Shutdown PC | Press Red button |
| Open Windows menu | Press Green button |
| Toggle TV keyboard | Press Blue button |
| Numbers 0-9 | Press number pad |
| Exit TV app | Hold Back button for 1 second |
All mappings are customizable via the web UI.
The remote's volume buttons stay with the TV while Windows plays through it (HDMI, DisplayPort, or S/PDIF, such as the TV or a soundbar on its eARC). While Windows plays on another device, such as headphones, they change the PC volume instead, and the TV app sets the TV volume back after each step. This works while the TV app shows the PC input.
Open http://localhost:41231 while the service is running.
Click any button on the visual LG remote to remap it:
- Mouse click — left, right, middle
- Keyboard key — Enter, Escape, F1-F12, A-Z, arrows, etc.
- Keyboard shortcut — Ctrl+C, Alt+Tab, Win+D, any combo
- Shell command — launch any program
- Special action — shutdown PC, toggle TV keyboard
- HDMI port — auto-detected at runtime, or select manually
- PC IP / MAC / Subnet — auto-detected from your network interfaces
- Cursor speed — adjustable from 0.1 (slow) to 5.0 (fast)
- Reinstall TV App — one-click deploy without command line: packages the TV app built into the service with the saved config, installs it on the default ares-cli device of the user signed in at the PC, and launches it
Some apps (like media players) use scroll for volume control. Add their process names to disable momentum scrolling — sends single steps instead.
Hover any button on the visual remote to see its current binding (e.g. "Green → Win" or "Red → Shutdown PC"). Green dots indicate custom (non-default) bindings.
A single button at the bottom of the config panel resets all buttons to their default bindings (with confirmation).
LG Magic Remote → TV App (webOS) → WebSocket → PC Service (Windows) → Mouse/Keyboard
gyroscope captures input port 41230 translates to controls your
buttons sends binary Win32 SendInput desktop
scroll wheel messages
Two processes on the PC:
- Service runs as SYSTEM — starts at boot, accepts network connections
- Client runs in your user session — injects mouse/keyboard input via SendInput
TV app configuration is stored in config.json — no JavaScript files are modified during installation. The HDMI port is auto-detected at runtime.
- Config injection —
config.jsonreplaces fragile sed/PowerShell string replacement - Auto-discovery — TV finds PC via SSDP, no manual IP entry needed
- Auto-detect HDMI — switches to the correct port automatically
- Web settings UI — visual remote configurator at localhost:41231
- Smooth scrolling — Mac-style momentum with per-app exclusions
- Non-blocking toasts — small pill notifications instead of full-screen dialogs
- CPU fixed — reduced from 20%+ to near 0% (timer + WebSocket spin fixes)
- Security hardened — buffer overflow protection, command injection blocking, XSS prevention, pipe access control, CSRF headers
- Connection state machine — prevents race conditions during connect/disconnect
- Node.js v22+ — polyfill for ares-cli compatibility
- Service keepalive — prevents webOS 25 from killing the TV service
- One-click install —
install.bathandles all prerequisites
- Tab — navigate between remote buttons
- Enter / Space — select focused button
- Enter in scroll exclusion input — add to list
| Problem | Solution |
|---|---|
| "Service is busy" or "not running" | Reboot TV, then relaunch the app |
| Pointer doesn't work but scroll does | Wave the remote at the TV to activate the gyroscope. It auto-retries every 3 seconds |
| "Failed to get sensor data [1003]" | Normal on webOS 25 — auto-retries in the background |
| TV can't find PC | Ensure same subnet, UDP multicast not blocked. Fall back to manual IP in config |
| Web UI won't load | Open http://localhost:41231 (not 41230). The PC service must be running |
| Settings UI says "ares not found" | Install Node.js and run npm install -g @webos-tools/cli |
| High CPU usage | Update to v2.2.0+ — fixes timer polling and WebSocket spin bugs |
| Home launcher pointer blocked | Expected in overlay mode — use D-pad to navigate the TV launcher |
| TV app shows after long delay | Normal on cold boot — webOS takes ~60s to initialize developer apps |
| Can't exit TV app | Press and hold the Back button for 1 second |
| Forgot what a button does | Hover it in the web UI — shows current binding |
git clone https://github.com/roko-tech/MagicRemoteService.git
cd MagicRemoteService
build.bat
Requires Visual Studio 2022 (or Build Tools) and .NET Framework 4.7.2.
- Device token auth — the TV presents a shared token (generated into
config.jsonat install) in the WebSocket URL; connections without the matching token are rejected, so other devices on your LAN can't drive the PC. The installer keeps the PC and TV tokens in sync; if you set a token, every TV must carry the same one — a PC-side token with an un-updated TV will silently reject that TV. Clear thetokenfield intv-config.json(next to the exe) to revert to open mode.- What the token protects against: blind LAN devices and malicious web pages (which can neither read it cross-origin nor sniff your wire). What it does not: the token is sent in cleartext over
ws://(no TLS), so a passive sniffer on your own network segment could capture and replay it. It raises the bar within a trusted LAN; it is not a substitute for one.
- What the token protects against: blind LAN devices and malicious web pages (which can neither read it cross-origin nor sniff your wire). What it does not: the token is sent in cleartext over
- Local network only — no encryption between TV and PC. Don't use on an untrusted network.
- Buffer overflow protection — WebSocket frame bounds checking (overflow-safe length validation)
- Command injection blocking — shell metacharacters rejected in key bindings (note: a command binding still runs the program you configure; the filter only blocks shell chaining)
- XSS prevention — user input sanitized in web UI
- Pipe access control — named pipe restricted to authenticated users
- CSRF protection — mutating POST requests are rejected server-side unless they carry the
X-Requested-Withheader (which cross-origin pages can't set without a CORS preflight). If you script the HTTP API directly, send that header on POSTs.
Don't enter passwords via the remote.
GPL-3.0 — see LICENSE