Add verbose flag and improve argument handling in CLI

This commit is contained in:
Lennard Kittner
2026-05-03 17:58:57 +02:00
parent 37b7b77337
commit 8f70c6df34
4 changed files with 105 additions and 18 deletions

View File

@@ -146,6 +146,8 @@ Options:
Mute or unmute playback. [possible values: true, false] Mute or unmute playback. [possible values: true, false]
--activate_noise_gate <activate_noise_gate> --activate_noise_gate <activate_noise_gate>
Activates noise gate. [possible values: true, false] Activates noise gate. [possible values: true, false]
-v, --verbose
Use verbose output
-h, --help -h, --help
Print help Print help
-V, --version -V, --version
@@ -166,6 +168,8 @@ Options:
Set the refresh interval (in seconds) [default: 3] Set the refresh interval (in seconds) [default: 3]
--press_mute_key <press_mute_key> --press_mute_key <press_mute_key>
The app will simulate pressing the microphone mute key whoever the headsets is muted or unmuted. [default: true] [possible values: true, false] The app will simulate pressing the microphone mute key whoever the headsets is muted or unmuted. [default: true] [possible values: true, false]
-v, --verbose
Use verbose output
-h, --help -h, --help
Print help Print help
-V, --version -V, --version

View File

@@ -1,11 +1,51 @@
use std::time::Duration; use std::time::Duration;
use clap::{Arg, Command}; use clap::{Arg, ArgAction, Command};
use hyper_headset::devices::{connect_compatible_device, DeviceEvent}; use hyper_headset::{
devices::{connect_compatible_device, Device, DeviceError, DeviceEvent},
VERBOSE,
};
const SHOW_ALL_OPTIONS: bool = false; const SHOW_ALL_OPTIONS: bool = false;
/// helper function to enable help messages
fn device_supports<F>(device: &Result<Box<dyn Device>, DeviceError>, f: F) -> bool
where
F: FnOnce(&Box<dyn Device>) -> bool,
{
device.as_ref().map(f).unwrap_or(false)
}
fn main() { fn main() {
let pre = Command::new(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION"))
.disable_version_flag(true) // we have to implement version manually
.disable_help_flag(true)
.arg(
Arg::new("verbose")
.long("verbose")
.short('v')
.action(ArgAction::SetTrue)
.required(false)
.help("Use verbose output "),
)
.arg(
Arg::new("version")
.long("version")
.short('V')
.action(ArgAction::SetTrue),
)
.allow_external_subcommands(true)
.try_get_matches();
if let Ok(pre) = pre {
VERBOSE.set(pre.get_flag("verbose")).unwrap();
if pre.get_flag("version") {
println!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
return;
}
}
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
use hyper_headset::act_as_askpass_handler; use hyper_headset::act_as_askpass_handler;
@@ -22,16 +62,12 @@ fn main() {
} }
prompt_user_for_udev_rule(); prompt_user_for_udev_rule();
} }
let mut device = match connect_compatible_device() {
Ok(device) => device, let device = connect_compatible_device();
Err(error) => {
eprintln!("{error}");
std::process::exit(1);
}
};
let matches = Command::new(env!("CARGO_PKG_NAME")) let matches = Command::new(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION")) .version(env!("CARGO_PKG_VERSION"))
.disable_version_flag(false)
.author(env!("CARGO_PKG_AUTHORS")) .author(env!("CARGO_PKG_AUTHORS"))
.about("A CLI application for monitoring and managing HyperX headsets.") .about("A CLI application for monitoring and managing HyperX headsets.")
.after_help("Help only lists commands supported by this headset.") .after_help("Help only lists commands supported by this headset.")
@@ -43,7 +79,7 @@ fn main() {
"Set the delay in minutes after which the headset will automatically shutdown.\n0 will disable automatic shutdown.", "Set the delay in minutes after which the headset will automatically shutdown.\n0 will disable automatic shutdown.",
) )
.hide(!SHOW_ALL_OPTIONS .hide(!SHOW_ALL_OPTIONS
&& !device.can_set_automatic_shutdown()) && !device_supports(&device, |d| d.can_set_automatic_shutdown()))
.value_parser(clap::value_parser!(u8)), .value_parser(clap::value_parser!(u8)),
) )
.arg( .arg(
@@ -52,7 +88,7 @@ fn main() {
.required(false) .required(false)
.help("Mute or unmute the headset.") .help("Mute or unmute the headset.")
.hide(!SHOW_ALL_OPTIONS .hide(!SHOW_ALL_OPTIONS
&& !device.can_set_mute()) && !device_supports(&device, |d| d.can_set_mute()))
.value_parser(clap::value_parser!(bool)), .value_parser(clap::value_parser!(bool)),
) )
.arg( .arg(
@@ -61,7 +97,7 @@ fn main() {
.required(false) .required(false)
.help("Enable or disable side tone.") .help("Enable or disable side tone.")
.hide(!SHOW_ALL_OPTIONS .hide(!SHOW_ALL_OPTIONS
&& !device.can_set_side_tone()) && !device_supports(&device, |d| d.can_set_side_tone()))
.value_parser(clap::value_parser!(bool)), .value_parser(clap::value_parser!(bool)),
) )
.arg( .arg(
@@ -70,7 +106,7 @@ fn main() {
.required(false) .required(false)
.help("Set the side tone volume.") .help("Set the side tone volume.")
.hide(!SHOW_ALL_OPTIONS .hide(!SHOW_ALL_OPTIONS
&& !device.can_set_side_tone_volume()) && !device_supports(&device, |d| d.can_set_side_tone_volume()))
.value_parser(clap::value_parser!(u8)), .value_parser(clap::value_parser!(u8)),
) )
.arg( .arg(
@@ -79,7 +115,7 @@ fn main() {
.required(false) .required(false)
.help("Enable voice prompt. This may not be supported on your device.") .help("Enable voice prompt. This may not be supported on your device.")
.hide(!SHOW_ALL_OPTIONS .hide(!SHOW_ALL_OPTIONS
&& !device.can_set_voice_prompt()) && !device_supports(&device, |d| d.can_set_voice_prompt()))
.value_parser(clap::value_parser!(bool)), .value_parser(clap::value_parser!(bool)),
) )
.arg( .arg(
@@ -88,7 +124,7 @@ fn main() {
.required(false) .required(false)
.help("Enables surround sound. This may be on by default and cannot be changed on your device.") .help("Enables surround sound. This may be on by default and cannot be changed on your device.")
.hide(!SHOW_ALL_OPTIONS .hide(!SHOW_ALL_OPTIONS
&& !device.can_set_surround_sound()) && !device_supports(&device, |d| d.can_set_surround_sound()))
.value_parser(clap::value_parser!(bool)), .value_parser(clap::value_parser!(bool)),
) )
.arg( .arg(
@@ -97,7 +133,7 @@ fn main() {
.required(false) .required(false)
.help("Mute or unmute playback.") .help("Mute or unmute playback.")
.hide(!SHOW_ALL_OPTIONS .hide(!SHOW_ALL_OPTIONS
&& !device.can_set_silent_mode()) && !device_supports(&device, |d| d.can_set_silent_mode()))
.value_parser(clap::value_parser!(bool)), .value_parser(clap::value_parser!(bool)),
) )
.arg( .arg(
@@ -106,11 +142,27 @@ fn main() {
.required(false) .required(false)
.help("Activates noise gate.") .help("Activates noise gate.")
.hide(!SHOW_ALL_OPTIONS .hide(!SHOW_ALL_OPTIONS
&& !device.can_set_silent_mode()) && !device_supports(&device, |d| d.can_set_silent_mode()))
.value_parser(clap::value_parser!(bool)), .value_parser(clap::value_parser!(bool)),
) )
.arg(
Arg::new("verbose")
.long("verbose")
.short('v')
.action(ArgAction::SetTrue)
.required(false)
.help("Use verbose output "),
)
.get_matches(); .get_matches();
let mut device = match device {
Ok(device) => device,
Err(e) => {
eprintln!("{e}");
std::process::exit(1)
}
};
let mut commands = Vec::new(); let mut commands = Vec::new();
if let Some(delay) = matches.get_one::<u8>("automatic_shutdown") { if let Some(delay) = matches.get_one::<u8>("automatic_shutdown") {
let delay = *delay as u64; let delay = *delay as u64;

View File

@@ -1,3 +1,4 @@
use std::sync::OnceLock;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use std::{fs, io, process::Command, time::Duration}; use std::{fs, io, process::Command, time::Duration};
@@ -7,11 +8,18 @@ use dialog::{Choice, DialogBox};
// #![warn(missing_docs)] // #![warn(missing_docs)]
pub mod devices; pub mod devices;
pub static VERBOSE: OnceLock<bool> = OnceLock::new();
#[macro_export] #[macro_export]
macro_rules! debug_println { macro_rules! debug_println {
($($args:tt)*) => { ($($args:tt)*) => {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!($($args)*); println!($($args)*);
#[cfg(not(debug_assertions))]
if *$crate::VERBOSE.get().unwrap_or(&false) {
println!($($args)*);
}
}; };
} }

View File

@@ -10,9 +10,11 @@ mod tray_battery_icon_state;
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))]
fn main() { fn main() {
use clap::ArgAction;
use std::sync::mpsc; use std::sync::mpsc;
use hyper_headset::devices::{DeviceEvent, DeviceProperties}; use hyper_headset::devices::{DeviceEvent, DeviceProperties};
use hyper_headset::VERBOSE;
use winit::event_loop::{ControlFlow, EventLoop, EventLoopProxy}; use winit::event_loop::{ControlFlow, EventLoop, EventLoopProxy};
use crate::status_tray_not_linux::TrayApp; use crate::status_tray_not_linux::TrayApp;
@@ -34,6 +36,7 @@ fn main() {
let matches = Command::new(env!("CARGO_PKG_NAME")) let matches = Command::new(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION")) .version(env!("CARGO_PKG_VERSION"))
.disable_version_flag(false)
.author(env!("CARGO_PKG_AUTHORS")) .author(env!("CARGO_PKG_AUTHORS"))
.about("A tray application for monitoring HyperX headsets.") .about("A tray application for monitoring HyperX headsets.")
.arg( .arg(
@@ -52,8 +55,17 @@ fn main() {
.default_value("true") .default_value("true")
.value_parser(clap::value_parser!(bool)), .value_parser(clap::value_parser!(bool)),
) )
.arg(Arg::new("verbose")
.long("verbose")
.short('v')
.action(ArgAction::SetTrue)
.required(false)
.help("Use verbose output ")
)
.get_matches(); .get_matches();
VERBOSE.set(matches.get_flag("verbose")).unwrap();
let press_mute_key = *matches.get_one::<bool>("press_mute_key").unwrap_or(&true); let press_mute_key = *matches.get_one::<bool>("press_mute_key").unwrap_or(&true);
let mut enigo = if press_mute_key { let mut enigo = if press_mute_key {
match Enigo::new(&Settings::default()) { match Enigo::new(&Settings::default()) {
@@ -128,6 +140,7 @@ fn main() {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn main() { fn main() {
use clap::ArgAction;
use clap::{Arg, Command}; use clap::{Arg, Command};
use enigo::{Direction, Enigo, Key, Keyboard, Settings}; use enigo::{Direction, Enigo, Key, Keyboard, Settings};
use std::sync::mpsc; use std::sync::mpsc;
@@ -136,8 +149,8 @@ fn main() {
use hyper_headset::devices::connect_compatible_device; use hyper_headset::devices::connect_compatible_device;
use status_tray::{StatusTray, TrayHandler}; use status_tray::{StatusTray, TrayHandler};
use hyper_headset::act_as_askpass_handler;
use hyper_headset::prompt_user_for_udev_rule; use hyper_headset::prompt_user_for_udev_rule;
use hyper_headset::{act_as_askpass_handler, VERBOSE};
if let Ok(name) = std::env::current_exe() { if let Ok(name) = std::env::current_exe() {
if let Some(name) = name.to_str() { if let Some(name) = name.to_str() {
@@ -151,6 +164,7 @@ fn main() {
prompt_user_for_udev_rule(); prompt_user_for_udev_rule();
let matches = Command::new(env!("CARGO_PKG_NAME")) let matches = Command::new(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION")) .version(env!("CARGO_PKG_VERSION"))
.disable_version_flag(false)
.author(env!("CARGO_PKG_AUTHORS")) .author(env!("CARGO_PKG_AUTHORS"))
.about("A tray application for monitoring HyperX headsets.") .about("A tray application for monitoring HyperX headsets.")
.arg( .arg(
@@ -169,6 +183,13 @@ fn main() {
.default_value("true") .default_value("true")
.value_parser(clap::value_parser!(bool)), .value_parser(clap::value_parser!(bool)),
) )
.arg(Arg::new("verbose")
.long("verbose")
.short('v')
.action(ArgAction::SetTrue)
.required(false)
.help("Use verbose output ")
)
.get_matches(); .get_matches();
let press_mute_key = *matches.get_one::<bool>("press_mute_key").unwrap_or(&true); let press_mute_key = *matches.get_one::<bool>("press_mute_key").unwrap_or(&true);
@@ -183,6 +204,8 @@ fn main() {
} else { } else {
None None
}; };
VERBOSE.set(matches.get_flag("verbose")).unwrap();
let refresh_interval = *matches.get_one::<u64>("refresh_interval").unwrap_or(&3); let refresh_interval = *matches.get_one::<u64>("refresh_interval").unwrap_or(&3);
let refresh_interval = Duration::from_secs(refresh_interval); let refresh_interval = Duration::from_secs(refresh_interval);
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();