Implement core speech-to-text pipeline
All major components: hotkey listener (rdev), audio capture (cpal), resampling (rubato), VAD (Silero ONNX), Parakeet v3 TDT transcription (ort), overlay window (winit+softbuffer), paste simulation (enigo+arboard), audio feedback (rodio), YAML config, CLI with clap, HuggingFace model download. ~2400 lines of Rust across 16 source files. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
use anyhow::{Context, Result};
|
||||
use arboard::Clipboard;
|
||||
use enigo::{Direction, Enigo, Key, Keyboard, Settings};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use tracing::{debug, info};
|
||||
|
||||
use crate::config::PasteMethod;
|
||||
|
||||
/// Paste text using the configured method.
|
||||
pub fn paste_text(text: &str, method: &PasteMethod, keep_on_clipboard: bool) -> Result<()> {
|
||||
let mut clipboard = Clipboard::new().context("Failed to open clipboard")?;
|
||||
|
||||
// Save current clipboard content if we need to restore it
|
||||
let previous = if !keep_on_clipboard {
|
||||
clipboard.get_text().ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Set text to clipboard
|
||||
clipboard
|
||||
.set_text(text.to_string())
|
||||
.context("Failed to set clipboard text")?;
|
||||
debug!("Text set to clipboard ({} chars)", text.len());
|
||||
|
||||
if *method == PasteMethod::ClipboardOnly {
|
||||
info!("Text copied to clipboard (clipboard_only mode)");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Small delay to ensure clipboard is ready
|
||||
thread::sleep(Duration::from_millis(50));
|
||||
|
||||
// Simulate paste keystroke
|
||||
let mut enigo = Enigo::new(&Settings::default()).context("Failed to create enigo instance")?;
|
||||
|
||||
match method {
|
||||
PasteMethod::CtrlV => {
|
||||
debug!("Pasting via Ctrl+V");
|
||||
enigo.key(Key::Control, Direction::Press)?;
|
||||
enigo.key(Key::Unicode('v'), Direction::Click)?;
|
||||
enigo.key(Key::Control, Direction::Release)?;
|
||||
}
|
||||
PasteMethod::ShiftInsert => {
|
||||
debug!("Pasting via Shift+Insert");
|
||||
enigo.key(Key::Shift, Direction::Press)?;
|
||||
enigo.key(Key::Other(0x2D), Direction::Click)?; // VK_INSERT on Windows
|
||||
enigo.key(Key::Shift, Direction::Release)?;
|
||||
}
|
||||
PasteMethod::CtrlShiftV => {
|
||||
debug!("Pasting via Ctrl+Shift+V");
|
||||
enigo.key(Key::Control, Direction::Press)?;
|
||||
enigo.key(Key::Shift, Direction::Press)?;
|
||||
enigo.key(Key::Unicode('v'), Direction::Click)?;
|
||||
enigo.key(Key::Shift, Direction::Release)?;
|
||||
enigo.key(Key::Control, Direction::Release)?;
|
||||
}
|
||||
PasteMethod::ClipboardOnly => unreachable!(),
|
||||
}
|
||||
|
||||
// Restore previous clipboard content if needed
|
||||
if let Some(prev) = previous {
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
let _ = clipboard.set_text(prev);
|
||||
debug!("Previous clipboard content restored");
|
||||
}
|
||||
|
||||
info!("Text pasted ({} chars)", text.len());
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user