use eframe::egui; use egui::{Key, RichText}; use std::collections::VecDeque; use egui::{FontData, FontDefinitions, FontFamily}; use std::sync::{Arc, Mutex}; use winit::event_loop::{ControlFlow, EventLoop}; use eframe::UserEvent; const MAX_KEYS: usize = 6; const SECRET_COMBO: [Key; MAX_KEYS] = [ Key::ArrowUp, Key::ArrowUp, Key::ArrowDown, Key::ArrowDown, Key::ArrowLeft, Key::ArrowRight, ]; struct AdminGateApp { key_history: VecDeque, should_run_admin_command: Arc>, } impl Default for AdminGateApp { fn default() -> Self { Self { key_history: VecDeque::with_capacity(MAX_KEYS), should_run_admin_command: Arc::new(Mutex::new(false)), } } } impl eframe::App for AdminGateApp { fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.vertical_centered(|ui| { ui.heading("Admin Settings Gate"); ui.add_space(20.0); // Display last 6 keys let key_display = self .key_history .iter() .map(|k| match k { Key::ArrowUp => "↑", Key::ArrowDown => "↓", Key::ArrowLeft => "←", Key::ArrowRight => "→", _ => "?", }) .collect::>() .join(" "); ui.label( RichText::new(&key_display) .size(60.0) .strong(), ); ui.add_space(20.0); }); }); egui::TopBottomPanel::bottom("footer").show(ctx, |ui| { ui.horizontal_centered(|ui| { ui.label(egui::RichText::new("Press ESC to quit. Enter runs the admin command.").size(24.0).weak()); }); }); // Input handling for event in &ctx.input(|i| i.raw.events.clone()) { if let egui::Event::Key { key, pressed: true, modifiers: _, physical_key : _, repeat: _, } = event { match key { Key::ArrowUp | Key::ArrowDown | Key::ArrowLeft | Key::ArrowRight => { if self.key_history.len() == MAX_KEYS { self.key_history.pop_front(); } self.key_history.push_back(*key); //self.should_run_admin_command = false; // reset status } Key::Enter => { if self.key_history.len() == MAX_KEYS && self .key_history .iter() .copied() .eq(SECRET_COMBO.iter().copied()) { // Run admin command *self.should_run_admin_command.lock().unwrap() = true; ctx.send_viewport_cmd(egui::ViewportCommand::Close); // This shuts down the GUI cleanly ctx.send_viewport_cmd(egui::ViewportCommand::Visible(false)); // This shuts down the GUI cleanly } } Key::Escape => { std::process::exit(0); } _ => {} } } } ctx.request_repaint(); // keep UI responsive } } fn setup_custom_fonts(ctx: &egui::Context) { let mut fonts = FontDefinitions::default(); // Add your custom font fonts.font_data.insert( "custom".to_string(), FontData::from_owned( std::fs::read("/usr/share/fonts/TTF/DejaVuSans.ttf").expect("Failed to load font"), ).into(), ); // Use the custom font for all proportional and monospace text fonts .families .get_mut(&FontFamily::Proportional) .unwrap() .insert(0, "custom".to_string()); fonts .families .get_mut(&FontFamily::Monospace) .unwrap() .insert(0, "custom".to_string()); ctx.set_fonts(fonts); } fn main() { let should_run_admin_command = Arc::new(Mutex::new(false)); let shared_flag = should_run_admin_command.clone(); let app = AdminGateApp { key_history: VecDeque::with_capacity(6), should_run_admin_command: shared_flag, }; { let options = eframe::NativeOptions::default(); let eventloop = EventLoop::::with_user_event().build().unwrap(); let mut winit_app = eframe::create_native("Admin Gate", options, Box::new(|cc| { // Setup fonts setup_custom_fonts(&cc.egui_ctx); Ok(Box::new(app)) }), &eventloop); eventloop.run_app(&mut winit_app).unwrap(); } { // After GUI closes if *should_run_admin_command.lock().unwrap() { println!("✅ Running admin command..."); match std::process::Command::new("sh") .arg("-c") .arg("kitty") .status() // ← wait until it finishes { Ok(status) => { println!("Admin command exited with: {}", status); } Err(e) => { eprintln!("❌ Failed to run admin command: {}", e); } } } } }