commit
0376fbe3e2
4 changed files with 59 additions and 71 deletions
|
|
@ -20,12 +20,7 @@ fn try_send_event(event: &EventType) {
|
||||||
|
|
||||||
fn send(event: EventType) {
|
fn send(event: EventType) {
|
||||||
try_send_event(&event);
|
try_send_event(&event);
|
||||||
thread::sleep(time::Duration::from_millis(20));
|
thread::sleep(time::Duration::from_millis(30));
|
||||||
}
|
|
||||||
|
|
||||||
fn send_multiple(events: &[EventType]) {
|
|
||||||
events.iter().for_each(try_send_event);
|
|
||||||
thread::sleep(time::Duration::from_millis(20));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_paste() {
|
fn send_paste() {
|
||||||
|
|
@ -39,14 +34,9 @@ fn send_paste() {
|
||||||
send(EventType::KeyPress(modifier_key));
|
send(EventType::KeyPress(modifier_key));
|
||||||
send(EventType::KeyPress(Key::KeyV));
|
send(EventType::KeyPress(Key::KeyV));
|
||||||
|
|
||||||
// Release both keys simultaneously
|
// Release both keys
|
||||||
send_multiple(&[
|
send(EventType::KeyRelease(Key::KeyV));
|
||||||
EventType::KeyRelease(Key::KeyV),
|
send(EventType::KeyRelease(modifier_key));
|
||||||
EventType::KeyRelease(modifier_key),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Additional delay after the complete combination
|
|
||||||
thread::sleep(time::Duration::from_millis(20));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_copy() {
|
fn send_copy() {
|
||||||
|
|
@ -60,11 +50,9 @@ fn send_copy() {
|
||||||
send(EventType::KeyPress(modifier_key));
|
send(EventType::KeyPress(modifier_key));
|
||||||
send(EventType::KeyPress(Key::KeyC));
|
send(EventType::KeyPress(Key::KeyC));
|
||||||
|
|
||||||
// Release both keys simultaneously
|
// Release both keys
|
||||||
send_multiple(&[
|
send(EventType::KeyRelease(Key::KeyC));
|
||||||
EventType::KeyRelease(Key::KeyC),
|
send(EventType::KeyRelease(modifier_key));
|
||||||
EventType::KeyRelease(modifier_key),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paste(text: String, app_handle: tauri::AppHandle) {
|
fn paste(text: String, app_handle: tauri::AppHandle) {
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ impl AudioRecordingManager {
|
||||||
} else {
|
} else {
|
||||||
// Pad to minimum 1000ms if needed
|
// Pad to minimum 1000ms if needed
|
||||||
if duration_ms < 1000.0 {
|
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;
|
let mut padded_audio = audio_data;
|
||||||
padded_audio.resize(target_samples, 0.0); // Pad with silence (zeros)
|
padded_audio.resize(target_samples, 0.0); // Pad with silence (zeros)
|
||||||
Some(padded_audio)
|
Some(padded_audio)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
use super::audio::AudioRecordingManager;
|
use super::audio::AudioRecordingManager;
|
||||||
use super::transcription::TranscriptionManager;
|
use super::transcription::TranscriptionManager;
|
||||||
use rdev::EventType;
|
use rdev::{EventType, Key};
|
||||||
use rig::agent::Agent;
|
|
||||||
use rig::providers::anthropic;
|
use rig::providers::anthropic;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
type KeySet = HashSet<rdev::Key>;
|
type KeySet = HashSet<Key>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BindingContext {
|
pub struct BindingContext {
|
||||||
|
|
@ -25,11 +24,10 @@ pub struct KeyBinding {
|
||||||
on_release: Box<
|
on_release: Box<
|
||||||
dyn Fn(&BindingContext) -> Option<tauri::async_runtime::JoinHandle<()>> + Send + 'static,
|
dyn Fn(&BindingContext) -> Option<tauri::async_runtime::JoinHandle<()>> + Send + 'static,
|
||||||
>,
|
>,
|
||||||
currently_pressed: Arc<Mutex<KeySet>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyBinding {
|
impl KeyBinding {
|
||||||
fn new<F, G>(id: String, keys: Vec<rdev::Key>, on_press: F, on_release: G) -> Self
|
fn new<F, G>(id: String, keys: Vec<Key>, on_press: F, on_release: G) -> Self
|
||||||
where
|
where
|
||||||
F: Fn(&BindingContext) -> Option<tauri::async_runtime::JoinHandle<()>> + Send + 'static,
|
F: Fn(&BindingContext) -> Option<tauri::async_runtime::JoinHandle<()>> + Send + 'static,
|
||||||
G: Fn(&BindingContext) -> Option<tauri::async_runtime::JoinHandle<()>> + Send + 'static,
|
G: Fn(&BindingContext) -> Option<tauri::async_runtime::JoinHandle<()>> + Send + 'static,
|
||||||
|
|
@ -39,52 +37,14 @@ impl KeyBinding {
|
||||||
keys: keys.into_iter().collect(),
|
keys: keys.into_iter().collect(),
|
||||||
on_press: Box::new(on_press),
|
on_press: Box::new(on_press),
|
||||||
on_release: Box::new(on_release),
|
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 {
|
pub struct KeyBindingManager {
|
||||||
bindings: Vec<KeyBinding>,
|
bindings: Vec<KeyBinding>,
|
||||||
|
global_pressed: Arc<Mutex<HashSet<Key>>>,
|
||||||
|
active_bindings: Arc<Mutex<HashSet<String>>>,
|
||||||
context: BindingContext,
|
context: BindingContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,6 +57,8 @@ impl KeyBindingManager {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bindings: Vec::new(),
|
bindings: Vec::new(),
|
||||||
|
global_pressed: Arc::new(Mutex::new(HashSet::new())),
|
||||||
|
active_bindings: Arc::new(Mutex::new(HashSet::new())),
|
||||||
context: BindingContext {
|
context: BindingContext {
|
||||||
recording_manager,
|
recording_manager,
|
||||||
transcription_manager,
|
transcription_manager,
|
||||||
|
|
@ -106,7 +68,7 @@ impl KeyBindingManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register<F, G>(&mut self, id: String, keys: Vec<rdev::Key>, on_press: F, on_release: G)
|
pub fn register<F, G>(&mut self, id: String, keys: Vec<Key>, on_press: F, on_release: G)
|
||||||
where
|
where
|
||||||
F: Fn(&BindingContext) -> Option<tauri::async_runtime::JoinHandle<()>> + Send + 'static,
|
F: Fn(&BindingContext) -> Option<tauri::async_runtime::JoinHandle<()>> + Send + 'static,
|
||||||
G: Fn(&BindingContext) -> Option<tauri::async_runtime::JoinHandle<()>> + Send + 'static,
|
G: Fn(&BindingContext) -> Option<tauri::async_runtime::JoinHandle<()>> + Send + 'static,
|
||||||
|
|
@ -117,12 +79,51 @@ impl KeyBindingManager {
|
||||||
|
|
||||||
pub fn handle_event(&self, event: &rdev::Event) {
|
pub fn handle_event(&self, event: &rdev::Event) {
|
||||||
if let EventType::KeyPress(key) | EventType::KeyRelease(key) = event.event_type {
|
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 {
|
for binding in &self.bindings {
|
||||||
if binding.handle_event(key, is_press, &self.context) {
|
let is_active = active.contains(&binding.id);
|
||||||
break; // Exit after first successful handling
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,6 @@ impl TranscriptionManager {
|
||||||
.full_get_segment_text(i)
|
.full_get_segment_text(i)
|
||||||
.expect("failed to get segment");
|
.expect("failed to get segment");
|
||||||
result.push_str(&segment);
|
result.push_str(&segment);
|
||||||
result.push(' ');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let et = std::time::Instant::now();
|
let et = std::time::Instant::now();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue