use tracing::debug;
use windows::Win32::Foundation::HWND;
use windows::Win32::UI::Input::KeyboardAndMouse::{ReleaseCapture, SetCapture};
pub struct CaptureGuard {
hwnd: HWND,
released: bool,
}
impl CaptureGuard {
pub fn acquire(hwnd: HWND) -> Self {
unsafe {
SetCapture(hwnd);
}
debug!(
hwnd = format!("0x{:X}", hwnd.0 as usize),
"[CaptureGuard] Capture acquired"
);
Self {
hwnd,
released: false,
}
}
pub fn mark_released(&mut self) {
self.released = true;
}
pub fn hwnd(&self) -> HWND {
self.hwnd
}
#[allow(dead_code)]
pub fn is_released(&self) -> bool {
self.released
}
}
impl Drop for CaptureGuard {
fn drop(&mut self) {
if !self.released {
let _ = unsafe { ReleaseCapture() };
debug!(
hwnd = format!("0x{:X}", self.hwnd.0 as usize),
"[CaptureGuard] Capture released via Drop"
);
}
}
}
impl std::fmt::Debug for CaptureGuard {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CaptureGuard")
.field("hwnd", &format_args!("0x{:X}", self.hwnd.0 as usize))
.field("released", &self.released)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn capture_guard_with_null_hwnd() {
let guard = CaptureGuard::acquire(HWND::default());
assert!(!guard.is_released());
}
#[test]
fn mark_released_sets_flag() {
let mut guard = CaptureGuard::acquire(HWND::default());
assert!(!guard.is_released());
guard.mark_released();
assert!(guard.is_released());
}
#[test]
fn debug_format() {
let guard = CaptureGuard::acquire(HWND::default());
let debug_str = format!("{:?}", guard);
assert!(debug_str.contains("CaptureGuard"));
assert!(debug_str.contains("released: false"));
}
}