Ultra-low-latency secondary display streaming between Windows machines with dedicated monitor standby.
Turn any spare Windows laptop into a high-refresh wireless or wired secondary monitor for your PC. Powered by DirectX DXGI Desktop Duplication and the Microsoft IddCx driver pipeline.
Most existing solutions for using a laptop as a secondary screen are either proprietary, laggy, bloated with background services, or require purchasing HDMI dummy plugs:
| Feature | MonitorLink | Spacedesk | Miracast ("Project to this PC") | Deskreen |
|---|---|---|---|---|
| Open Source | Yes (MIT) | No (Proprietary) | No (Windows only) | Yes (GPL-3.0) |
| Capture Pipeline | DirectX DXGI (60 FPS) | Virtual Display Driver | Miracast Wi-Fi Direct | Electron / WebRTC |
| Latency | < 15ms (Wi-Fi) / < 5ms (Wired) | ~30–50ms | Inconsistent (Stutters) | ~50–80ms |
| Setup Complexity | 1-Click Auto-Discovery | Multi-step installer | Frequent pairing failures | Web browser + QR code |
| Direct Cable Support | Yes (Gigabit Ethernet/USB) | Manual IP setup | No (Wi-Fi Direct only) | Local network only |
| Dedicated Standby | Yes (SetThreadExecutionState) |
No | Full desktop | Browser window |
| True Extended Desktop | Included IddCx Driver | Proprietary driver | Supported | Requires dummy plug |
- Run
run_pc.bat(orpython MonitorLink.py --mode pc). - The sender starts an mDNS/UDP beacon and opens a local WebSocket endpoint (
0.0.0.0:8765).
- Run
run_laptop.bat(orpython MonitorLink.py --mode laptop). - The laptop automatically discovers the host on your Wi-Fi or wired connection.
- To Link: Click Connect Display on either device. The laptop immediately enters an edge-to-edge fullscreen monitor state, hides the local cursor, and renders the PC display feed at up to 60 FPS.
- To Delink: Click Disconnect Display on the host, or press
Escon the client laptop. The laptop closes the receiver canvas and returns to its prior desktop state with all local windows and power timeouts preserved.
+-------------------------------------------------------------------------+
| HOST (PC) |
| |
| [ D3D11 / Desktop Duplication ] ---> [ TurboJPEG Compression ] |
| (IddCx Virtual Monitor / DXGI) (cv2.imencode, 60 FPS) |
| | |
| [ WebSocket Server ] |
| (port 8765: /stream, /control) |
+----------------------------------------------------+--------------------+
|
(Local Wi-Fi or Point-to-Point Cable)
|
+----------------------------------------------------+--------------------+
| CLIENT (Laptop) |
| |
| [ WebSocket Client ] ---> [ QImage Direct Blit ] |
| (Binary JPEG payload) (QPainter edge-to-edge canvas) |
| | |
| [ SetThreadExecutionState ] [ Bi-Directional Delink ] |
| (ES_DISPLAY_REQUIRED) (Esc hotkey / host control) |
+-------------------------------------------------------------------------+
| Component | Implementation | Notes |
|---|---|---|
| Screen capture | DirectX 11 DXGI Desktop Duplication API | Zero desktop memory copy overhead; falls back to Win32 GDI if running in isolated sessions |
| Compression | OpenCV Hardware-optimized JPEG | Frame drop policy ensures real-time pacing with zero accumulated socket buffer latency |
| Transport | Asynchronous binary WebSockets | Port 8765. Frame header + raw payload with ping/pong latency tracking |
| Discovery | UDP subnet broadcasts | Port 8766. Broadcasts machine role, IP interfaces, and hostnames every 1.0s |
| Receiver UI | PyQt6 with hardware-accelerated paint event | Borderless WindowStaysOnTopHint, auto-hiding cursor (1.5s timeout), floating HUD |
| Power management | Win32 SetThreadExecutionState |
Requests ES_SYSTEM_REQUIRED and ES_DISPLAY_REQUIRED while linked; cleans up on delink |
MonitorLink/
├── core/ # Core system, capture & networking engines
│ ├── capture.py # Hardware DXGI Desktop Duplication & GDI capturer (BGR 60 FPS)
│ ├── streamer.py # WebSocket streaming server & frame broadcast loop
│ ├── receiver.py # Laptop client receiver & latency tracker
│ ├── virtual_display.py # Indirect Display Driver manager & Windows topology sorter
│ ├── discovery.py # Local UDP subnet beacon auto-discovery
│ ├── input_handler.py # Remote mouse & keyboard passthrough
│ └── power_manager.py # Win32 sleep suppression (SetThreadExecutionState)
├── ui/ # Clean desktop user interface (PyQt6)
│ ├── main_window.py # Dual-role dashboard (PC Sender / Laptop Receiver)
│ ├── monitor_window.py # Fullscreen edge-to-edge canvas with floating HUD
│ ├── components.py # Custom cards, hardware indicators, and SVG icons
│ └── styles.py # Dark pro theme stylesheet (QSS)
├── driver/ # Bundled Microsoft IddCx Virtual Display Driver
│ ├── nefcon/ # Driver installer utility (x64, x86, ARM64)
│ └── VirtualDisplayDriver/ # Signed driver files, certificate, and resolution XML
├── static/ # Web receiver fallback for in-browser client (HTML/JS/CSS)
├── assets/ # Application icons, branding, and preview screenshots
├── MonitorLink.py # Application entry point & CLI parser
├── install_driver.bat # 1-click driver installation script (Elevated Admin)
├── run_pc.bat # Sender mode quick launcher
├── run_laptop.bat # Receiver mode quick launcher
└── build_exe.bat # Standalone PyInstaller portable packaging script
Windows requires an enumerated display device to provide an Extended Desktop workspace. If your host PC only has a single physical monitor, you have two options:
- Mirroring (Primary Display): Directly duplicates
\\.\DISPLAY1to the laptop screen with no driver installation required. - Extended Desktop (Virtual Display Driver): Uses the bundled Microsoft IddCx (Indirect Display Driver) implementation to create a genuine
\\.\DISPLAY2adapter in Windows Display Settings.
An automated script and signed driver binaries are provided in driver/:
# Run from an elevated PowerShell prompt:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\install_driver.batOnce installed, Windows recognizes a virtual display adapter (Root\MttVDD). You can arrange its relative position (left, right, above, or below your main screen) in Windows Display Settings (ms-settings:display). MonitorLink will automatically detect the second monitor and target it for streaming.
When linked, the client laptop enters a dedicated display receiver state:
- Display backlight and system activity: The application calls
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED). This keeps the panel powered and prevents modern standby sleep transitions without modifying global power schemes. - Input and cursor: The client cursor is suppressed when stationary. An optional input passthrough mode allows remote mouse manipulation over the control socket.
- State restoration: When delinked (via host UI, laptop HUD, or
Esc), the application:- Releases the fullscreen widget.
- Resets thread execution state flags via
SetThreadExecutionState(ES_CONTINUOUS). - Restores standard Windows cursor visibility and focus to the active shell.
Laptops are engineered with HDMI Output (Tx) controllers connected to their internal GPU. They cannot accept incoming TMDS/FRL video signals on that port. Connecting an HDMI cable between a desktop graphics card and a laptop HDMI port will not deliver video to the laptop panel.
- Direct Ethernet cable: Connect a standard Cat5e/Cat6 cable between the PC and Laptop RJ-45 ports. Windows configures a link-local APIPA address (
169.254.x.x). MonitorLink detects the wired adapter and prioritizes it for sub-5ms latency and full gigabit bandwidth. - USB-C Data / USB Tethering: Connecting over USB with RNDIS / USB Ethernet provides a dedicated local network interface.
- USB HDMI Video Capture Dongle: If physical HDMI output from your PC is strictly required, plug the PC HDMI cable into a USB UVC video capture dongle (~$10) plugged into the laptop.
- Operating System: Windows 10 (version 1903 or newer) or Windows 11.
- Python: Python 3.10 to 3.13.
- Network: Local Wi-Fi network with UDP broadcast enabled, or direct Ethernet / USB connection.
- Permissions: Standard user rights for streaming and client receiver. Administrator rights are required only if installing the optional IddCx Virtual Display Driver.
python -m venv .venv
.\.venv\Scripts\pip install -r requirements.txt# Run on PC:
.\.venv\Scripts\python.exe MonitorLink.py --mode pc
# Run on Laptop:
.\.venv\Scripts\python.exe MonitorLink.py --mode laptopTo generate a standalone portable build without requiring Python on the client laptop:
.\build_exe.batThe compiled binary and dependencies will be written to dist\MonitorLink\MonitorLink.exe.
If MonitorLink saved you from buying an expensive portable monitor, please consider starring the repository on GitHub! It helps the project reach more users and developers.
- 💬 Discussions: Have questions, latency test results, or setup ideas? Join the GitHub Discussions!
- 🐛 Issues: Found a bug or compatibility issue with your GPU or Windows build? Open an Issue.
- 🤝 Pull Requests: Pull requests are welcome for new encoder optimizations, input capture improvements, and localized guides.
MIT. Virtual Display Driver binaries are based on Microsoft's IddCx indirect display driver samples.

