diff --git a/src/event.rs b/src/event.rs
index 3e308c1a..883a3019 100644
--- a/src/event.rs
+++ b/src/event.rs
@@ -54,6 +54,7 @@
//! #[cfg(feature = "bracketed-paste")]
//! Event::Paste(data) => println!("{:?}", data),
//! Event::Resize(width, height) => println!("New size {}x{}", width, height),
+//! Event::ApplicationProgramCommand(command) => println!("New APC {}", command),
//! }
//! }
//! execute!(
@@ -100,6 +101,7 @@
//! #[cfg(feature = "bracketed-paste")]
//! Event::Paste(data) => println!("Pasted {:?}", data),
//! Event::Resize(width, height) => println!("New size {}x{}", width, height),
+//! Event::ApplicationProgramCommand(command) => println!("New APC {}", command),
//! }
//! } else {
//! // Timeout expired and no `Event` is available
@@ -563,6 +565,9 @@ pub enum Event {
/// A resize event with new dimensions after resize (columns, rows).
/// **Note** that resize events can occur in batches.
Resize(u16, u16),
+ /// Application Program Command sent by the terminal.
+ /// Primarily used by the Kitty terminal for graphics commands.
+ ApplicationProgramCommand(String),
}
impl Event {
@@ -755,6 +760,28 @@ impl Event {
_ => None,
}
}
+
+ /// Returns the string of the command if the event is a APC event, otherwise `None`.
+ ///
+ /// This is a convenience method that makes code which only cares about resize events easier to write.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use crossterm::event;
+ ///
+ /// while let Some(command) = event::read()?.as_apc_event() {
+ /// // ...
+ /// }
+ /// # std::io::Result::Ok(())
+ /// ```
+ #[inline]
+ pub fn as_apc_event(&self) -> Option<&str> {
+ match self {
+ Event::ApplicationProgramCommand(command) => Some(command),
+ _ => None,
+ }
+ }
}
/// Represents a mouse event.
@@ -1713,35 +1740,66 @@ mod tests {
assert_eq!(event.as_key_press_event(), Some(ESC_PRESSED));
assert_eq!(event.as_key_release_event(), None);
assert_eq!(event.as_key_repeat_event(), None);
+ assert_eq!(event.as_mouse_event(), None);
assert_eq!(event.as_resize_event(), None);
+ assert_eq!(event.as_apc_event(), None);
let event = Event::Key(ESC_RELEASED);
assert_eq!(event.as_key_event(), Some(ESC_RELEASED));
assert_eq!(event.as_key_release_event(), Some(ESC_RELEASED));
assert_eq!(event.as_key_press_event(), None);
assert_eq!(event.as_key_repeat_event(), None);
+ assert_eq!(event.as_mouse_event(), None);
assert_eq!(event.as_resize_event(), None);
+ assert_eq!(event.as_apc_event(), None);
let event = Event::Key(ESC_REPEAT);
assert_eq!(event.as_key_event(), Some(ESC_REPEAT));
assert_eq!(event.as_key_repeat_event(), Some(ESC_REPEAT));
assert_eq!(event.as_key_press_event(), None);
assert_eq!(event.as_key_release_event(), None);
+ assert_eq!(event.as_mouse_event(), None);
assert_eq!(event.as_resize_event(), None);
+ assert_eq!(event.as_apc_event(), None);
let event = Event::Resize(1, 1);
assert_eq!(event.as_resize_event(), Some((1, 1)));
assert_eq!(event.as_key_event(), None);
+ assert_eq!(event.as_key_release_event(), None);
+ assert_eq!(event.as_key_press_event(), None);
+ assert_eq!(event.as_key_repeat_event(), None);
+ assert_eq!(event.as_mouse_event(), None);
+ assert_eq!(event.as_apc_event(), None);
let event = Event::Mouse(MOUSE_CLICK);
assert_eq!(event.as_mouse_event(), Some(MOUSE_CLICK));
assert_eq!(event.as_key_event(), None);
+ assert_eq!(event.as_key_release_event(), None);
+ assert_eq!(event.as_key_press_event(), None);
+ assert_eq!(event.as_key_repeat_event(), None);
+ assert_eq!(event.as_resize_event(), None);
+ assert_eq!(event.as_apc_event(), None);
#[cfg(feature = "bracketed-paste")]
{
let event = Event::Paste("".to_string());
assert_eq!(event.as_paste_event(), Some(""));
assert_eq!(event.as_key_event(), None);
+ assert_eq!(event.as_key_release_event(), None);
+ assert_eq!(event.as_key_press_event(), None);
+ assert_eq!(event.as_key_repeat_event(), None);
+ assert_eq!(event.as_resize_event(), None);
+ assert_eq!(event.as_mouse_event(), None);
+ assert_eq!(event.as_apc_event(), None);
}
+
+ let event = Event::ApplicationProgramCommand("".to_string());
+ assert_eq!(event.as_apc_event(), Some(""));
+ assert_eq!(event.as_key_event(), None);
+ assert_eq!(event.as_key_release_event(), None);
+ assert_eq!(event.as_key_press_event(), None);
+ assert_eq!(event.as_key_repeat_event(), None);
+ assert_eq!(event.as_resize_event(), None);
+ assert_eq!(event.as_mouse_event(), None);
}
}
diff --git a/src/event/sys/unix/parse.rs b/src/event/sys/unix/parse.rs
index 29377438..9769a1a0 100644
--- a/src/event/sys/unix/parse.rs
+++ b/src/event/sys/unix/parse.rs
@@ -1,4 +1,4 @@
-use std::io;
+use std::{io, str};
use crate::event::{
Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers, KeyboardEnhancementFlags,
@@ -75,6 +75,7 @@ pub(crate) fn parse_event(
}
b'[' => parse_csi(buffer),
b'\x1B' => Ok(Some(InternalEvent::Event(Event::Key(KeyCode::Esc.into())))),
+ b'_' => parse_apc(buffer),
_ => parse_event(&buffer[1..], input_available).map(|event_option| {
event_option.map(|event| {
if let InternalEvent::Event(Event::Key(key_event)) = event {
@@ -134,6 +135,20 @@ fn char_code_to_event(code: KeyCode) -> KeyEvent {
KeyEvent::new(code, modifiers)
}
+pub(crate) fn parse_apc(buffer: &[u8]) -> io::Result