diff --git a/examples/event-read.rs b/examples/event-read.rs
index d3103111f..0200ab266 100644
--- a/examples/event-read.rs
+++ b/examples/event-read.rs
@@ -13,7 +13,7 @@ use crossterm::{
read, DisableBracketedPaste, DisableFocusChange, DisableMouseCapture, EnableBracketedPaste,
EnableFocusChange, EnableMouseCapture, Event, KeyCode,
},
- execute,
+ execute, queue,
terminal::{disable_raw_mode, enable_raw_mode},
Result,
};
@@ -69,22 +69,38 @@ fn main() -> Result<()> {
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_EVENT_TYPES
+ )
+ )?;
+ }
+
execute!(
stdout,
EnableBracketedPaste,
EnableFocusChange,
EnableMouseCapture,
- PushKeyboardEnhancementFlags(
- KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
- | KeyboardEnhancementFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES
- | KeyboardEnhancementFlags::REPORT_EVENT_TYPES
- )
)?;
if let Err(e) = print_events() {
println!("Error: {:?}\r", e);
}
+ if supports_keyboard_enhancement {
+ queue!(stdout, PopKeyboardEnhancementFlags)?;
+ }
+
execute!(
stdout,
DisableBracketedPaste,
diff --git a/src/event.rs b/src/event.rs
index 34fd4dd28..7e28d8bf5 100644
--- a/src/event.rs
+++ b/src/event.rs
@@ -932,6 +932,12 @@ pub(crate) enum InternalEvent {
/// A cursor position (`col`, `row`).
#[cfg(unix)]
CursorPosition(u16, u16),
+ /// The progressive keyboard enhancement flags enabled by the terminal.
+ #[cfg(unix)]
+ KeyboardEnhancementFlags(KeyboardEnhancementFlags),
+ /// Attributes and architectural class of the terminal.
+ #[cfg(unix)]
+ PrimaryDeviceAttributes,
}
#[cfg(test)]
diff --git a/src/event/filter.rs b/src/event/filter.rs
index 2b7e29290..f78730dcd 100644
--- a/src/event/filter.rs
+++ b/src/event/filter.rs
@@ -17,6 +17,35 @@ impl Filter for CursorPositionFilter {
}
}
+#[cfg(unix)]
+#[derive(Debug, Clone)]
+pub(crate) struct KeyboardEnhancementFlagsFilter;
+
+#[cfg(unix)]
+impl Filter for KeyboardEnhancementFlagsFilter {
+ fn eval(&self, event: &InternalEvent) -> bool {
+ // This filter checks for either a KeyboardEnhancementFlags response or
+ // a PrimaryDeviceAttributes response. If we receive the PrimaryDeviceAttributes
+ // response but not KeyboardEnhancementFlags, the terminal does not support
+ // progressive keyboard enhancement.
+ matches!(
+ *event,
+ InternalEvent::KeyboardEnhancementFlags(_) | InternalEvent::PrimaryDeviceAttributes
+ )
+ }
+}
+
+#[cfg(unix)]
+#[derive(Debug, Clone)]
+pub(crate) struct PrimaryDeviceAttributesFilter;
+
+#[cfg(unix)]
+impl Filter for PrimaryDeviceAttributesFilter {
+ fn eval(&self, event: &InternalEvent) -> bool {
+ matches!(*event, InternalEvent::PrimaryDeviceAttributes)
+ }
+}
+
#[derive(Debug, Clone)]
pub(crate) struct EventFilter;
@@ -45,7 +74,8 @@ impl Filter for InternalEventFilter {
#[cfg(unix)]
mod tests {
use super::{
- super::Event, CursorPositionFilter, EventFilter, Filter, InternalEvent, InternalEventFilter,
+ super::Event, CursorPositionFilter, EventFilter, Filter, InternalEvent,
+ InternalEventFilter, KeyboardEnhancementFlagsFilter, PrimaryDeviceAttributesFilter,
};
#[test]
@@ -54,6 +84,23 @@ mod tests {
assert!(CursorPositionFilter.eval(&InternalEvent::CursorPosition(0, 0)));
}
+ #[test]
+ fn test_keyboard_enhancement_status_filter_filters_keyboard_enhancement_status() {
+ assert!(!KeyboardEnhancementFlagsFilter.eval(&InternalEvent::Event(Event::Resize(10, 10))));
+ assert!(
+ KeyboardEnhancementFlagsFilter.eval(&InternalEvent::KeyboardEnhancementFlags(
+ crate::event::KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
+ ))
+ );
+ assert!(KeyboardEnhancementFlagsFilter.eval(&InternalEvent::PrimaryDeviceAttributes));
+ }
+
+ #[test]
+ fn test_primary_device_attributes_filter_filters_primary_device_attributes() {
+ assert!(!PrimaryDeviceAttributesFilter.eval(&InternalEvent::Event(Event::Resize(10, 10))));
+ assert!(PrimaryDeviceAttributesFilter.eval(&InternalEvent::PrimaryDeviceAttributes));
+ }
+
#[test]
fn test_event_filter_filters_events() {
assert!(EventFilter.eval(&InternalEvent::Event(Event::Resize(10, 10))));
diff --git a/src/event/sys/unix/parse.rs b/src/event/sys/unix/parse.rs
index 0cfbd1a5e..654cee682 100644
--- a/src/event/sys/unix/parse.rs
+++ b/src/event/sys/unix/parse.rs
@@ -2,8 +2,9 @@ use std::io;
use crate::{
event::{
- Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers, MediaKeyCode,
- ModifierKeyCode, MouseButton, MouseEvent, MouseEventKind,
+ Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers,
+ KeyboardEnhancementFlags, MediaKeyCode, ModifierKeyCode, MouseButton, MouseEvent,
+ MouseEventKind,
},
ErrorKind, Result,
};
@@ -177,6 +178,11 @@ pub(crate) fn parse_csi(buffer: &[u8]) -> Result