Open SourceLamco RDP › Input

lamco-rdp-input

RDP input event translation — scancodes, mouse, and multi-monitor coordinates

v0.1 · MIT/Apache-2.0

RDP input, translated end-to-end

RDP sends keyboard input as Windows scancodes. Linux compositors expect evdev keycodes. Between them sits a surprisingly thorny translation layer: scancode tables, extended-prefix handling (E0, E1), modifier state tracking, international layouts, multi-monitor coordinate transforms with DPI scaling. lamco-rdp-input implements all of it in pure Rust, ready to drop into any RDP server built on IronRDP or otherwise.

Keyboard

  • 150+ scancode mappings
  • Extended E0 / E1 prefix handling
  • International layouts: US, DE, FR, UK, AZERTY, QWERTZ, Dvorak
  • Modifier tracking (Shift, Ctrl, Alt, Meta)
  • Caps/Num/Scroll toggle handling
  • Configurable key-repeat detection

Mouse

  • Absolute and relative movement
  • Sub-pixel precision with accumulation
  • 5-button support (L, R, M, X1, X2)
  • High-precision scrolling with accumulator
  • Button state tracking

Multi-monitor

  • RDP → Virtual Desktop → Monitor → Stream transform
  • Per-monitor DPI scaling
  • Scale-factor support
  • Windows-style mouse acceleration curves
  • Multi-monitor boundary handling

Quick start

Cargo.toml
[dependencies]
lamco-rdp-input = "0.1"
translating a keyboard event
use lamco_rdp_input::{InputTranslator, RdpInputEvent, MonitorInfo};

// Configure monitors
let monitors = vec![
    MonitorInfo {
        id: 1,
        name: "Primary".to_string(),
        x: 0, y: 0,
        width: 1920, height: 1080,
        dpi: 96.0,
        scale_factor: 1.0,
        stream_x: 0, stream_y: 0,
        stream_width: 1920, stream_height: 1080,
        is_primary: true,
    },
];

// Create translator
let mut translator = InputTranslator::new(monitors)?;

// Translate a keyboard event
let event = RdpInputEvent::KeyboardScancode {
    scancode: 0x1E,  // 'A' key
    extended: false,
    e1_prefix: false,
    pressed: true,
};

let linux_event = translator.translate_event(event)?;