medius 3.3.0

Host control library for the medius transparent mouse passthrough box
Documentation
//! Emit-rate pacing override: what paces injected motion, and the rate in effect (§4.14).

/// What paces injected motion (`OPTION(EMIT)`).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum EmitPace {
    /// Pace to the mouse's learnt native report rate (the default).
    #[default]
    Learned,
    /// Pace to the cloned mouse's `bInterval` poll rate.
    Interval,
    /// A fixed rate in Hz. The 1 ms frame clock snaps it to `1000/n` Hz and caps it at 1 kHz.
    Fixed(u16),
    /// A learned model decides per millisecond whether injected cursor motion emits and what counts it
    /// carries, from a profile of the attached mouse's own report stream. See [`RenderState`].
    Rendered,
}

/// Whether [`EmitPace::Rendered`] is actually rendering, reported by `RESP(OPTIONS, EMIT)` (§4.14).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum RenderState {
    /// The selected mode is not [`EmitPace::Rendered`].
    #[default]
    Off,
    /// Still collecting the attached mouse's profile; the box is pacing as [`EmitPace::Learned`] does.
    Warming,
    /// Rendering.
    Live,
    /// No usable model, or the game PC does not poll the clone every millisecond.
    Unavailable,
}

/// The configured [`EmitPace`] plus the emit-rate ceiling and the wire rate actually in effect (§4.14).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct EmitPaceStatus {
    /// The selected mode (for [`EmitPace::Fixed`], the rate the host requested).
    pub mode: EmitPace,
    /// The ceiling currently in effect (Hz); 0 = learnt/adaptive, or no device yet in [`EmitPace::Interval`].
    pub resolved_hz: u16,
    /// The forced wire rate the host asked for (Hz); `None` leaves the device's own.
    pub force_hz: Option<u16>,
    /// What the clone's input endpoints advertise now (Hz), forced or native; 0 = no clone.
    pub advertised_hz: u16,
    /// Whether a forced interval is written into the descriptor being served.
    pub force_active: bool,
    /// Whether [`EmitPace::Rendered`] is rendering, warming up, or refused.
    pub render_state: RenderState,
}

impl EmitPaceStatus {
    /// Decode a `RESP(OPTIONS, EMIT)` payload (§4.14).
    pub(crate) fn from_payload(p: &[u8]) -> Option<EmitPaceStatus> {
        if p.len() < 13 {
            return None;
        }
        let fixed_hz = u16::from_le_bytes([p[3], p[4]]);
        let resolved_hz = u16::from_le_bytes([p[5], p[6]]);
        let force_hz = u16::from_le_bytes([p[7], p[8]]);
        let advertised_hz = u16::from_le_bytes([p[9], p[10]]);
        let mode = match p[2] {
            0 => EmitPace::Learned,
            1 => EmitPace::Interval,
            2 => EmitPace::Fixed(fixed_hz),
            3 => EmitPace::Rendered,
            _ => return None,
        };
        let render_state = match p[12] {
            0 => RenderState::Off,
            1 => RenderState::Warming,
            2 => RenderState::Live,
            3 => RenderState::Unavailable,
            _ => return None,
        };
        Some(EmitPaceStatus {
            mode,
            resolved_hz,
            force_hz: (force_hz != 0).then_some(force_hz),
            advertised_hz,
            force_active: p[11] != 0,
            render_state,
        })
    }
}