feat(screenshot): implement area screenshot functionality and integrate with shortcut management

This commit is contained in:
2025-04-22 22:04:26 +02:00
parent f6f31540af
commit dc83bdb3fb
5 changed files with 69 additions and 6 deletions

View File

@ -1,12 +1,13 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "Haystack" name = "Haystack"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"base64 0.21.7", "base64 0.21.7",
"chrono",
"cocoa", "cocoa",
"notify", "notify",
"serde", "serde",
@ -536,8 +537,10 @@ checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
dependencies = [ dependencies = [
"android-tzdata", "android-tzdata",
"iana-time-zone", "iana-time-zone",
"js-sys",
"num-traits", "num-traits",
"serde", "serde",
"wasm-bindgen",
"windows-link", "windows-link",
] ]

View File

@ -28,6 +28,7 @@ base64 = "0.21.7"
tokio = { version = "1.36.0", features = ["full"] } tokio = { version = "1.36.0", features = ["full"] }
tauri-plugin-store = "2.0.0-beta.12" tauri-plugin-store = "2.0.0-beta.12"
tauri-plugin-http = "2.0.0-beta.12" tauri-plugin-http = "2.0.0-beta.12"
chrono = "0.4"
[target."cfg(target_os = \"macos\")".dependencies] [target."cfg(target_os = \"macos\")".dependencies]
cocoa = "0.26" cocoa = "0.26"

View File

@ -1,7 +1,8 @@
mod commands; mod commands;
mod shortcut; pub mod screenshot;
pub mod shortcut;
mod state; mod state;
mod utils; pub mod utils;
mod window; mod window;
use state::new_shared_watcher_state; use state::new_shared_watcher_state;

View File

@ -0,0 +1,53 @@
use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
use std::fs;
use std::process::Command;
use tauri::{AppHandle, Runtime};
/// Takes a screenshot of a selected area and returns the image data as base64
pub fn take_area_screenshot<R: Runtime>(app: &AppHandle<R>) -> Result<String, String> {
// Create a temporary file path
let temp_dir = std::env::temp_dir();
let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S");
let temp_file = temp_dir.join(format!("haystack_screenshot_{}.png", timestamp));
// Use screencapture command with -i flag for interactive selection
let output = Command::new("screencapture")
.arg("-i") // interactive selection
.arg("-x") // don't play sound
.arg("-o") // don't show cursor
.arg("-r") // don't add shadow
.arg(temp_file.to_str().unwrap())
.output()
.map_err(|e| format!("Failed to execute screencapture: {}", e))?;
if !output.status.success() {
return Err(format!(
"screencapture failed: {}",
String::from_utf8_lossy(&output.stderr)
));
}
// Read the captured image
let contents =
fs::read(&temp_file).map_err(|e| format!("Failed to read screenshot file: {}", e))?;
// Convert to base64
let base64_string = BASE64.encode(&contents);
// Clean up the temporary file
if let Err(e) = fs::remove_file(&temp_file) {
println!("Warning: Failed to remove temporary screenshot file: {}", e);
}
// Log the base64 string (truncated for readability)
if base64_string.len() > 100 {
println!(
"Screenshot base64 (truncated): {}...",
&base64_string[..100]
);
} else {
println!("Screenshot base64: {}", base64_string);
}
Ok(base64_string)
}

View File

@ -1,3 +1,4 @@
use crate::screenshot::take_area_screenshot;
use tauri::App; use tauri::App;
use tauri::AppHandle; use tauri::AppHandle;
use tauri::Emitter; use tauri::Emitter;
@ -200,6 +201,9 @@ fn register_shortcut_upon_start(
// TODO: Implement screenshot functionality // TODO: Implement screenshot functionality
println!("Screenshot shortcut pressed"); println!("Screenshot shortcut pressed");
} }
if let Err(e) = take_area_screenshot(app) {
println!("Failed to take screenshot: {}", e);
}
} }
}) })
.build(), .build(),
@ -268,11 +272,12 @@ pub fn change_screenshot_shortcut<R: Runtime>(
fn register_screenshot_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) { fn register_screenshot_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) {
app.global_shortcut() app.global_shortcut()
.on_shortcut(shortcut, move |_app, scut, event| { .on_shortcut(shortcut, move |app, scut, event| {
if scut == &shortcut { if scut == &shortcut {
if let ShortcutState::Pressed = event.state() { if let ShortcutState::Pressed = event.state() {
// TODO: Implement screenshot functionality if let Err(e) = take_area_screenshot(app) {
println!("Screenshot shortcut pressed"); println!("Failed to take screenshot: {}", e);
}
} }
} }
}) })