Add dialog prompts and make udev checks linux only
This commit is contained in:
@@ -1,19 +1,27 @@
|
||||
use std::{
|
||||
fs,
|
||||
io::{self},
|
||||
time::Duration,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
use clap::{Arg, Command};
|
||||
use hyper_headset::{
|
||||
check_rule, debug_println, devices::connect_compatible_device, prompt_user_for_udev_rule,
|
||||
update_rule, RuleState, UDEV_RULES, UDEV_RULE_PATH_SYSTEM, UDEV_RULE_PATH_USER,
|
||||
};
|
||||
use hyper_headset::devices::connect_compatible_device;
|
||||
|
||||
const SHOW_ALL_OPTIONS: bool = false;
|
||||
|
||||
fn main() {
|
||||
prompt_user_for_udev_rule();
|
||||
#[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 mut device = match connect_compatible_device() {
|
||||
Ok(device) => device,
|
||||
Err(error) => {
|
||||
|
||||
137
src/lib.rs
137
src/lib.rs
@@ -1,5 +1,8 @@
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::{fs, io, process::Command, time::Duration};
|
||||
|
||||
use dialog::{Choice, DialogBox};
|
||||
|
||||
// #![warn(missing_docs)]
|
||||
pub mod devices;
|
||||
|
||||
@@ -21,6 +24,7 @@ pub enum RuleState {
|
||||
RuleMatch(bool),
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn check_rule(path: &str, rules: &str) -> RuleState {
|
||||
let mut rule_state;
|
||||
|
||||
@@ -39,34 +43,95 @@ pub fn check_rule(path: &str, rules: &str) -> RuleState {
|
||||
rule_state
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn act_as_askpass_handler() -> ! {
|
||||
let a = dialog::Password::new("Created rule at /usr/lib/udev/rules.d/99-HyperHeadset.rules")
|
||||
.title("HyperHeadset")
|
||||
.show()
|
||||
.expect("Failed to open dialog");
|
||||
println!("{}", a.unwrap_or("".to_string()));
|
||||
std::process::exit(0)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn update_rule(path: &str, rules: &str) {
|
||||
let status = Command::new("sudo")
|
||||
.arg("sh")
|
||||
.arg("-c")
|
||||
.arg(format!(
|
||||
"echo {} > {} && udevadm control --reload-rules && udevadm trigger",
|
||||
shell_escape::escape(rules.into()),
|
||||
shell_escape::escape(path.into())
|
||||
))
|
||||
.status();
|
||||
let status = if std::io::IsTerminal::is_terminal(&std::io::stdin()) {
|
||||
Command::new("sudo")
|
||||
.arg("sh")
|
||||
.arg("-c")
|
||||
.arg(format!(
|
||||
"echo {} > {} && udevadm control --reload-rules && udevadm trigger",
|
||||
shell_escape::escape(rules.into()),
|
||||
shell_escape::escape(path.into())
|
||||
))
|
||||
.status()
|
||||
} else {
|
||||
Command::new("sudo")
|
||||
.env("SUDO_ASKPASS", std::env::current_exe().unwrap())
|
||||
.arg("--askpass")
|
||||
.arg("sh")
|
||||
.arg("-c")
|
||||
.arg(format!(
|
||||
"echo {} > {} && udevadm control --reload-rules && udevadm trigger",
|
||||
shell_escape::escape(rules.into()),
|
||||
shell_escape::escape(path.into())
|
||||
))
|
||||
.status()
|
||||
};
|
||||
// a little delay so the rules are active before trying to connect
|
||||
std::thread::sleep(Duration::from_millis(500));
|
||||
|
||||
match status {
|
||||
Ok(exit_status) if exit_status.success() => {
|
||||
println!("created rule at {path}.\nYou may need to replug your headset for the udev rules to take effect.");
|
||||
show_message(&format!("created rule at {path}.\nYou may need to replug your headset for the udev rules to take effect."));
|
||||
}
|
||||
Ok(e) => {
|
||||
println!("Failed to create rule at {path}: {}", e);
|
||||
println!("Your headset may not be recognized without the correct udev rules.");
|
||||
show_message(&format!("Failed to create rule at {path}: {}.\nYour headset may not be recognized without the correct udev rules.", e));
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to create rule at {path}: {}", e);
|
||||
println!("Your headset may not be recognized without the correct udev rules.");
|
||||
show_message(&format!("Failed to create rule at {path}: {}\nYour headset may not be recognized without the correct udev rules.", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn show_message(message: &str) {
|
||||
if std::io::IsTerminal::is_terminal(&std::io::stdin()) {
|
||||
println!("{message}");
|
||||
} else {
|
||||
let _ = dialog::Message::new(message.to_string())
|
||||
.title("HyperHeadset")
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn handle_udev_rule_user_interaction(path: &str, ask_message: &str, decline_message: &str) {
|
||||
if std::io::IsTerminal::is_terminal(&std::io::stdin()) {
|
||||
print!("{ask_message} (y/N): ");
|
||||
io::Write::flush(&mut io::stdout()).unwrap();
|
||||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input).unwrap();
|
||||
if matches!(input.trim(), "y" | "Y") {
|
||||
update_rule(path, UDEV_RULES);
|
||||
} else {
|
||||
println!("{decline_message}");
|
||||
}
|
||||
} else if dialog::Question::new(ask_message.to_string())
|
||||
.title("HyperHeadset")
|
||||
.show()
|
||||
.unwrap_or(Choice::No)
|
||||
== Choice::Yes
|
||||
{
|
||||
update_rule(path, UDEV_RULES);
|
||||
} else {
|
||||
let _ = dialog::Message::new(decline_message.to_string())
|
||||
.title("HyperHeadset")
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn prompt_user_for_udev_rule() {
|
||||
let user_rule_state = check_rule(UDEV_RULE_PATH_USER, UDEV_RULES);
|
||||
let system_rule_state = check_rule(UDEV_RULE_PATH_SYSTEM, UDEV_RULES);
|
||||
@@ -77,45 +142,23 @@ pub fn prompt_user_for_udev_rule() {
|
||||
(_, RuleState::RuleMatch(true)) => (),
|
||||
|
||||
(RuleState::RuleMatch(false), _) | (RuleState::RuleExists(true), _) => {
|
||||
print!(
|
||||
"Udev rules at {UDEV_RULE_PATH_USER} do not have the expected value. Do you want to recreate them? (y/N): "
|
||||
);
|
||||
io::Write::flush(&mut io::stdout()).unwrap();
|
||||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input).unwrap();
|
||||
if matches!(input.trim(), "y" | "Y") {
|
||||
update_rule(UDEV_RULE_PATH_USER, UDEV_RULES);
|
||||
} else {
|
||||
println!("Your headset may not be recognized without the correct udev rules.");
|
||||
}
|
||||
handle_udev_rule_user_interaction(UDEV_RULE_PATH_USER,
|
||||
&format!("Udev rules at {UDEV_RULE_PATH_USER} do not have the expected value. Do you want to recreate them?"),
|
||||
"Your headset may not be recognized without the correct udev rules.");
|
||||
}
|
||||
(RuleState::RuleExists(false), RuleState::RuleMatch(false))
|
||||
| (RuleState::RuleExists(false), RuleState::RuleExists(true)) => {
|
||||
print!(
|
||||
"Udev rules at {UDEV_RULE_PATH_SYSTEM} do not have the expected value. Do you want to recreate them? (y/N): "
|
||||
);
|
||||
io::Write::flush(&mut io::stdout()).unwrap();
|
||||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input).unwrap();
|
||||
if matches!(input.trim(), "y" | "Y") {
|
||||
update_rule(UDEV_RULE_PATH_SYSTEM, UDEV_RULES);
|
||||
} else {
|
||||
println!("Your headset may not be recognized without the correct udev rules.");
|
||||
}
|
||||
handle_udev_rule_user_interaction(UDEV_RULE_PATH_SYSTEM,
|
||||
&format!("Udev rules at {UDEV_RULE_PATH_SYSTEM} do not have the expected value. Do you want to recreate them?"),
|
||||
"Your headset may not be recognized without the correct udev rules.");
|
||||
}
|
||||
|
||||
(RuleState::RuleExists(false), RuleState::RuleExists(false)) => {
|
||||
print!("No udev rules found. Do you want to create {UDEV_RULE_PATH_USER}? (y/N): ");
|
||||
io::Write::flush(&mut io::stdout()).unwrap();
|
||||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input).unwrap();
|
||||
if matches!(input.trim(), "y" | "Y") {
|
||||
update_rule(UDEV_RULE_PATH_USER, UDEV_RULES);
|
||||
} else {
|
||||
println!(
|
||||
"Without udev rules your headset can only be accessed when running as root."
|
||||
);
|
||||
}
|
||||
handle_udev_rule_user_interaction(
|
||||
UDEV_RULE_PATH_USER,
|
||||
&format!("No udev rules found. Do you want to create {UDEV_RULE_PATH_USER}?"),
|
||||
"Without udev rules your headset can only be accessed when running as root.",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
src/main.rs
21
src/main.rs
@@ -3,11 +3,26 @@ use enigo::{Direction, Enigo, Key, Keyboard, Settings};
|
||||
use std::time::Duration;
|
||||
|
||||
mod status_tray;
|
||||
use hyper_headset::{devices::connect_compatible_device, prompt_user_for_udev_rule};
|
||||
use hyper_headset::devices::connect_compatible_device;
|
||||
use status_tray::{StatusTray, TrayHandler};
|
||||
|
||||
fn main() {
|
||||
prompt_user_for_udev_rule();
|
||||
#[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 matches = Command::new(env!("CARGO_PKG_NAME"))
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.author(env!("CARGO_PKG_AUTHORS"))
|
||||
@@ -54,7 +69,7 @@ fn main() {
|
||||
// with the default refresh_interval the state is only actively queried every 3min
|
||||
// querying the device to frequently can lead to instability
|
||||
|
||||
let mute_state = device.get_device_state().muted.clone();
|
||||
let mute_state = device.get_device_state().muted;
|
||||
match if run_counter % 30 == 0 {
|
||||
device.active_refresh_state()
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user