From b7d40b7c90f24fa686752ef415679dedbbb1d2c7 Mon Sep 17 00:00:00 2001 From: Oliver Walter Date: Wed, 6 Aug 2025 20:30:05 +0200 Subject: [PATCH] mouse control with buttons --- src/main.rs | 141 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 97 insertions(+), 44 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9ef338e..4bb6711 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,11 @@ +use eframe::UserEvent; use eframe::egui; +use egui::{FontData, FontDefinitions, FontFamily}; use egui::{Key, RichText}; use std::collections::VecDeque; -use egui::{FontData, FontDefinitions, FontFamily}; -use std::sync::{Arc, Mutex}; -use winit::event_loop::{EventLoop}; -use eframe::UserEvent; use std::env; +use std::sync::{Arc, Mutex}; +use winit::event_loop::EventLoop; const MAX_KEYS: usize = 6; const SECRET_COMBO: [Key; MAX_KEYS] = [ @@ -17,7 +17,6 @@ const SECRET_COMBO: [Key; MAX_KEYS] = [ Key::ArrowRight, ]; - struct AdminGateApp { key_history: VecDeque, should_run_admin_command: Arc>, @@ -32,7 +31,6 @@ impl Default for AdminGateApp { } } - impl eframe::App for AdminGateApp { fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) { egui::CentralPanel::default().show(ctx, |ui| { @@ -55,20 +53,81 @@ impl eframe::App for AdminGateApp { .collect::>() .join(" "); - ui.label( - RichText::new(&key_display) - .size(60.0) - .strong(), - ); + ui.label(RichText::new(&key_display).size(60.0).strong()); ui.add_space(20.0); + ui.horizontal_top(|ui| { + ui.add_space(30.0); + + egui::Grid::new("arrow_grid") + .spacing([20.0, 20.0]) + .striped(false) + .min_col_width(80.0) + .show(ui, |ui| { + // Row 1 + if ui.add_sized([80.0, 80.0], egui::Button::new("X")).clicked() { + std::process::exit(0); + } + + if ui.add_sized([80.0, 80.0], egui::Button::new("↑")).clicked() { + if self.key_history.len() == MAX_KEYS { + self.key_history.pop_front(); + } + self.key_history.push_back(Key::ArrowUp); + } + ui.label(""); // empty cell + ui.end_row(); + + // Row 2 + if ui.add_sized([80.0, 80.0], egui::Button::new("←")).clicked() { + if self.key_history.len() == MAX_KEYS { + self.key_history.pop_front(); + } + self.key_history.push_back(Key::ArrowLeft); + } + if ui.add_sized([80.0, 80.0], egui::Button::new("⏎")).clicked() { + if self.key_history.len() == MAX_KEYS + && self + .key_history + .iter() + .copied() + .eq(SECRET_COMBO.iter().copied()) + { + *self.should_run_admin_command.lock().unwrap() = true; + ctx.send_viewport_cmd(egui::ViewportCommand::Close); + } + } + if ui.add_sized([80.0, 80.0], egui::Button::new("→")).clicked() { + if self.key_history.len() == MAX_KEYS { + self.key_history.pop_front(); + } + self.key_history.push_back(Key::ArrowRight); + } + ui.end_row(); + + // Row 3 + ui.label(""); // empty cell + if ui.add_sized([80.0, 80.0], egui::Button::new("↓")).clicked() { + if self.key_history.len() == MAX_KEYS { + self.key_history.pop_front(); + } + self.key_history.push_back(Key::ArrowDown); + } + ui.label(""); // empty cell + ui.end_row(); + }); + }); }); }); 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()); + ui.label( + egui::RichText::new("Press ESC to quit. Enter runs the admin command.") + .size(24.0) + .weak(), + ); }); }); @@ -78,7 +137,7 @@ impl eframe::App for AdminGateApp { key, pressed: true, modifiers: _, - physical_key : _, + physical_key: _, repeat: _, } = event { @@ -116,7 +175,6 @@ impl eframe::App for AdminGateApp { } } - fn setup_custom_fonts(ctx: &egui::Context) { let mut fonts = FontDefinitions::default(); @@ -124,10 +182,9 @@ fn setup_custom_fonts(ctx: &egui::Context) { 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(), + ) + .into(), ); // Use the custom font for all proportional and monospace text @@ -146,11 +203,8 @@ fn setup_custom_fonts(ctx: &egui::Context) { ctx.set_fonts(fonts); } - - -fn main() { - - let mut args = env::args().skip(1); // Skip program name +fn main() { + let mut args = env::args().skip(1); // Skip program name let admin_command = match args.next() { Some(cmd) => cmd, @@ -162,37 +216,38 @@ fn main() { let admin_args: Vec = args.collect(); - let should_run_admin_command = Arc::new(Mutex::new(false)); let shared_flag = should_run_admin_command.clone(); - let app = AdminGateApp { + 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 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(); + 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(admin_command) + { + // After GUI closes + if *should_run_admin_command.lock().unwrap() { + println!("✅ Running admin command..."); + + match std::process::Command::new(admin_command) .args(admin_args) .status() // ← wait until it finishes { @@ -203,8 +258,6 @@ fn main() { eprintln!("❌ Failed to run admin command: {}", e); } } + } } } - - -}