vncrs 🖥️
A pure Rust VNC server library for Windows. Share your screen over the network to any standard VNC viewer — with zero fluff and minimal setup.
🌟 Features
- RFB 3.8 Protocol: Compatible with all major VNC clients — RealVNC, TigerVNC, UltraVNC, and more.
- VNC Authentication: Optional DES-based password protection.
- Multiple Encodings: Automatically negotiates the best encoding — Raw, Hextile, or Zlib.
- Tile-Based Dirty Detection: Only transmits changed screen regions to keep bandwidth low.
- Full Input Injection: Mouse movement, left/middle/right clicks, 4-directional scroll, and keyboard events.
- View-Only Mode: Serve your screen without allowing any remote input.
- Configurable FPS Cap: Tune frame rate anywhere from 1 to 120 FPS.
- Graceful Shutdown: Stop the server programmatically via an
Arc<AtomicBool>flag. - Extensible Traits: Plug in your own screen capture or input backend.
- Per-Session Stats: FPS and bandwidth reported after each client disconnects.
⚠️ Windows Only. Screen capture and input injection rely on
scrapandenigo, which target Windows in this configuration.
🛠️ Prerequisites
To build and run this project from source, you will need Rust and Cargo installed on your system.
If you don't have Rust installed, get it via rustup:
|
🚀 Installation
As a library dependency
Or add it manually to your Cargo.toml:
[]
= "0.1.1"
From source
Clone the repository and build with Cargo:
⚡ Quick Start
use ;
use ScrapCapture;
use EnigoInput;
Then connect with any VNC viewer:
🎮 Examples
Three ready-to-run examples are included in the examples/ directory.
simple_server
Minimal server on port 5900 with a password and 30 FPS cap.
headless
View-only server — the screen is shared but remote input is completely disabled.
full_server
A fully-featured CLI server with argument parsing.
| Flag | Default | Description |
|---|---|---|
-p, --port <PORT> |
5900 |
TCP port to listen on |
--password <PASS> |
— | VNC password (max 8 chars) |
-n, --name <NAME> |
"Rust VNC" |
Desktop name shown to the client |
--fps <FPS> |
60 |
Max frame rate |
--view-only |
— | Disable remote input |
-v, --verbose |
— | Enable debug logging |
Example:
⚙️ Configuration
VncServerConfig uses a builder pattern — all fields have sensible defaults.
| Method | Default | Description |
|---|---|---|
.port(u16) |
5900 |
TCP port to listen on |
.password(&str) |
None |
VNC password (truncated to 8 chars automatically) |
.name(&str) |
"Rust VNC" |
Desktop name shown to the client |
.max_fps(u32) |
60 |
Frame rate cap (clamped to 1–120) |
.tile_size(usize) |
64 |
Dirty-check tile size in pixels (clamped to 16–256) |
let config = new
.port
.password
.name
.max_fps
.tile_size;
🛑 Graceful Shutdown
The server exposes an Arc<AtomicBool> that you can flip from any thread — for example in a Ctrl-C handler:
use Ordering;
let running = server.running_flag;
set_handler.ok;
server.listen?;
You can also call server.stop() directly if you hold a reference to the server.
🏗️ Architecture
vncrs
├── server.rs VncServer — main accept / client loop
├── config.rs VncServerConfig builder
├── error.rs VncError + Result type alias
├── stats.rs Per-session FPS / bandwidth counter
├── capture/
│ ├── mod.rs ScreenCapture trait
│ └── scrap.rs Windows implementation via `scrap`
├── input/
│ ├── mod.rs InputHandler trait + NoopInput
│ ├── enigo_input.rs Windows implementation via `enigo`
│ └── keysym.rs X11 keysym → enigo key mapping
├── encoding/
│ ├── mod.rs EncoderSet (negotiation + dispatch)
│ ├── raw.rs Raw encoding
│ ├── hextile.rs Hextile encoding
│ └── zlib.rs Zlib encoding
└── protocol/
├── handshake.rs RFB 3.8 handshake
├── auth.rs VNC authentication (DES challenge-response)
├── messages.rs Client message parsing
└── pixel_format.rs PixelFormat negotiation
Key Traits
Implement ScreenCapture to provide your own frame source:
Implement InputHandler to handle remote input events:
Use the built-in NoopInput for a view-only server without writing a custom implementation.
📦 Dependencies
| Crate | Purpose |
|---|---|
scrap |
Screen capture |
enigo |
Mouse & keyboard injection |
flate2 |
Zlib compression |
des + cipher |
DES for VNC challenge-response auth |
rand |
Random challenge generation |
thiserror |
Ergonomic error definitions |
log + env_logger |
Structured logging |
🤝 Contributing
Contributions, issues, and feature requests are always welcome! Feel free to check the issues page if you want to contribute.
- Fork the project.
- Create your feature branch (
git checkout -b feature/AmazingFeature). - Commit your changes (
git commit -m 'Add some AmazingFeature'). - Push to the branch (
git push origin feature/AmazingFeature). - Open a Pull Request.
📝 License
This project is licensed under the MIT License — see the LICENSE file for details.
Developed with ❤️ in Rust