From 2448a3369871475cf8abdafc6391f1b9ceffcac2 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Mon, 15 Jun 2026 01:50:16 +0000 Subject: [PATCH] style(host/windows): rustfmt the Windows backends Co-Authored-By: Claude Opus 4.8 (1M context) --- crates/punktfunk-host/src/audio.rs | 3 +- crates/punktfunk-host/src/audio/wasapi_cap.rs | 18 +++- crates/punktfunk-host/src/capture.rs | 8 +- crates/punktfunk-host/src/capture/dxgi.rs | 15 +++- crates/punktfunk-host/src/encode.rs | 13 ++- crates/punktfunk-host/src/encode/nvenc.rs | 10 ++- crates/punktfunk-host/src/encode/sw.rs | 10 ++- crates/punktfunk-host/src/inject.rs | 4 +- crates/punktfunk-host/src/inject/sendinput.rs | 71 ++++++++++++--- crates/punktfunk-host/src/m3.rs | 86 +++++++++---------- crates/punktfunk-host/src/vdisplay.rs | 4 +- crates/punktfunk-host/src/vdisplay/sudovda.rs | 28 +++--- 12 files changed, 177 insertions(+), 93 deletions(-) diff --git a/crates/punktfunk-host/src/audio.rs b/crates/punktfunk-host/src/audio.rs index b4ba387..017ddb8 100644 --- a/crates/punktfunk-host/src/audio.rs +++ b/crates/punktfunk-host/src/audio.rs @@ -39,7 +39,8 @@ pub fn open_audio_capture(channels: u32) -> Result> { #[cfg(target_os = "windows")] pub fn open_audio_capture(channels: u32) -> Result> { - wasapi_cap::WasapiLoopbackCapturer::open(channels).map(|c| Box::new(c) as Box) + wasapi_cap::WasapiLoopbackCapturer::open(channels) + .map(|c| Box::new(c) as Box) } #[cfg(not(any(target_os = "linux", target_os = "windows")))] diff --git a/crates/punktfunk-host/src/audio/wasapi_cap.rs b/crates/punktfunk-host/src/audio/wasapi_cap.rs index 0881bd5..0bd4d8c 100644 --- a/crates/punktfunk-host/src/audio/wasapi_cap.rs +++ b/crates/punktfunk-host/src/audio/wasapi_cap.rs @@ -46,7 +46,9 @@ impl WasapiLoopbackCapturer { .context("spawn wasapi audio thread")?; match ready_rx.recv_timeout(Duration::from_secs(3)) { Ok(Ok(())) => { - tracing::info!("WASAPI loopback capture: 48 kHz stereo f32 (default render endpoint)"); + tracing::info!( + "WASAPI loopback capture: 48 kHz stereo f32 (default render endpoint)" + ); Ok(WasapiLoopbackCapturer { chunks: rx, channels, @@ -93,7 +95,10 @@ fn capture_thread( ready: SyncSender>, ) -> Result<()> { // COM must be initialized on THIS thread (MTA), before any device call. - if let Err(e) = wasapi::initialize_mta().ok().context("CoInitializeEx (MTA)") { + if let Err(e) = wasapi::initialize_mta() + .ok() + .context("CoInitializeEx (MTA)") + { let _ = ready.send(Err(e)); return Ok(()); } @@ -122,7 +127,9 @@ fn capture_thread( let capture_client = audio_client .get_audiocaptureclient() .context("IAudioCaptureClient")?; - audio_client.start_stream().context("start loopback stream")?; + audio_client + .start_stream() + .context("start loopback stream")?; let _ = ready.send(Ok(())); let mut bytes: VecDeque = VecDeque::new(); @@ -182,7 +189,10 @@ mod tests { }; assert_eq!(cap.channels(), 2); match cap.next_chunk() { - Ok(samples) => assert!(samples.len() % 2 == 0, "interleaved stereo => even sample count"), + Ok(samples) => assert!( + samples.len() % 2 == 0, + "interleaved stereo => even sample count" + ), Err(e) => eprintln!("no audio within timeout (silent system?): {e:#}"), } } diff --git a/crates/punktfunk-host/src/capture.rs b/crates/punktfunk-host/src/capture.rs index 527938d..3d5c8b2 100644 --- a/crates/punktfunk-host/src/capture.rs +++ b/crates/punktfunk-host/src/capture.rs @@ -257,7 +257,9 @@ pub fn capture_virtual_output(vout: crate::vdisplay::VirtualOutput) -> Result Result> { let target = vout.win_capture.clone().ok_or_else(|| { - anyhow::anyhow!("SudoVDA target not yet an active display (needs a WDDM GPU to activate it)") + anyhow::anyhow!( + "SudoVDA target not yet an active display (needs a WDDM GPU to activate it)" + ) })?; dxgi::DuplCapturer::open(target, vout.preferred_mode, vout.keepalive) .map(|c| Box::new(c) as Box) @@ -268,7 +270,7 @@ pub fn capture_virtual_output(_vout: crate::vdisplay::VirtualOutput) -> Result = None; - match self.dupl.AcquireNextFrame(self.timeout_ms, &mut info, &mut res) { + match self + .dupl + .AcquireNextFrame(self.timeout_ms, &mut info, &mut res) + { Ok(()) => {} Err(e) if e.code() == DXGI_ERROR_WAIT_TIMEOUT => return Ok(None), Err(e) if e.code() == DXGI_ERROR_ACCESS_LOST => { diff --git a/crates/punktfunk-host/src/encode.rs b/crates/punktfunk-host/src/encode.rs index c71b393..6e3feb4 100644 --- a/crates/punktfunk-host/src/encode.rs +++ b/crates/punktfunk-host/src/encode.rs @@ -185,8 +185,13 @@ pub fn open_video( ); // Software H.264 realistically caps far below the negotiated hardware rates. const SW_BITRATE_CEIL: u64 = 100_000_000; - let enc = - sw::OpenH264Encoder::open(format, width, height, fps, bitrate_bps.min(SW_BITRATE_CEIL))?; + let enc = sw::OpenH264Encoder::open( + format, + width, + height, + fps, + bitrate_bps.min(SW_BITRATE_CEIL), + )?; Ok(Box::new(enc) as Box) } #[cfg(not(any(target_os = "linux", target_os = "windows")))] @@ -198,10 +203,10 @@ pub fn open_video( #[cfg(target_os = "linux")] mod linux; -#[cfg(target_os = "windows")] -mod sw; #[cfg(all(target_os = "windows", feature = "nvenc"))] mod nvenc; +#[cfg(target_os = "windows")] +mod sw; #[cfg(test)] mod tests { diff --git a/crates/punktfunk-host/src/encode/nvenc.rs b/crates/punktfunk-host/src/encode/nvenc.rs index fdfb277..e74f805 100644 --- a/crates/punktfunk-host/src/encode/nvenc.rs +++ b/crates/punktfunk-host/src/encode/nvenc.rs @@ -18,8 +18,8 @@ use std::ffi::c_void; use std::ptr; use windows::core::Interface; use windows::Win32::Graphics::Direct3D11::{ - ID3D11Device, ID3D11DeviceContext, ID3D11Texture2D, D3D11_BIND_RENDER_TARGET, D3D11_TEXTURE2D_DESC, - D3D11_USAGE_DEFAULT, + ID3D11Device, ID3D11DeviceContext, ID3D11Texture2D, D3D11_BIND_RENDER_TARGET, + D3D11_TEXTURE2D_DESC, D3D11_USAGE_DEFAULT, }; use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SAMPLE_DESC}; @@ -94,7 +94,11 @@ impl NvencD3d11Encoder { /// Lazily create the session on the first frame's D3D11 device (so capture + encode share it). fn init_session(&mut self, device: &ID3D11Device) -> Result<()> { unsafe { - self.ctx = Some(device.GetImmediateContext().context("D3D11 immediate context")?); + self.ctx = Some( + device + .GetImmediateContext() + .context("D3D11 immediate context")?, + ); // 1. open the session bound to the D3D11 device. let mut params = nv::NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS { diff --git a/crates/punktfunk-host/src/encode/sw.rs b/crates/punktfunk-host/src/encode/sw.rs index 4a4298d..41bf63e 100644 --- a/crates/punktfunk-host/src/encode/sw.rs +++ b/crates/punktfunk-host/src/encode/sw.rs @@ -132,10 +132,12 @@ impl Encoder for OpenH264Encoder { ); match self.src_format { - PixelFormat::Rgb => self.yuv.read_rgb(RgbSliceU8::new(&bytes[..w * h * 3], (w, h))), - PixelFormat::Bgra | PixelFormat::Bgrx => { - self.yuv.read_rgb(BgraSliceU8::new(&bytes[..w * h * 4], (w, h))) - } + PixelFormat::Rgb => self + .yuv + .read_rgb(RgbSliceU8::new(&bytes[..w * h * 3], (w, h))), + PixelFormat::Bgra | PixelFormat::Bgrx => self + .yuv + .read_rgb(BgraSliceU8::new(&bytes[..w * h * 4], (w, h))), PixelFormat::Rgba | PixelFormat::Rgbx => { self.normalize_to_bgra(bytes, 4, true); self.yuv.read_rgb(BgraSliceU8::new(&self.scratch, (w, h))); diff --git a/crates/punktfunk-host/src/inject.rs b/crates/punktfunk-host/src/inject.rs index 6792d05..892fd68 100644 --- a/crates/punktfunk-host/src/inject.rs +++ b/crates/punktfunk-host/src/inject.rs @@ -317,7 +317,7 @@ pub mod gamepad { } #[cfg(target_os = "linux")] mod libei; -#[cfg(target_os = "linux")] -mod wlr; #[cfg(target_os = "windows")] mod sendinput; +#[cfg(target_os = "linux")] +mod wlr; diff --git a/crates/punktfunk-host/src/inject/sendinput.rs b/crates/punktfunk-host/src/inject/sendinput.rs index 2a2d2e5..07ffdbb 100644 --- a/crates/punktfunk-host/src/inject/sendinput.rs +++ b/crates/punktfunk-host/src/inject/sendinput.rs @@ -13,11 +13,11 @@ use windows::Win32::System::StationsAndDesktops::{ }; use windows::Win32::UI::Input::KeyboardAndMouse::{ MapVirtualKeyExW, SendInput, INPUT, INPUT_0, INPUT_KEYBOARD, INPUT_MOUSE, KEYBDINPUT, - KEYEVENTF_EXTENDEDKEY, KEYEVENTF_KEYUP, KEYEVENTF_SCANCODE, MAPVK_VK_TO_VSC_EX, MOUSEEVENTF_ABSOLUTE, - MOUSEEVENTF_HWHEEL, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN, - MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, - MOUSEEVENTF_VIRTUALDESK, MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP, MOUSEINPUT, - VIRTUAL_KEY, + KEYEVENTF_EXTENDEDKEY, KEYEVENTF_KEYUP, KEYEVENTF_SCANCODE, MAPVK_VK_TO_VSC_EX, + MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_HWHEEL, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, + MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN, + MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_VIRTUALDESK, MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, + MOUSEEVENTF_XUP, MOUSEINPUT, VIRTUAL_KEY, }; use windows::Win32::UI::WindowsAndMessaging::{ GetSystemMetrics, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN, @@ -73,7 +73,10 @@ impl SendInputInjector { if n as usize != inputs.len() { // 0 = blocked (different/secure desktop). Surface as Err so the host service drops + // reopens the injector (which reattaches the input desktop). - anyhow::bail!("SendInput injected {n}/{} events (blocked desktop?)", inputs.len()); + anyhow::bail!( + "SendInput injected {n}/{} events (blocked desktop?)", + inputs.len() + ); } Ok(()) } @@ -130,11 +133,46 @@ impl InputInjector for SendInputInjector { InputKind::MouseButtonDown | InputKind::MouseButtonUp => { let down = event.kind == InputKind::MouseButtonDown; let (flag, data) = match event.code { - 1 => (if down { MOUSEEVENTF_LEFTDOWN } else { MOUSEEVENTF_LEFTUP }, 0u32), - 2 => (if down { MOUSEEVENTF_MIDDLEDOWN } else { MOUSEEVENTF_MIDDLEUP }, 0), - 3 => (if down { MOUSEEVENTF_RIGHTDOWN } else { MOUSEEVENTF_RIGHTUP }, 0), - 4 => (if down { MOUSEEVENTF_XDOWN } else { MOUSEEVENTF_XUP }, XBUTTON1), - 5 => (if down { MOUSEEVENTF_XDOWN } else { MOUSEEVENTF_XUP }, XBUTTON2), + 1 => ( + if down { + MOUSEEVENTF_LEFTDOWN + } else { + MOUSEEVENTF_LEFTUP + }, + 0u32, + ), + 2 => ( + if down { + MOUSEEVENTF_MIDDLEDOWN + } else { + MOUSEEVENTF_MIDDLEUP + }, + 0, + ), + 3 => ( + if down { + MOUSEEVENTF_RIGHTDOWN + } else { + MOUSEEVENTF_RIGHTUP + }, + 0, + ), + 4 => ( + if down { + MOUSEEVENTF_XDOWN + } else { + MOUSEEVENTF_XUP + }, + XBUTTON1, + ), + 5 => ( + if down { + MOUSEEVENTF_XDOWN + } else { + MOUSEEVENTF_XUP + }, + XBUTTON2, + ), _ => return Ok(()), }; let mi = MOUSEINPUT { @@ -155,7 +193,11 @@ impl InputInjector for SendInputInjector { dx: 0, dy: 0, mouseData: event.x as u32, // signed wheel delta reinterpreted as DWORD - dwFlags: if horizontal { MOUSEEVENTF_HWHEEL } else { MOUSEEVENTF_WHEEL }, + dwFlags: if horizontal { + MOUSEEVENTF_HWHEEL + } else { + MOUSEEVENTF_WHEEL + }, time: 0, dwExtraInfo: 0, }; @@ -226,5 +268,8 @@ fn virtual_desktop_rect() -> (i32, i32, i32, i32) { // RCtrl (0xA3), RAlt (0xA5), Pause (0x90). MAPVK_VK_TO_VSC_EX already encodes E0 for most; this is a // thin safety net. fn forced_extended(vk: u16) -> bool { - matches!(vk, 0x21..=0x28 | 0x2D | 0x2E | 0x5B | 0x5C | 0x5D | 0xA3 | 0xA5 | 0x90) + matches!( + vk, + 0x21..=0x28 | 0x2D | 0x2E | 0x5B | 0x5C | 0x5D | 0xA3 | 0xA5 | 0x90 + ) } diff --git a/crates/punktfunk-host/src/m3.rs b/crates/punktfunk-host/src/m3.rs index c251b50..029a2c7 100644 --- a/crates/punktfunk-host/src/m3.rs +++ b/crates/punktfunk-host/src/m3.rs @@ -1528,52 +1528,52 @@ fn resolve_compositor(pref: CompositorPref) -> Result = available.iter().map(|c| c.id()).collect(); - match Compositor::from_pref(pref) { - Some(want) if want == chosen => { - tracing::info!( - compositor = chosen.id(), - "honoring client compositor request" - ) + if !overridden { + // Point input at the same backend and select gamescope ATTACH (no churny managed restart). + crate::vdisplay::apply_input_env(chosen); } - Some(want) => tracing::warn!( - requested = want.id(), - chosen = chosen.id(), - available = ?avail_ids, - "client-requested compositor unavailable — falling back to auto-detect" - ), - None => tracing::info!( - compositor = chosen.id(), - "auto-detected compositor (client: auto)" - ), - } - Ok(chosen) + let avail_ids: Vec<&str> = available.iter().map(|c| c.id()).collect(); + match Compositor::from_pref(pref) { + Some(want) if want == chosen => { + tracing::info!( + compositor = chosen.id(), + "honoring client compositor request" + ) + } + Some(want) => tracing::warn!( + requested = want.id(), + chosen = chosen.id(), + available = ?avail_ids, + "client-requested compositor unavailable — falling back to auto-detect" + ), + None => tracing::info!( + compositor = chosen.id(), + "auto-detected compositor (client: auto)" + ), + } + Ok(chosen) } } diff --git a/crates/punktfunk-host/src/vdisplay.rs b/crates/punktfunk-host/src/vdisplay.rs index 7dab2af..9a1fb32 100644 --- a/crates/punktfunk-host/src/vdisplay.rs +++ b/crates/punktfunk-host/src/vdisplay.rs @@ -540,10 +540,10 @@ mod gamescope; mod kwin; #[cfg(target_os = "linux")] mod mutter; -#[cfg(target_os = "linux")] -mod wlroots; #[cfg(target_os = "windows")] mod sudovda; +#[cfg(target_os = "linux")] +mod wlroots; #[cfg(test)] mod tests { diff --git a/crates/punktfunk-host/src/vdisplay/sudovda.rs b/crates/punktfunk-host/src/vdisplay/sudovda.rs index 249d68d..7098d48 100644 --- a/crates/punktfunk-host/src/vdisplay/sudovda.rs +++ b/crates/punktfunk-host/src/vdisplay/sudovda.rs @@ -229,11 +229,16 @@ impl VirtualDisplay for SudoVdaDisplay { device_name, serial: [0u8; 14], }; - let add_bytes = - unsafe { std::slice::from_raw_parts(&add as *const _ as *const u8, size_of::()) }; + let add_bytes = unsafe { + std::slice::from_raw_parts(&add as *const _ as *const u8, size_of::()) + }; let mut out = [0u8; size_of::()]; - unsafe { ioctl(self.device, IOCTL_ADD, add_bytes, &mut out) } - .with_context(|| format!("SudoVDA ADD {}x{}@{}", mode.width, mode.height, mode.refresh_hz))?; + unsafe { ioctl(self.device, IOCTL_ADD, add_bytes, &mut out) }.with_context(|| { + format!( + "SudoVDA ADD {}x{}@{}", + mode.width, mode.height, mode.refresh_hz + ) + })?; let ao = unsafe { *(out.as_ptr() as *const AddOut) }; tracing::info!( "SudoVDA created {}x{}@{} (target_id={}, adapter_luid={:#x})", @@ -281,10 +286,12 @@ impl VirtualDisplay for SudoVdaDisplay { Ok(VirtualOutput { node_id: 0, // unused on Windows; the capture target is the GDI name below preferred_mode: Some((mode.width, mode.height, mode.refresh_hz)), - win_capture: gdi_name.clone().map(|n| crate::capture::dxgi::WinCaptureTarget { - adapter_luid: crate::capture::dxgi::pack_luid(ao.luid), - gdi_name: n, - }), + win_capture: gdi_name + .clone() + .map(|n| crate::capture::dxgi::WinCaptureTarget { + adapter_luid: crate::capture::dxgi::pack_luid(ao.luid), + gdi_name: n, + }), keepalive: Box::new(SudoVdaKeepalive { device: device_raw, guid: MONITOR_GUID, @@ -314,8 +321,9 @@ impl Drop for SudoVdaKeepalive { let _ = j.join(); } let rp = RemoveParams { guid: self.guid }; - let rp_bytes = - unsafe { std::slice::from_raw_parts(&rp as *const _ as *const u8, size_of::()) }; + let rp_bytes = unsafe { + std::slice::from_raw_parts(&rp as *const _ as *const u8, size_of::()) + }; let mut none: [u8; 0] = []; let h = HANDLE(self.device as *mut c_void); if let Err(e) = unsafe { ioctl(h, IOCTL_REMOVE, rp_bytes, &mut none) } {