From c92b571c16cba683c647c5ee5c95c3ef2c33e6f7 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Mon, 21 Jul 2025 18:42:46 -0400 Subject: [PATCH] add evfbo (evdev + fbdev + stdout) backend During a normal boot in the postmarketOS initramfs, the TTY is not easily accessible. The on-screen keyboard is expected to send the password to stdout instead of to a uinput device. Add the evfbo backend to support full-disk encryption. --- Cargo.toml | 4 ++ src/stdio/mod.rs | 8 ++++ src/stdio/output.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++ src/ufkbd_evfbo.rs | 81 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+) create mode 100644 src/stdio/mod.rs create mode 100644 src/stdio/output.rs create mode 100644 src/ufkbd_evfbo.rs diff --git a/Cargo.toml b/Cargo.toml index 723258d..125afd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,10 @@ bindgen = "0.71" name = "ufkbd-evfb" path = "src/ufkbd_evfb.rs" +[[bin]] +name = "ufkbd-evfbo" +path = "src/ufkbd_evfbo.rs" + [[bin]] name = "ufkbd-gnome" path = "src/ufkbd_gnome.rs" diff --git a/src/stdio/mod.rs b/src/stdio/mod.rs new file mode 100644 index 0000000..a116eba --- /dev/null +++ b/src/stdio/mod.rs @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2025, Richard Acayan. All rights reserved. + */ + +mod output; + +pub use self::output::Output; diff --git a/src/stdio/output.rs b/src/stdio/output.rs new file mode 100644 index 0000000..2b87957 --- /dev/null +++ b/src/stdio/output.rs @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2025, Richard Acayan. All rights reserved. + */ + +use crate::core::Keyboard; +use crate::core::Layout; +use std::iter::FromIterator; +use xkeysym::Keysym; + +pub struct Output { + back: String, + front: String, + complete: bool, +} + +impl Output { + pub fn new() -> Self + { + Self { + back: String::new(), + front: String::new(), + complete: false, + } + } + + #[inline(always)] + pub fn complete(&self) -> bool + { + self.complete + } +} + +impl Keyboard for Output { + fn key_supported(&self, sym: Keysym) -> bool + { + match sym { + Keysym::Return => true, + Keysym::BackSpace => true, + Keysym::Delete => true, + Keysym::Left => true, + Keysym::Right => true, + _ => false, + } + } + + fn press(&mut self, sym: Keysym) + { + match sym { + Keysym::Return => { + let front = self.front.chars().rev(); + let front = String::from_iter(front); + + println!("{}{}", self.back, front); + + self.complete = true; + }, + Keysym::BackSpace => { + self.back.pop(); + }, + Keysym::Delete => { + self.front.pop(); + }, + Keysym::Left => { + if let Some(c) = self.back.pop() { + self.front.push(c); + } + }, + Keysym::Right => { + if let Some(c) = self.front.pop() { + self.back.push(c); + } + }, + _ => (), + } + } + + fn release(&mut self, _: Keysym) + { + } + + fn text(&mut self, text: &str) + { + for c in text.chars() { + self.back.push(c); + } + } + + fn change_layout(&mut self, _: &Layout) + { + } +} diff --git a/src/ufkbd_evfbo.rs b/src/ufkbd_evfbo.rs new file mode 100644 index 0000000..67ad82b --- /dev/null +++ b/src/ufkbd_evfbo.rs @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2025, Richard Acayan. All rights reserved. + */ + +mod core; +mod evdev; +mod fbdev; +mod linux; +mod stdio; + +use crate::core::Button; +use crate::core::Configuration; +use crate::core::Display; +use crate::core::Graphics; +use crate::core::Layout; +use crate::evdev::Touchscreen; +use crate::fbdev::Framebuffer; +use crate::stdio::Output; +use polling::Event; +use polling::Events; +use polling::Poller; +use signal_hook::consts::signal; +use signal_hook::iterator::Signals; +use std::sync::Arc; +use std::sync::Mutex; +use std::time::Instant; + +fn main() +{ + let cfg = Configuration::load().unwrap(); + let disp = Framebuffer::new(&cfg).unwrap(); + + let gfx = Graphics::new(disp, &cfg); + let gfx = Mutex::new(gfx); + let gfx = Arc::new(gfx); + + let kbd = Output::new(); + let layout = Layout::load(&cfg).unwrap(); + let mut btn = Button::new(&cfg, layout, kbd, gfx.clone()); + btn.set_text_supported(true); + + { + let mut gfx = gfx.lock().unwrap(); + let (width, height) = gfx.display().size(); + gfx.resize(btn.layout(), btn.mod_state(), width, height); + } + + let mut touchscreen = Touchscreen::new(btn, &cfg).unwrap(); + + let mut events = Events::new(); + let poller = Poller::new().unwrap(); + let ts_evt = Event::readable(0); + + let mut sigs = Signals::new([ + signal::SIGHUP, + signal::SIGINT, + signal::SIGPIPE, + signal::SIGTERM, + ]).unwrap(); + + unsafe { + poller.add(&touchscreen, ts_evt).unwrap(); + } + + while sigs.pending().next().is_none() && !touchscreen.button().keyboard().complete() { + let timer = touchscreen.button().next_time().map(|t| t - Instant::now()); + + events.clear(); + poller.modify(&touchscreen, ts_evt).unwrap(); + poller.wait(&mut events, timer).unwrap(); + + if !events.is_empty() { + touchscreen.handle_events(); + } + + touchscreen.dispatch_timers(); + } + + poller.delete(&touchscreen).unwrap(); +}