summaryrefslogtreecommitdiff
path: root/src/term.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/term.rs')
-rw-r--r--src/term.rs50
1 files changed, 50 insertions, 0 deletions
diff --git a/src/term.rs b/src/term.rs
new file mode 100644
index 0000000..b11bbdc
--- /dev/null
+++ b/src/term.rs
@@ -0,0 +1,50 @@
+//! Terminal setup and teardown.
+
+use std::io::{self, stdout};
+
+use ratatui::DefaultTerminal;
+use ratatui::crossterm::event::{
+ KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags,
+};
+use ratatui::crossterm::{execute, terminal};
+
+/// What this terminal can tell us about the keyboard.
+#[derive(Clone, Copy, Debug)]
+pub struct KeyboardCaps {
+ /// The terminal reports key releases (the kitty keyboard protocol), so a
+ /// scene can know a key is being held. Without it, holding a key looks
+ /// like one press, a ~0.5 s pause, then auto-repeats, and real-time
+ /// controls need a fallback such as a throttle you step up and down.
+ pub key_release: bool,
+}
+
+/// Raw mode, alternate screen, and the kitty keyboard protocol where available.
+pub fn init() -> io::Result<(DefaultTerminal, KeyboardCaps)> {
+ let terminal = ratatui::try_init()?;
+ let key_release = terminal::supports_keyboard_enhancement().unwrap_or(false);
+ if key_release {
+ execute!(
+ stdout(),
+ PushKeyboardEnhancementFlags(
+ KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
+ | KeyboardEnhancementFlags::REPORT_EVENT_TYPES
+ )
+ )?;
+ // ratatui's panic hook restores raw mode and the alternate screen but
+ // not these flags, which would leave the shell receiving kitty-encoded
+ // keys. Pop them first, then hand over to ratatui's hook.
+ let previous = std::panic::take_hook();
+ std::panic::set_hook(Box::new(move |info| {
+ let _ = execute!(stdout(), PopKeyboardEnhancementFlags);
+ previous(info);
+ }));
+ }
+ Ok((terminal, KeyboardCaps { key_release }))
+}
+
+pub fn restore(caps: KeyboardCaps) {
+ if caps.key_release {
+ let _ = execute!(stdout(), PopKeyboardEnhancementFlags);
+ }
+ ratatui::restore();
+}