bca71adad7
The "report alternate keys" part of the Kitty keyboard protocol will send an additional codepoint containing the "shifted" version of a key based on the keyboard layout. This is useful for downstream applications which set up keybindings based on symbols instead of exact keys being pressed. For example, underscore (_) with the Alt modifier is sent as minus (-) with Alt and Shift modifiers. A terminal will send the underscore codepoint as an alternate though, and we can use that information and the presence of the Shift modifier to resolve the symbol. Other examples are 'A-(' (sent as 'A-S-9') and 'A-)' (sent as 'A-S-0'). This change allows pushing the "report alternate keys" flag and overwrites the keycode and modifiers for any shifted keys sent by the terminal.
115 lines
2.9 KiB
Rust
115 lines
2.9 KiB
Rust
//! Demonstrates how to block read events.
|
|
//!
|
|
//! cargo run --example event-read
|
|
|
|
use std::io::stdout;
|
|
|
|
use crossterm::event::{
|
|
poll, KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags,
|
|
};
|
|
use crossterm::{
|
|
cursor::position,
|
|
event::{
|
|
read, DisableBracketedPaste, DisableFocusChange, DisableMouseCapture, EnableBracketedPaste,
|
|
EnableFocusChange, EnableMouseCapture, Event, KeyCode,
|
|
},
|
|
execute, queue,
|
|
terminal::{disable_raw_mode, enable_raw_mode},
|
|
Result,
|
|
};
|
|
use std::time::Duration;
|
|
|
|
const HELP: &str = r#"Blocking read()
|
|
- Keyboard, mouse, focus and terminal resize events enabled
|
|
- Hit "c" to print current cursor position
|
|
- Use Esc to quit
|
|
"#;
|
|
|
|
fn print_events() -> Result<()> {
|
|
loop {
|
|
// Blocking read
|
|
let event = read()?;
|
|
|
|
println!("Event: {:?}\r", event);
|
|
|
|
if event == Event::Key(KeyCode::Char('c').into()) {
|
|
println!("Cursor position: {:?}\r", position());
|
|
}
|
|
|
|
if let Event::Resize(x, y) = event {
|
|
let (original_size, new_size) = flush_resize_events((x, y));
|
|
println!("Resize from: {:?}, to: {:?}\r", original_size, new_size);
|
|
}
|
|
|
|
if event == Event::Key(KeyCode::Esc.into()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// Resize events can occur in batches.
|
|
// With a simple loop they can be flushed.
|
|
// This function will keep the first and last resize event.
|
|
fn flush_resize_events(first_resize: (u16, u16)) -> ((u16, u16), (u16, u16)) {
|
|
let mut last_resize = first_resize;
|
|
while let Ok(true) = poll(Duration::from_millis(50)) {
|
|
if let Ok(Event::Resize(x, y)) = read() {
|
|
last_resize = (x, y);
|
|
}
|
|
}
|
|
|
|
(first_resize, last_resize)
|
|
}
|
|
|
|
fn main() -> Result<()> {
|
|
println!("{}", HELP);
|
|
|
|
enable_raw_mode()?;
|
|
|
|
let mut stdout = stdout();
|
|
|
|
let supports_keyboard_enhancement = matches!(
|
|
crossterm::terminal::supports_keyboard_enhancement(),
|
|
Ok(true)
|
|
);
|
|
|
|
if supports_keyboard_enhancement {
|
|
queue!(
|
|
stdout,
|
|
PushKeyboardEnhancementFlags(
|
|
KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
|
|
| KeyboardEnhancementFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES
|
|
| KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS
|
|
| KeyboardEnhancementFlags::REPORT_EVENT_TYPES
|
|
)
|
|
)?;
|
|
}
|
|
|
|
execute!(
|
|
stdout,
|
|
EnableBracketedPaste,
|
|
EnableFocusChange,
|
|
EnableMouseCapture,
|
|
)?;
|
|
|
|
if let Err(e) = print_events() {
|
|
println!("Error: {:?}\r", e);
|
|
}
|
|
|
|
if supports_keyboard_enhancement {
|
|
queue!(stdout, PopKeyboardEnhancementFlags)?;
|
|
}
|
|
|
|
execute!(
|
|
stdout,
|
|
DisableBracketedPaste,
|
|
PopKeyboardEnhancementFlags,
|
|
DisableFocusChange,
|
|
DisableMouseCapture
|
|
)?;
|
|
|
|
disable_raw_mode()
|
|
}
|