265 lines
9.4 KiB
Rust
265 lines
9.4 KiB
Rust
#![cfg_attr(target_os = "windows", windows_subsystem = "windows")]
|
|
|
|
#[cfg(target_os = "linux")]
|
|
mod status_tray;
|
|
|
|
#[cfg(not(target_os = "linux"))]
|
|
mod status_tray_not_linux;
|
|
|
|
mod tray_battery_icon_state;
|
|
|
|
#[cfg(not(target_os = "linux"))]
|
|
fn main() {
|
|
use clap::ArgAction;
|
|
use std::sync::mpsc;
|
|
|
|
use hyper_headset::devices::{DeviceEvent, DeviceProperties};
|
|
use hyper_headset::VERBOSE;
|
|
use winit::event_loop::{ControlFlow, EventLoop, EventLoopProxy};
|
|
|
|
use crate::status_tray_not_linux::TrayApp;
|
|
|
|
let event_loop: EventLoop<Option<DeviceProperties>> =
|
|
EventLoop::with_user_event().build().unwrap();
|
|
let proxy: EventLoopProxy<Option<DeviceProperties>> = event_loop.create_proxy();
|
|
event_loop.set_control_flow(ControlFlow::Wait);
|
|
|
|
let (tx, rx) = mpsc::channel::<DeviceEvent>();
|
|
|
|
std::thread::spawn(move || {
|
|
use std::time::Duration;
|
|
|
|
use clap::{Arg, Command};
|
|
use enigo::{Direction, Enigo, Key, Keyboard, Settings};
|
|
|
|
use hyper_headset::devices::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 tray application for monitoring HyperX headsets.")
|
|
.arg(
|
|
Arg::new("refresh_interval")
|
|
.long("refresh_interval")
|
|
.required(false)
|
|
.help("Set the refresh interval (in seconds)")
|
|
.default_value("3")
|
|
.value_parser(clap::value_parser!(u64)),
|
|
)
|
|
.arg(
|
|
Arg::new("press_mute_key")
|
|
.long("press_mute_key")
|
|
.required(false)
|
|
.help("The app will simulate pressing the microphone mute key whoever the headsets is muted or unmuted.")
|
|
.default_value("true")
|
|
.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();
|
|
|
|
VERBOSE.set(matches.get_flag("verbose")).unwrap();
|
|
|
|
let press_mute_key = *matches.get_one::<bool>("press_mute_key").unwrap_or(&true);
|
|
let mut enigo = if press_mute_key {
|
|
match Enigo::new(&Settings::default()) {
|
|
Ok(enigo) => Some(enigo),
|
|
Err(e) => {
|
|
eprintln!("Virtual mute key failed to initialize: {e}");
|
|
None
|
|
}
|
|
}
|
|
} else {
|
|
None
|
|
};
|
|
let refresh_interval = *matches.get_one::<u64>("refresh_interval").unwrap_or(&3);
|
|
let refresh_interval = Duration::from_secs(refresh_interval);
|
|
|
|
loop {
|
|
let mut device = loop {
|
|
match connect_compatible_device() {
|
|
Ok(d) => break d,
|
|
Err(e) => {
|
|
let _ = proxy.send_event(None);
|
|
eprintln!("Connecting failed with error: {e}")
|
|
}
|
|
}
|
|
std::thread::sleep(Duration::from_secs(1));
|
|
};
|
|
|
|
// Run loop
|
|
let mut run_counter = 0;
|
|
loop {
|
|
let mute_state = device.get_device_state().device_properties.muted;
|
|
match if run_counter % 30 == 0 {
|
|
device.active_refresh_state()
|
|
} else {
|
|
device.passive_refresh_state()
|
|
} {
|
|
Ok(()) => (),
|
|
Err(error) => {
|
|
eprintln!("{error}");
|
|
let _ = proxy
|
|
.send_event(Some(device.get_device_state().device_properties.clone()));
|
|
break; // try to reconnect
|
|
}
|
|
};
|
|
if mute_state.is_some()
|
|
&& mute_state != device.get_device_state().device_properties.muted
|
|
{
|
|
if let Some(enigo) = &mut enigo {
|
|
if let Err(e) = enigo.key(Key::F20, Direction::Click) {
|
|
eprintln!("Failed to press key on mute: {e}");
|
|
}
|
|
}
|
|
}
|
|
|
|
// with the default refresh_interval the state is only actively queried every 3min
|
|
// querying the device to frequently can lead to instability
|
|
let first = rx.recv_timeout(refresh_interval);
|
|
for command in first.into_iter().chain(rx.try_iter()) {
|
|
let _ = device.try_apply(command);
|
|
std::thread::sleep(hyper_headset::devices::RESPONSE_DELAY);
|
|
let _ = device.active_refresh_state();
|
|
}
|
|
|
|
let _ = proxy.send_event(Some(device.get_device_state().device_properties.clone()));
|
|
run_counter += 1;
|
|
}
|
|
}
|
|
});
|
|
|
|
event_loop.run_app(&mut TrayApp::new(tx)).unwrap();
|
|
}
|
|
|
|
#[cfg(target_os = "linux")]
|
|
fn main() {
|
|
use clap::ArgAction;
|
|
use clap::{Arg, Command};
|
|
use enigo::{Direction, Enigo, Key, Keyboard, Settings};
|
|
use std::sync::mpsc;
|
|
use std::time::Duration;
|
|
|
|
use hyper_headset::devices::connect_compatible_device;
|
|
use status_tray::{StatusTray, TrayHandler};
|
|
|
|
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 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 matches = Command::new(env!("CARGO_PKG_NAME"))
|
|
.version(env!("CARGO_PKG_VERSION"))
|
|
.disable_version_flag(false)
|
|
.author(env!("CARGO_PKG_AUTHORS"))
|
|
.about("A tray application for monitoring HyperX headsets.")
|
|
.arg(
|
|
Arg::new("refresh_interval")
|
|
.long("refresh_interval")
|
|
.required(false)
|
|
.help("Set the refresh interval (in seconds)")
|
|
.default_value("3")
|
|
.value_parser(clap::value_parser!(u64)),
|
|
)
|
|
.arg(
|
|
Arg::new("press_mute_key")
|
|
.long("press_mute_key")
|
|
.required(false)
|
|
.help("The app will simulate pressing the microphone mute key whoever the headsets is muted or unmuted.")
|
|
.default_value("true")
|
|
.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();
|
|
|
|
let press_mute_key = *matches.get_one::<bool>("press_mute_key").unwrap_or(&true);
|
|
let mut enigo = if press_mute_key {
|
|
match Enigo::new(&Settings::default()) {
|
|
Ok(enigo) => Some(enigo),
|
|
Err(e) => {
|
|
eprintln!("Virtual mute key failed to initialize: {e}");
|
|
None
|
|
}
|
|
}
|
|
} else {
|
|
None
|
|
};
|
|
VERBOSE.set(matches.get_flag("verbose")).unwrap();
|
|
|
|
let refresh_interval = *matches.get_one::<u64>("refresh_interval").unwrap_or(&3);
|
|
let refresh_interval = Duration::from_secs(refresh_interval);
|
|
let (tx, rx) = mpsc::channel();
|
|
let tray_handler = TrayHandler::new(StatusTray::new(tx));
|
|
loop {
|
|
let mut device = loop {
|
|
match connect_compatible_device() {
|
|
Ok(d) => break d,
|
|
Err(e) => {
|
|
tray_handler.clear_state();
|
|
eprintln!("Connecting failed with error: {e}")
|
|
}
|
|
}
|
|
std::thread::sleep(Duration::from_secs(1));
|
|
};
|
|
|
|
// Run loop
|
|
let mut run_counter = 0;
|
|
loop {
|
|
let mute_state = device.get_device_state().device_properties.muted;
|
|
match if run_counter % 30 == 0 {
|
|
device.active_refresh_state()
|
|
} else {
|
|
device.passive_refresh_state()
|
|
} {
|
|
Ok(()) => (),
|
|
Err(error) => {
|
|
eprintln!("{error}");
|
|
tray_handler.update(device.get_device_state());
|
|
break; // try to reconnect
|
|
}
|
|
};
|
|
if mute_state.is_some()
|
|
&& mute_state != device.get_device_state().device_properties.muted
|
|
{
|
|
if let Some(enigo) = &mut enigo {
|
|
if let Err(e) = enigo.key(Key::MicMute, Direction::Click) {
|
|
eprintln!("Failed to press key on mute: {e}");
|
|
}
|
|
}
|
|
}
|
|
|
|
// with the default refresh_interval the state is only actively queried every 3min
|
|
// querying the device to frequently can lead to instability
|
|
let first = rx.recv_timeout(refresh_interval);
|
|
for command in first.into_iter().chain(rx.try_iter()) {
|
|
let _ = device.try_apply(command);
|
|
std::thread::sleep(hyper_headset::devices::RESPONSE_DELAY);
|
|
let _ = device.active_refresh_state();
|
|
}
|
|
|
|
tray_handler.update(device.get_device_state());
|
|
run_counter += 1;
|
|
}
|
|
}
|
|
}
|