use std::sync::atomic::{AtomicBool, Ordering};
use ratatui::DefaultTerminal;
static KEYBOARD_ENHANCED: AtomicBool = AtomicBool::new(false);
static MOUSE_CAPTURED: AtomicBool = AtomicBool::new(false);
pub fn init() -> std::io::Result<DefaultTerminal> {
let terminal = ratatui::try_init()?;
push_keyboard_enhancement();
let _ = set_mouse_capture(true);
Ok(terminal)
}
pub fn restore() {
let _ = set_mouse_capture(false);
pop_keyboard_enhancement();
ratatui::restore();
}
pub fn set_mouse_capture(on: bool) -> std::io::Result<()> {
use std::io::Write;
let mut out = std::io::stdout();
if on {
out.write_all(b"\x1b[?1000h\x1b[?1006h")?;
} else {
out.write_all(b"\x1b[?1006l\x1b[?1000l")?;
}
out.flush()?;
MOUSE_CAPTURED.store(on, Ordering::Relaxed);
Ok(())
}
pub fn mouse_captured() -> bool {
MOUSE_CAPTURED.load(Ordering::Relaxed)
}
pub fn suspended<T>(terminal: &mut DefaultTerminal, f: impl FnOnce() -> T) -> std::io::Result<T> {
use crossterm::execute;
use crossterm::terminal::{
EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode,
};
pop_keyboard_enhancement();
let had_mouse = mouse_captured();
if had_mouse {
let _ = set_mouse_capture(false);
}
disable_raw_mode()?;
execute!(std::io::stdout(), LeaveAlternateScreen)?;
let result = f();
enable_raw_mode()?;
execute!(std::io::stdout(), EnterAlternateScreen)?;
repush_keyboard_enhancement();
if had_mouse {
let _ = set_mouse_capture(true);
}
terminal.clear()?; Ok(result)
}
fn push_keyboard_enhancement() {
use crossterm::event::{KeyboardEnhancementFlags, PushKeyboardEnhancementFlags};
use crossterm::execute;
use crossterm::terminal::supports_keyboard_enhancement;
if matches!(supports_keyboard_enhancement(), Ok(true))
&& execute!(
std::io::stdout(),
PushKeyboardEnhancementFlags(KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES)
)
.is_ok()
{
KEYBOARD_ENHANCED.store(true, Ordering::Relaxed);
}
}
fn repush_keyboard_enhancement() {
use crossterm::event::{KeyboardEnhancementFlags, PushKeyboardEnhancementFlags};
use crossterm::execute;
if KEYBOARD_ENHANCED.load(Ordering::Relaxed) {
let _ = execute!(
std::io::stdout(),
PushKeyboardEnhancementFlags(KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES)
);
}
}
fn pop_keyboard_enhancement() {
use crossterm::event::PopKeyboardEnhancementFlags;
use crossterm::execute;
if KEYBOARD_ENHANCED.load(Ordering::Relaxed) {
let _ = execute!(std::io::stdout(), PopKeyboardEnhancementFlags);
}
}