use std::error::Error;
use std::sync::Arc;
use std::time::{Duration, Instant};
use enigo::{Enigo, Settings};
use gilrs::{Event, EventType, Gilrs};
use tokio::sync::{Mutex, mpsc};
use osynic_pad::{Config, GamepadMapper, MappingMode, PadEvent, cli, events};
#[tokio::main]
async fn main() {
match run().await {
Ok(_) => (),
Err(err) => {
eprintln!("错误: {}", err);
std::process::exit(1);
}
}
}
async fn run() -> Result<(), Box<dyn Error>> {
cli::show_welcome_screen()?;
let (config_path, debug) = cli::show_config_selector()?;
let config_filename = config_path
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("Unknown");
let config = Config::load_from_path(&config_path)?;
let enigo = Arc::new(Mutex::new(Enigo::new(&Settings::default())?));
let mode = config.mapping_mode.clone().unwrap_or(MappingMode::Default);
let mapper = Arc::new(GamepadMapper::new(
config,
Arc::clone(&enigo),
mode.clone(),
debug,
));
let (tx, mut rx) = mpsc::channel::<PadEvent>(1000);
let mut gilrs = Gilrs::new()?;
cli::show_startup_info(config_filename, &format!("{:?}", mode), debug);
cli::show_gamepads(&gilrs);
let tx_clone = tx.clone();
let gamepad_handler = tokio::spawn(async move {
let mut last_event_time = Instant::now();
loop {
while let Some(Event {
id: _,
event,
time: _,
..
}) = gilrs.next_event()
{
match event {
EventType::ButtonPressed(button, _) => {
let _ = tx_clone
.try_send(PadEvent::ButtonPress(events::button_to_string(button)));
}
EventType::ButtonReleased(button, _) => {
let _ = tx_clone
.try_send(PadEvent::ButtonRelease(events::button_to_string(button)));
}
EventType::AxisChanged(axis, value, _) => match axis {
gilrs::Axis::LeftZ => {
let _ = tx_clone.try_send(PadEvent::TriggerChanged(
"LeftTrigger2".to_string(),
value,
));
}
gilrs::Axis::RightZ => {
let _ = tx_clone.try_send(PadEvent::TriggerChanged(
"RightTrigger2".to_string(),
value,
));
}
_ => {}
},
_ => {}
}
}
let elapsed = last_event_time.elapsed();
let sleep_time = if elapsed < Duration::from_millis(2) {
Duration::from_millis(2) - elapsed
} else {
Duration::ZERO
};
tokio::time::sleep(sleep_time).await;
last_event_time = Instant::now();
}
});
let event_handler = tokio::spawn({
let mapper = Arc::clone(&mapper);
async move {
while let Some(event) = rx.recv().await {
if let Err(e) = mapper.handle_event(event).await {
eprintln!("处理事件错误: {}", e);
}
}
}
});
tokio::signal::ctrl_c().await?;
println!("\n\n👋 正在关闭...");
drop(tx);
gamepad_handler.abort();
event_handler.abort();
Ok(())
}