1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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();
}
|