Conversation
- Create linux.rs platform module (rdev hotkey + ydotool/xdotool paste + full pipeline) - Wire up hotkey.rs to export from linux module on Linux - Update paste.rs for Linux (arboard clipboard + ydotool Ctrl+V) - Update appctx.rs for Linux frontmost-app detection via xdotool - Update local_llm.rs with XDG-compliant paths on Linux - Update lib.rs with Linux permission stubs and xdg-open - Add rdev dependency for global keyboard listening - Update tauri.conf.json for Linux bundle targets - Fix whisper-rs to v0.16 for working Linux build
- Add push_to_talk_key field to whimpr_core::Settings (default ControlRight) - Linux: use configured key from settings in rdev keyboard listener - Parse key string to rdev::Key with Alt/AltGr/Shift/Ctrl/Meta/CapsLock/F1-F12 - Add key picker UI in Settings pane with 21 key options - Human-readable key labels in startup log messages
AnttonioAzevedo
left a comment
There was a problem hiding this comment.
Linux support looks solid overall, but flagging two real functional bugs (PTT race condition orphaning the mic capture handle, and a silent fallback in parse_ptt_key that contradicts its own doc comment) plus two duplication/architecture cleanups (reusing foreground_app() instead of re-implementing it, and migrating onto the shared whimpr_core::StateMachine instead of hand-rolled recording state — which would also incidentally fix the race).
| let _ = now_ms(); | ||
| eprintln!("[whimpr:linux] PTT DOWN — starting capture"); | ||
| emit_bar("recording"); | ||
| std::thread::spawn(|| match whimpr_audio::start(|_: &[f32]| {}) { |
There was a problem hiding this comment.
Race condition: PTT-down opens the mic on a spawned thread and only stores the CaptureHandle into CAPTURE after whimpr_audio::start() succeeds. If PTT-up fires before that thread finishes, on_ptt_up()'s take() returns None (nothing to stop), and the spawned thread then writes Some(handle) into CAPTURE afterward — orphaned and never stopped. The mic stays open indefinitely, and the next PTT cycle's take() grabs this stale handle instead of the new one.
This happens on a normal quick tap of the PTT key, not just under artificial load — worth fixing before merge (e.g. by registering the handle synchronously before spawning, or by having PTT-up cancel a still-in-flight open).
| "F10" => Some(F10), | ||
| "F11" => Some(F11), | ||
| "F12" => Some(F12), | ||
| _ => { |
There was a problem hiding this comment.
parse_ptt_key's doc comment says it "Returns None for unrecognized keys," but the fallback arm here returns Some(ControlRight) instead — silently substituting a different key. This makes the "invalid push-to-talk key" error branch in spawn_keyboard_listener (lines ~369-372) dead code.
If settings.json ever gets a bad/corrupted push_to_talk_key value, the listener will silently bind to Right Ctrl instead of surfacing an error, and the user has no way to discover their configured key was ignored. Please make the fallback actually return None per the doc comment.
|
|
||
| // ── The push-to-talk pipeline ─────────────────────────────────────────────────── | ||
|
|
||
| fn on_ptt_down() { |
There was a problem hiding this comment.
The Linux platform hand-rolls its own recording state (a bare AtomicBool plus a raw OnceLock<Mutex<Option<CaptureHandle>>>) instead of reusing whimpr_core::StateMachine, which the macOS implementation (src-tauri/src/hotkey.rs) already uses to manage the same recording/transcribing/done/idle lifecycle.
This ad hoc state is the direct cause of the orphaned-capture race flagged above — the shared StateMachine was presumably built to avoid exactly this class of bug. Any lifecycle fix made to StateMachine won't benefit Linux, and bugs specific to this duplicate implementation have to be found and fixed twice. Recommend migrating Linux onto StateMachine rather than maintaining a parallel state model.
| #[cfg(target_os = "linux")] | ||
| pub fn frontmost_bundle_id() -> Option<String> { | ||
| // Try xdotool first (most reliable on X11) | ||
| if let Ok(out) = std::process::Command::new("xdotool") |
There was a problem hiding this comment.
frontmost_bundle_id() re-implements the same xdotool getactivewindow / getwindowclassname logic that already exists as foreground_app() in src-tauri/src/linux.rs (~lines 99-111), instead of calling that helper.
Two independent copies of the xdotool-invocation logic now exist — a future fix to one (e.g. the xprop fallback linux.rs already has) won't be applied to the other, so frontmost-app detection will silently diverge between call sites. Worth extracting/reusing the existing helper instead of duplicating it.
Summary
Adds full Linux platform support to WhimprFlow, plus a configurable push-to-talk key setting.
Linux Support
src-tauri/src/linux.rs— full dictation pipeline:rdev(X11 + Wayland) for push-to-talkydotool(Wayland) /xdotool(X11 fallback)~/.local/share/WhimprFlow/)hotkey.rs,lib.rs,paste.rs,appctx.rs,local_llm.rsall updated with Linux cfg branchesrdevfor global keyboard, shell-out to ydotool/xdotool for paste (no C library deps)Configurable Push-to-Talk Key
push_to_talk_keyfield inSettings(default:ControlRight)Tested
cargo check+cargo buildpass cleanly on Arch Linux (Wayland)