Open Source › Lamco RDP › Clipboard-rdp
lamco-rdp-clipboard
IronRDP CliprdrBackend implementation — bridges CLIPRDR SVC to any ClipboardSink
IronRDP CLIPRDR, done right
IronRDP’s CLIPRDR static virtual channel is where clipboard events arrive in an RDP session — but the trait surface is synchronous, called from the message-processing loop, and has no built-in concept of a backend abstraction. lamco-rdp-clipboard provides the bridge: a CliprdrBackend implementation that queues events for async processing and delegates to any ClipboardSink from lamco-clipboard-core. File transfer (MS-RDPECLIP FileContents) included.
How the bridge works
┌────────────────────────────────────────────────────────────────────┐ │ lamco-rdp-clipboard │ │ ┌─────────────────────┐ ┌───────────────────────────────┐ │ │ │ RdpCliprdrBackend │◄───────►│ ClipboardSink (trait) │ │ │ │ (CliprdrBackend) │ │ - Portal │ │ │ └─────────────────────┘ │ - X11 │ │ │ ▲ │ - Memory (testing) │ │ │ │ └───────────────────────────────┘ │ │ ▼ │ │ ┌─────────────────────┐ │ │ │ ironrdp-cliprdr │ │ │ │ (CLIPRDR SVC) │ │ │ └─────────────────────┘ │ └────────────────────────────────────────────────────────────────────┘
Event model
The ClipboardEvent enum covers every CLIPRDR interaction:
| Event | Meaning |
|---|---|
| Ready | Backend initialized, channel ready |
| RequestFormatList | Request to send local format list |
| NegotiatedCapabilities | Capabilities negotiated with peer |
| RemoteCopy | Remote clipboard content changed |
| FormatDataRequest | Peer requests specific format data |
| FormatDataResponse | Peer sent requested data |
| FileContentsRequest | Peer requests a file chunk |
| FileContentsResponse | Peer sent a file chunk |
| Lock / Unlock | Clipboard lock operations |
Quick start
[dependencies]
lamco-rdp-clipboard = "0.3"
use lamco_rdp_clipboard::{RdpCliprdrFactory, ClipboardEvent};
use ironrdp_cliprdr::backend::CliprdrBackendFactory;
// Create a factory with a temp directory for file transfers
let factory = RdpCliprdrFactory::new("/tmp/clipboard");
// Subscribe to clipboard events
let receiver = factory.subscribe();
// Build a backend for IronRDP
let backend = factory.build_cliprdr_backend();
// Process events asynchronously
loop {
for event in receiver.drain() {
match event {
ClipboardEvent::Ready => println!("Clipboard ready"),
ClipboardEvent::RemoteCopy { formats } => {
println!("Remote copy: {} formats", formats.len());
}
ClipboardEvent::FormatDataRequest { format_id } => {
println!("Data requested: {:?}", format_id);
}
_ => {}
}
}
}
The backend is non-blocking by design — CliprdrBackend trait methods queue events instead of blocking the RDP message loop.