Add input device selection to interactive config TUI
Enumerates available audio input devices via cpal and presents them in a dropdown, with "System default" as the first option. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use cpal::traits::{DeviceTrait, HostTrait};
|
||||||
use dialoguer::{Input, Select};
|
use dialoguer::{Input, Select};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@@ -105,6 +106,8 @@ pub fn interactive() -> Result<()> {
|
|||||||
.interact()?;
|
.interact()?;
|
||||||
config.audio_feedback = feedback_idx == 0;
|
config.audio_feedback = feedback_idx == 0;
|
||||||
|
|
||||||
|
config.input_device = prompt_input_device(config.input_device.as_deref())?;
|
||||||
|
|
||||||
let vad_idx = Select::new()
|
let vad_idx = Select::new()
|
||||||
.with_prompt("VAD (voice activity detection)")
|
.with_prompt("VAD (voice activity detection)")
|
||||||
.items(&["enabled", "disabled"])
|
.items(&["enabled", "disabled"])
|
||||||
@@ -122,6 +125,52 @@ pub fn interactive() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prompt the user to select an audio input device from available devices.
|
||||||
|
fn prompt_input_device(current: Option<&str>) -> Result<Option<String>> {
|
||||||
|
let current_label = current.unwrap_or("system default");
|
||||||
|
|
||||||
|
let host = cpal::default_host();
|
||||||
|
let mut device_names: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
if let Ok(devices) = host.input_devices() {
|
||||||
|
for device in devices {
|
||||||
|
if let Ok(name) = device.name() {
|
||||||
|
device_names.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build selection list: "System default" first, then each detected device
|
||||||
|
let mut items: Vec<String> = vec!["System default".to_string()];
|
||||||
|
for name in &device_names {
|
||||||
|
items.push(name.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the default selection index
|
||||||
|
let default_idx = if let Some(cur) = current {
|
||||||
|
let cur_lower = cur.to_lowercase();
|
||||||
|
device_names
|
||||||
|
.iter()
|
||||||
|
.position(|n| n.to_lowercase().contains(&cur_lower))
|
||||||
|
.map(|i| i + 1) // offset by 1 for "System default"
|
||||||
|
.unwrap_or(0)
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
let sel = Select::new()
|
||||||
|
.with_prompt(format!("Input device (current: {current_label})"))
|
||||||
|
.items(&items)
|
||||||
|
.default(default_idx)
|
||||||
|
.interact()?;
|
||||||
|
|
||||||
|
if sel == 0 {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Ok(Some(device_names[sel - 1].clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Prompt the user to either press a key combination or type it manually.
|
/// Prompt the user to either press a key combination or type it manually.
|
||||||
fn prompt_hotkey(label: &str, current: &str) -> Result<String> {
|
fn prompt_hotkey(label: &str, current: &str) -> Result<String> {
|
||||||
let choice = Select::new()
|
let choice = Select::new()
|
||||||
|
|||||||
Reference in New Issue
Block a user