From c5a41244b4bd7575448b9ce75281cf3d9db843f2 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Mon, 21 Apr 2025 05:51:07 +0000 Subject: [PATCH] handle tty raw mode ourselves --- Cargo.toml | 2 +- linux/src/keys.rs | 1 + linux/src/lib.rs | 2 +- linux/src/raw.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++++ src/bin/main.rs | 19 +++++++------- 5 files changed, 78 insertions(+), 11 deletions(-) create mode 100644 linux/src/keys.rs create mode 100644 linux/src/raw.rs diff --git a/Cargo.toml b/Cargo.toml index fcb18be..57e098c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ default-run = "ming" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [workspace] -members = ["linux"] +members = [ "linux" ] [build-dependencies] bmp-rust = "0.5.0" diff --git a/linux/src/keys.rs b/linux/src/keys.rs new file mode 100644 index 0000000..ab0c014 --- /dev/null +++ b/linux/src/keys.rs @@ -0,0 +1 @@ +// \ No newline at end of file diff --git a/linux/src/lib.rs b/linux/src/lib.rs index 049ad2d..138fb7b 100644 --- a/linux/src/lib.rs +++ b/linux/src/lib.rs @@ -1,2 +1,2 @@ pub mod fb; - +pub mod raw; diff --git a/linux/src/raw.rs b/linux/src/raw.rs new file mode 100644 index 0000000..e75e737 --- /dev/null +++ b/linux/src/raw.rs @@ -0,0 +1,65 @@ +use std::io::Stdout; +use std::mem::zeroed; +use std::os::fd::AsRawFd; + +use libc::{ cfmakeraw, c_int, tcgetattr, tcsetattr, termios, TCSAFLUSH }; + +//https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html +//on TCSAFLUSH: "The TCSAFLUSH argument specifies when to apply the change: in this case, it waits for all pending output to be written to the terminal, and also discards any input that hasn't been read." + +//https://www.man7.org/linux/man-pages/man3/termios.3.html +//(use cfmakeraw instead doing all those bitwise stuff manually) + +//enter and exit tty raw mode + +pub struct RawStdout { + pub stdout: Stdout, + old_termios: termios, +} + +impl RawStdout { + pub fn new(stdout: Stdout) -> Self { + RawStdout { + stdout, + old_termios: unsafe { zeroed() }, + } + } + + pub fn get_termios(raw_fd: c_int) -> Result { + let mut termios_struct: termios = unsafe { zeroed() }; + let result = unsafe { + tcgetattr(raw_fd, &mut termios_struct) + }; + if result != -1 { + Ok(termios_struct) + } else { + Err(()) + } + } + + pub fn enter_raw_mode(&mut self) -> Result<(), ()> { + let raw_fd = self.stdout.as_raw_fd(); + let mut termios_struct = Self::get_termios(raw_fd)?; + self.old_termios = termios_struct; + let result = unsafe { + cfmakeraw(&mut termios_struct); + tcsetattr(raw_fd, TCSAFLUSH, &mut termios_struct) + }; + if result != -1 { + Ok(()) + } else { + Err(()) + } + } + + pub fn exit_raw_mode(&mut self) -> Result<(), ()> { + let result = unsafe { + tcsetattr(self.stdout.as_raw_fd(), TCSAFLUSH, &mut self.old_termios) + }; + if result != -1 { + Ok(()) + } else { + Err(()) + } + } +} diff --git a/src/bin/main.rs b/src/bin/main.rs index 4c09208..abf8280 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -7,8 +7,8 @@ use std::process::exit; use std::env; use linux::fb::Framebuffer; +use linux::raw::RawStdout; use termion::input::TermRead; -use termion::raw::IntoRawMode; use termion::event::Key; use ming_wm_lib::window_manager_types::KeyChar; @@ -73,13 +73,14 @@ fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { let mut wm: WindowManager = WindowManager::new(writer, framebuffer, dimensions, rotate, grayscale); - let mut stdout = stdout().into_raw_mode().unwrap(); + let mut stdout = RawStdout::new(stdout()); + stdout.enter_raw_mode().unwrap(); - write!(stdout, "{}", CLEAR_ALL).unwrap(); + write!(stdout.stdout, "{}", CLEAR_ALL).unwrap(); - write!(stdout, "{}", HIDE_CURSOR).unwrap(); + write!(stdout.stdout, "{}", HIDE_CURSOR).unwrap(); - stdout.flush().unwrap(); + stdout.stdout.flush().unwrap(); wm.draw(None, false); @@ -154,13 +155,13 @@ fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { ThreadMessage::KeyChar(kc) => wm.handle_message(WindowManagerMessage::KeyChar(kc.clone())), ThreadMessage::Touch(x, y) => wm.handle_message(WindowManagerMessage::Touch(x, y)), ThreadMessage::Clear => { - write!(stdout, "{}", CLEAR_ALL).unwrap(); - stdout.flush().unwrap(); + write!(stdout.stdout, "{}", CLEAR_ALL).unwrap(); + stdout.stdout.flush().unwrap(); }, ThreadMessage::Exit => { if !wm.locked { - write!(stdout, "{}", SHOW_CURSOR).unwrap(); - stdout.suspend_raw_mode().unwrap(); + write!(stdout.stdout, "{}", SHOW_CURSOR).unwrap(); + stdout.exit_raw_mode().unwrap(); exit(0); } },