use std::time::Duration; use clap::{Arg, ArgAction, Command}; use hyper_headset::{ devices::{connect_compatible_device, Device, DeviceError, DeviceEvent}, VERBOSE, }; const SHOW_ALL_OPTIONS: bool = false; /// helper function to enable help messages fn device_supports(device: &Result, DeviceError>, f: F) -> bool where F: FnOnce(&Box) -> bool, { device.as_ref().map(f).unwrap_or(false) } 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")] { use hyper_headset::act_as_askpass_handler; use hyper_headset::prompt_user_for_udev_rule; if let Ok(name) = std::env::current_exe() { if let Some(name) = name.to_str() { if let Ok(askpass) = std::env::var("SUDO_ASKPASS") { if name == askpass { act_as_askpass_handler(); } } } } prompt_user_for_udev_rule(); } let device = connect_compatible_device(); let matches = Command::new(env!("CARGO_PKG_NAME")) .version(env!("CARGO_PKG_VERSION")) .disable_version_flag(false) .author(env!("CARGO_PKG_AUTHORS")) .about("A CLI application for monitoring and managing HyperX headsets.") .after_help("Help only lists commands supported by this headset.") .arg( Arg::new("automatic_shutdown") .long("automatic_shutdown") .required(false) .help( "Set the delay in minutes after which the headset will automatically shutdown.\n0 will disable automatic shutdown.", ) .hide(!SHOW_ALL_OPTIONS && !device_supports(&device, |d| d.can_set_automatic_shutdown())) .value_parser(clap::value_parser!(u8)), ) .arg( Arg::new("mute") .long("mute") .required(false) .help("Mute or unmute the headset.") .hide(!SHOW_ALL_OPTIONS && !device_supports(&device, |d| d.can_set_mute())) .value_parser(clap::value_parser!(bool)), ) .arg( Arg::new("enable_side_tone") .long("enable_side_tone") .required(false) .help("Enable or disable side tone.") .hide(!SHOW_ALL_OPTIONS && !device_supports(&device, |d| d.can_set_side_tone())) .value_parser(clap::value_parser!(bool)), ) .arg( Arg::new("side_tone_volume") .long("side_tone_volume") .required(false) .help("Set the side tone volume.") .hide(!SHOW_ALL_OPTIONS && !device_supports(&device, |d| d.can_set_side_tone_volume())) .value_parser(clap::value_parser!(u8)), ) .arg( Arg::new("enable_voice_prompt") .long("enable_voice_prompt") .required(false) .help("Enable voice prompt. This may not be supported on your device.") .hide(!SHOW_ALL_OPTIONS && !device_supports(&device, |d| d.can_set_voice_prompt())) .value_parser(clap::value_parser!(bool)), ) .arg( Arg::new("surround_sound") .long("surround_sound") .required(false) .help("Enables surround sound. This may be on by default and cannot be changed on your device.") .hide(!SHOW_ALL_OPTIONS && !device_supports(&device, |d| d.can_set_surround_sound())) .value_parser(clap::value_parser!(bool)), ) .arg( Arg::new("mute_playback") .long("mute_playback") .required(false) .help("Mute or unmute playback.") .hide(!SHOW_ALL_OPTIONS && !device_supports(&device, |d| d.can_set_silent_mode())) .value_parser(clap::value_parser!(bool)), ) .arg( Arg::new("activate_noise_gate") .long("activate_noise_gate") .required(false) .help("Activates noise gate.") .hide(!SHOW_ALL_OPTIONS && !device_supports(&device, |d| d.can_set_silent_mode())) .value_parser(clap::value_parser!(bool)), ) .arg( Arg::new("verbose") .long("verbose") .short('v') .action(ArgAction::SetTrue) .required(false) .help("Use verbose output "), ) .arg( Arg::new("json") .long("json") .default_value("false") .action(ArgAction::SetTrue) .required(false) .help("Use JSON output. Time is in seconds."), ) .get_matches(); let mut device = match device { Ok(device) => device, Err(e) => { eprintln!("{e}"); std::process::exit(1) } }; let mut commands = Vec::new(); if let Some(delay) = matches.get_one::("automatic_shutdown") { let delay = *delay as u64; commands.push(DeviceEvent::AutomaticShutdownAfter(Duration::from_secs( delay * 60u64, ))); } if let Some(mute) = matches.get_one::("mute") { commands.push(DeviceEvent::Muted(*mute)); } if let Some(enable) = matches.get_one::("enable_side_tone") { commands.push(DeviceEvent::SideToneOn(*enable)); } if let Some(volume) = matches.get_one::("side_tone_volume") { commands.push(DeviceEvent::SideToneVolume(*volume)); } if let Some(enable) = matches.get_one::("enable_voice_prompt") { commands.push(DeviceEvent::VoicePrompt(*enable)); } if let Some(surround_sound) = matches.get_one::("surround_sound") { commands.push(DeviceEvent::SurroundSound(*surround_sound)); } if let Some(mute_playback) = matches.get_one::("mute_playback") { commands.push(DeviceEvent::Silent(*mute_playback)); } if let Some(activate) = matches.get_one::("activate_noise_gate") { commands.push(DeviceEvent::NoiseGateActive(*activate)); } for command in commands { if let Err(e) = device.try_apply(command) { eprintln!("{e}"); std::process::exit(1); } } std::thread::sleep(Duration::from_secs_f64(0.5)); // setting an option may cause a response form the headset if device.allow_passive_refresh() { if let Err(error) = device.passive_refresh_state() { eprintln!("{error}"); std::process::exit(1); }; } if let Err(error) = device.active_refresh_state() { eprintln!("{error}"); std::process::exit(1); }; if let Some(output_json) = matches.get_one::("json") { if *output_json { let properties = &device.get_device_state().device_properties; let mut headset_info_json = "{\n ".to_string(); let json_properties: Vec = properties .get_properties() .iter() .map(|property| match property { hyper_headset::devices::PropertyDescriptorWrapper::Int( property_descriptor, _items, ) => match property_descriptor.data { Some(data) => format!(" \"{}\": {},\n", property_descriptor.name, data), _ => "".to_string(), }, hyper_headset::devices::PropertyDescriptorWrapper::Bool( property_descriptor, ) => match property_descriptor.data { Some(data) => format!(" \"{}\": {},\n", property_descriptor.name, data), _ => "".to_string(), }, hyper_headset::devices::PropertyDescriptorWrapper::String( property_descriptor, ) => match &property_descriptor.data { Some(data) => { format!("\"{}\": \"{}\"", property_descriptor.name, data) } _ => "".to_string(), }, }) .collect(); headset_info_json += &json_properties.join(",\n "); headset_info_json += "\n}"; println!("{}", headset_info_json); } else { println!("{}", device.get_device_state().device_properties); } } else { println!("{}", device.get_device_state().device_properties); } }