This commit is contained in:
Brad Stein 2025-06-28 17:55:15 -05:00
parent 60cee23d08
commit 820ba97b76
5 changed files with 26 additions and 16 deletions

View File

@ -15,6 +15,7 @@ pub struct InputAggregator {
mou_tx: Sender<MouseReport>, mou_tx: Sender<MouseReport>,
dev_mode: bool, dev_mode: bool,
released: bool, released: bool,
magic_active: bool,
keyboards: Vec<KeyboardAggregator>, keyboards: Vec<KeyboardAggregator>,
mice: Vec<MouseAggregator>, mice: Vec<MouseAggregator>,
camera: Option<CameraCapture>, camera: Option<CameraCapture>,
@ -25,7 +26,7 @@ impl InputAggregator {
pub fn new(dev_mode: bool, pub fn new(dev_mode: bool,
kbd_tx: Sender<KeyboardReport>, kbd_tx: Sender<KeyboardReport>,
mou_tx: Sender<MouseReport>) -> Self { mou_tx: Sender<MouseReport>) -> Self {
Self { kbd_tx, mou_tx, dev_mode, released: false, Self { kbd_tx, mou_tx, dev_mode, released: false, magic_active: false,
keyboards: Vec::new(), mice: Vec::new(), keyboards: Vec::new(), mice: Vec::new(),
camera: None, mic: None } camera: None, mic: None }
} }
@ -105,15 +106,14 @@ impl InputAggregator {
// Example approach: poll each aggregator in a simple loop // Example approach: poll each aggregator in a simple loop
let mut tick = interval(Duration::from_millis(10)); let mut tick = interval(Duration::from_millis(10));
loop { loop {
let mut want_toggle = false; let magic_now = self.keyboards.iter().any(|k| k.magic_grab());
let mut want_kill = false; let mut want_kill = false;
for kbd in &mut self.keyboards { for kbd in &mut self.keyboards {
kbd.process_events(); kbd.process_events();
want_toggle |= kbd.magic_grab();
want_kill |= kbd.magic_kill(); want_kill |= kbd.magic_kill();
} }
if want_toggle { self.toggle_grab(); } if magic_now && !self.magic_active { self.toggle_grab(); }
if want_kill { if want_kill {
warn!("🧙 magic chord - killing 🪄 AVADA KEDAVRA!!! 💥💀⚰️"); warn!("🧙 magic chord - killing 🪄 AVADA KEDAVRA!!! 💥💀⚰️");
std::process::exit(0); std::process::exit(0);
@ -122,21 +122,22 @@ impl InputAggregator {
for mouse in &mut self.mice { for mouse in &mut self.mice {
mouse.process_events(); mouse.process_events();
} }
// camera / mic stubs could go here
// camera / mic stubs go here
self.magic_active = magic_now;
tick.tick().await; tick.tick().await;
} }
} }
fn toggle_grab(&mut self) { fn toggle_grab(&mut self) {
if self.released { if self.released {
for k in &mut self.keyboards { k.grab(); }
for m in &mut self.mice { m.grab(); }
tracing::info!("🧙 magic chord - restricting devices 🪄 IMPERIUS!!! 🎮🔒"); tracing::info!("🧙 magic chord - restricting devices 🪄 IMPERIUS!!! 🎮🔒");
} else { } else {
for k in &mut self.keyboards { k.ungrab(); }
for m in &mut self.mice { m.ungrab(); }
tracing::info!("🧙 magic chord - freeing devices 🪄 EXPELLIARMUS!!! 🔓🕊️"); tracing::info!("🧙 magic chord - freeing devices 🪄 EXPELLIARMUS!!! 🔓🕊️");
} }
for k in &mut self.keyboards { k.set_grab(self.released); }
for m in &mut self.mice { m.set_grab(self.released); }
self.released = !self.released; self.released = !self.released;
} }
} }

View File

@ -26,8 +26,9 @@ impl KeyboardAggregator {
Self { dev, tx, dev_mode, pressed_keys: HashSet::new()} Self { dev, tx, dev_mode, pressed_keys: HashSet::new()}
} }
pub fn grab(&mut self) { let _ = self.dev.grab(); } pub fn set_grab(&mut self, grab: bool) {
pub fn ungrab(&mut self) { let _ = self.dev.ungrab(); } let _ = if grab { self.dev.grab() } else { self.dev.ungrab() };
}
pub fn process_events(&mut self) { pub fn process_events(&mut self) {
// --- first fetch, then log (avoids aliasing borrow) --- // --- first fetch, then log (avoids aliasing borrow) ---

View File

@ -28,8 +28,9 @@ impl MouseAggregator {
} }
#[inline] fn slog(&self, f: impl FnOnce()) { if self.dev_mode { f() } } #[inline] fn slog(&self, f: impl FnOnce()) { if self.dev_mode { f() } }
pub fn grab(&mut self) { let _ = self.dev.grab(); } pub fn set_grab(&mut self, grab: bool) {
pub fn ungrab(&mut self) { let _ = self.dev.ungrab(); } let _ = if grab { self.dev.grab() } else { self.dev.ungrab() };
}
pub fn process_events(&mut self) { pub fn process_events(&mut self) {
let evts: Vec<InputEvent> = match self.dev.fetch_events() { let evts: Vec<InputEvent> = match self.dev.fetch_events() {

View File

@ -105,7 +105,7 @@ After=network.target lesavka-core.service
[Service] [Service]
ExecStart=/usr/local/bin/lesavka-server ExecStart=/usr/local/bin/lesavka-server
Restart=always Restart=always
Environment=RUST_LOG=lesavka_server=trace,lesavka_server::video=trace,lesavka_server::usb_gadget=info Environment=RUST_LOG=lesavka_server::video=trace,lesavka_server::usb_gadget=info,lesavka_server=info
Environment=RUST_BACKTRACE=1 Environment=RUST_BACKTRACE=1
Restart=always Restart=always
RestartSec=5 RestartSec=5

View File

@ -28,12 +28,19 @@ pub async fn eye_ball(
// appsink name=sink emit-signals=true drop=true sync=false" // appsink name=sink emit-signals=true drop=true sync=false"
// ); // );
let desc = format!( let desc = format!(
"v4l2src device={dev} io-mode=mmap ! videorate skip-to-first=true ! \ "v4l2src device={dev} io-mode=mmap ! \
queue2 max-size-buffers=0 max-size-bytes=0 min-threshold-time=10000000 ! \ queue max-size-buffers=0 max-size-bytes=0 max-size-time=0 ! \
video/x-h264,stream-format=byte-stream,alignment=au,profile=high ! \ video/x-h264,stream-format=byte-stream,alignment=au,profile=high ! \
h264parse config-interval=1 ! \ h264parse config-interval=1 ! \
appsink name=sink emit-signals=true drop=false sync=false" appsink name=sink emit-signals=true drop=false sync=false"
); );
// let desc = format!(
// "v4l2src device={dev} io-mode=mmap ! videorate skip-to-first=true ! \
// queue2 max-size-buffers=0 max-size-bytes=0 min-threshold-time=10000000 ! \
// video/x-h264,stream-format=byte-stream,alignment=au,profile=high ! \
// h264parse config-interval=1 ! \
// appsink name=sink emit-signals=true drop=false sync=false"
// );
let pipeline = gst::parse::launch(&desc)? let pipeline = gst::parse::launch(&desc)?
.downcast::<gst::Pipeline>() .downcast::<gst::Pipeline>()