From 4a7f5e12819c3775fed2ac75534c05181461b82f Mon Sep 17 00:00:00 2001 From: CJ Pais Date: Mon, 17 Feb 2025 11:50:28 -0800 Subject: [PATCH 1/2] Add a little extra padding to avoid some failures. --- src-tauri/src/managers/audio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-tauri/src/managers/audio.rs b/src-tauri/src/managers/audio.rs index 75bfcf3..e274d98 100644 --- a/src-tauri/src/managers/audio.rs +++ b/src-tauri/src/managers/audio.rs @@ -154,7 +154,7 @@ impl AudioRecordingManager { } else { // Pad to minimum 1000ms if needed if duration_ms < 1000.0 { - let target_samples = (16000.0 * (1000.0 / 1000.0)) as usize; // 16000 samples for 1 second + let target_samples = (16400.0 * (1000.0 / 1000.0)) as usize; // 16000 samples for 1 second let mut padded_audio = audio_data; padded_audio.resize(target_samples, 0.0); // Pad with silence (zeros) Some(padded_audio) From b47a89716476fc134a525646895dba79b2c4ab4d Mon Sep 17 00:00:00 2001 From: CJ Pais Date: Mon, 17 Feb 2025 11:51:15 -0800 Subject: [PATCH 2/2] Fixed bindings blowing up. --- src-tauri/src/lib.rs | 26 ++---- src-tauri/src/managers/keybinding.rs | 101 ++++++++++++------------ src-tauri/src/managers/transcription.rs | 1 - 3 files changed, 58 insertions(+), 70 deletions(-) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index c9089dd..cdb9c4c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -20,12 +20,7 @@ fn try_send_event(event: &EventType) { fn send(event: EventType) { try_send_event(&event); - thread::sleep(time::Duration::from_millis(20)); -} - -fn send_multiple(events: &[EventType]) { - events.iter().for_each(try_send_event); - thread::sleep(time::Duration::from_millis(20)); + thread::sleep(time::Duration::from_millis(30)); } fn send_paste() { @@ -39,14 +34,9 @@ fn send_paste() { send(EventType::KeyPress(modifier_key)); send(EventType::KeyPress(Key::KeyV)); - // Release both keys simultaneously - send_multiple(&[ - EventType::KeyRelease(Key::KeyV), - EventType::KeyRelease(modifier_key), - ]); - - // Additional delay after the complete combination - thread::sleep(time::Duration::from_millis(20)); + // Release both keys + send(EventType::KeyRelease(Key::KeyV)); + send(EventType::KeyRelease(modifier_key)); } fn send_copy() { @@ -60,11 +50,9 @@ fn send_copy() { send(EventType::KeyPress(modifier_key)); send(EventType::KeyPress(Key::KeyC)); - // Release both keys simultaneously - send_multiple(&[ - EventType::KeyRelease(Key::KeyC), - EventType::KeyRelease(modifier_key), - ]); + // Release both keys + send(EventType::KeyRelease(Key::KeyC)); + send(EventType::KeyRelease(modifier_key)); } fn paste(text: String, app_handle: tauri::AppHandle) { diff --git a/src-tauri/src/managers/keybinding.rs b/src-tauri/src/managers/keybinding.rs index b61b667..44fcdad 100644 --- a/src-tauri/src/managers/keybinding.rs +++ b/src-tauri/src/managers/keybinding.rs @@ -1,12 +1,11 @@ use super::audio::AudioRecordingManager; use super::transcription::TranscriptionManager; -use rdev::EventType; -use rig::agent::Agent; +use rdev::{EventType, Key}; use rig::providers::anthropic; use std::collections::HashSet; use std::sync::{Arc, Mutex}; -type KeySet = HashSet; +type KeySet = HashSet; #[derive(Clone)] pub struct BindingContext { @@ -25,11 +24,10 @@ pub struct KeyBinding { on_release: Box< dyn Fn(&BindingContext) -> Option> + Send + 'static, >, - currently_pressed: Arc>, } impl KeyBinding { - fn new(id: String, keys: Vec, on_press: F, on_release: G) -> Self + fn new(id: String, keys: Vec, on_press: F, on_release: G) -> Self where F: Fn(&BindingContext) -> Option> + Send + 'static, G: Fn(&BindingContext) -> Option> + Send + 'static, @@ -39,52 +37,14 @@ impl KeyBinding { keys: keys.into_iter().collect(), on_press: Box::new(on_press), on_release: Box::new(on_release), - currently_pressed: Arc::new(Mutex::new(HashSet::new())), } } - - fn handle_event(&self, key: rdev::Key, is_press: bool, context: &BindingContext) -> bool { - let mut pressed = self.currently_pressed.lock().unwrap(); - - if is_press { - if !self.keys.contains(&key) { - return false; // Ignore keys that aren't part of this binding - } - - if pressed.contains(&key) { - return false; - } - - pressed.insert(key); - if pressed.len() == self.keys.len() && pressed.is_subset(&self.keys) { - let _ = (self.on_press)(context); - return true; - } - } else { - // Release event - if !self.keys.contains(&key) { - return false; - } - - if pressed.remove(&key) { - if pressed.len() == self.keys.len() - 1 { - let _ = (self.on_release)(context); - - // Clear the currently_pressed set if all keys are released - if pressed.is_empty() { - pressed.clear(); - } - - return true; - } - } - } - false - } } pub struct KeyBindingManager { bindings: Vec, + global_pressed: Arc>>, + active_bindings: Arc>>, context: BindingContext, } @@ -97,6 +57,8 @@ impl KeyBindingManager { ) -> Self { Self { bindings: Vec::new(), + global_pressed: Arc::new(Mutex::new(HashSet::new())), + active_bindings: Arc::new(Mutex::new(HashSet::new())), context: BindingContext { recording_manager, transcription_manager, @@ -106,7 +68,7 @@ impl KeyBindingManager { } } - pub fn register(&mut self, id: String, keys: Vec, on_press: F, on_release: G) + pub fn register(&mut self, id: String, keys: Vec, on_press: F, on_release: G) where F: Fn(&BindingContext) -> Option> + Send + 'static, G: Fn(&BindingContext) -> Option> + Send + 'static, @@ -117,12 +79,51 @@ impl KeyBindingManager { pub fn handle_event(&self, event: &rdev::Event) { if let EventType::KeyPress(key) | EventType::KeyRelease(key) = event.event_type { - let is_press = matches!(event.event_type, EventType::KeyPress(_)); + let mut is_press = matches!(event.event_type, EventType::KeyPress(_)); - // Only process the first binding that successfully handles the event + // Update global pressed keys + let mut pressed = self.global_pressed.lock().unwrap(); + + // If we get a release event for a key that wasn't pressed, + // treat it as a press event instead + if !is_press && !pressed.contains(&key) { + is_press = true; + } + + if is_press { + pressed.insert(key); + } else { + pressed.remove(&key); + } + let pressed_snapshot = pressed.clone(); + drop(pressed); + + // Check binding states + let mut active = self.active_bindings.lock().unwrap(); for binding in &self.bindings { - if binding.handle_event(key, is_press, &self.context) { - break; // Exit after first successful handling + let is_active = active.contains(&binding.id); + let all_required_pressed = binding.keys.is_subset(&pressed_snapshot); + let any_required_key = binding.keys.contains(&key); + + // Only process if this event is for a key we care about + if any_required_key { + match (all_required_pressed, is_active) { + (true, false) => { + (binding.on_press)(&self.context); + active.insert(binding.id.clone()); + } + (false, true) => { + // Only trigger release if none of the required keys are pressed + let any_binding_key_pressed = + binding.keys.iter().any(|k| pressed_snapshot.contains(k)); + + if !any_binding_key_pressed { + (binding.on_release)(&self.context); + active.remove(&binding.id); + } + } + _ => {} + } } } } diff --git a/src-tauri/src/managers/transcription.rs b/src-tauri/src/managers/transcription.rs index a4114ab..ab90b92 100644 --- a/src-tauri/src/managers/transcription.rs +++ b/src-tauri/src/managers/transcription.rs @@ -63,7 +63,6 @@ impl TranscriptionManager { .full_get_segment_text(i) .expect("failed to get segment"); result.push_str(&segment); - result.push(' '); } let et = std::time::Instant::now();