summaryrefslogtreecommitdiff
path: root/src/term.rs
blob: b11bbdcf339c7b9e6d851ff63cd0c26f02badce8 (plain)
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();
}