#[cfg(target_os = "macos")]
use cocoa::base::nil;
#[cfg(target_os = "macos")]
use cocoa::appkit::{NSApplication, NSApplicationActivationPolicyAccessory};
#[cfg(target_os = "macos")]
use cocoa::foundation::NSAutoreleasePool;
mod audio;
mod input;
mod ui;
mod config;
mod service;
use anyhow::Result;
use log::{info, error};
use once_cell::sync::Lazy;
use parking_lot::Mutex;
use std::sync::Arc;
use std::io::Write;
use clap::Parser;
static APP_STATE: Lazy<Arc<Mutex<config::Config>>> = Lazy::new(|| {
Arc::new(Mutex::new(config::Config::load().unwrap_or_default()))
});
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
#[arg(long)]
start_service: bool,
#[arg(long)]
stop_service: bool,
#[arg(long)]
restart_service: bool,
}
fn main() -> Result<()> {
env_logger::Builder::from_env(env_logger::Env::default()
.filter_or("RUST_LOG", "debug"))
.format(|buf, record| {
writeln!(buf, "[{}] {}", record.level(), record.args())
})
.init();
info!("Starting ClickClack...");
let cli = Cli::parse();
if cli.start_service || cli.stop_service || cli.restart_service {
let service_manager = service::ServiceManager::new()?;
if cli.start_service {
service_manager.start_service()?;
println!("ClickClack service started successfully");
return Ok(());
}
if cli.stop_service {
service_manager.stop_service()?;
println!("ClickClack service stopped successfully");
return Ok(());
}
if cli.restart_service {
service_manager.restart_service()?;
println!("ClickClack service restarted successfully");
return Ok(());
}
}
#[cfg(target_os = "macos")]
unsafe {
let _pool = NSAutoreleasePool::new(nil);
let app = NSApplication::sharedApplication(nil);
app.setActivationPolicy_(NSApplicationActivationPolicyAccessory);
}
if let Err(e) = ui::tray::ensure_assets_exist() {
error!("Failed to initialize assets: {}", e);
return Err(anyhow::anyhow!("Failed to initialize assets: {}", e));
}
info!("Assets initialized successfully");
let sound_engine = Arc::new(audio::SoundEngine::new()?);
info!("Sound engine initialized");
let keyboard_handler = input::KeyboardHandler::new(sound_engine.clone())?;
keyboard_handler.start()?;
info!("Keyboard handler started");
let _tray = ui::TrayIcon::new()?;
info!("Tray icon created");
#[cfg(target_os = "macos")]
unsafe {
let app = NSApplication::sharedApplication(nil);
app.run();
}
#[cfg(not(target_os = "macos"))]
loop {
std::thread::sleep(std::time::Duration::from_millis(100));
}
Ok(())
}