use std::sync::{Arc, Mutex};
use image::RgbaImage;
use windows_capture::capture::{Context, GraphicsCaptureApiHandler};
use windows_capture::frame::Frame;
use windows_capture::graphics_capture_api::InternalCaptureControl;
use windows_capture::settings::{
ColorFormat, CursorCaptureSettings, DirtyRegionSettings, DrawBorderSettings,
MinimumUpdateIntervalSettings, SecondaryWindowSettings, Settings,
};
use windows_capture::window::Window;
use crate::capture::draw_click_marker;
use crate::model::WindowInfo;
type Slot = Arc<Mutex<Option<RgbaImage>>>;
struct OneShot {
slot: Slot,
}
impl GraphicsCaptureApiHandler for OneShot {
type Flags = Slot;
type Error = std::convert::Infallible;
fn new(ctx: Context<Self::Flags>) -> Result<Self, Self::Error> {
Ok(Self { slot: ctx.flags })
}
fn on_frame_arrived(
&mut self,
frame: &mut Frame,
capture_control: InternalCaptureControl,
) -> Result<(), Self::Error> {
if let Ok(fb) = frame.buffer() {
let (w, h) = (fb.width(), fb.height());
let mut scratch = Vec::new();
let rgba = fb.as_nopadding_buffer(&mut scratch);
if let Some(img) = RgbaImage::from_raw(w, h, rgba.to_vec()) {
if let Ok(mut slot) = self.slot.lock() {
*slot = Some(img);
}
}
}
capture_control.stop();
Ok(())
}
}
pub fn capture_for_click(pos: Option<(i32, i32)>) -> Option<(RgbaImage, Option<WindowInfo>)> {
let window = Window::foreground().ok()?;
let pid = window.process_id().ok()?;
if pid == std::process::id() {
return None;
}
let rect = window.rect().ok()?;
let info = WindowInfo {
title: window.title().unwrap_or_default(),
app_name: window.process_name().unwrap_or_default(),
pid,
x: rect.left,
y: rect.top,
width: (rect.right - rect.left).max(0) as u32,
height: (rect.bottom - rect.top).max(0) as u32,
};
let slot: Slot = Arc::new(Mutex::new(None));
let settings = Settings::new(
window,
CursorCaptureSettings::WithoutCursor,
DrawBorderSettings::WithoutBorder,
SecondaryWindowSettings::Default,
MinimumUpdateIntervalSettings::Default,
DirtyRegionSettings::Default,
ColorFormat::Rgba8,
slot.clone(),
);
OneShot::start(settings).ok()?;
let mut image = slot.lock().ok()?.take()?;
if let Some((px, py)) = pos {
draw_click_marker(&mut image, px - info.x, py - info.y);
}
Some((image, Some(info)))
}