diff --git a/Cargo.toml b/Cargo.toml index aa23a87c..f0555e5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ event-stream = ["dep:futures-core", "events"] # Enables async events use-dev-tty = ["filedescriptor"] # Enables raw file descriptor polling / selecting instead of mio. events = ["dep:mio", "dep:signal-hook", "dep:signal-hook-mio"] # Enables reading input/events from the system. serde = ["dep:serde", "bitflags/serde"] # Enables 'serde' for various types. +event-kind = ["events"] # Enables a 'release' event for input for windows and kitty protocol. # # Shared dependencies @@ -81,7 +82,7 @@ serde_json = "1.0" # [[example]] name = "event-read" -required-features = ["bracketed-paste", "events"] +required-features = ["bracketed-paste", "events", "event-kind"] [[example]] name = "event-match-modifiers" diff --git a/examples/interactive-demo/src/test/color.rs b/examples/interactive-demo/src/test/color.rs index dc37d3ba..d34ac457 100644 --- a/examples/interactive-demo/src/test/color.rs +++ b/examples/interactive-demo/src/test/color.rs @@ -1,6 +1,5 @@ #![allow(clippy::cognitive_complexity)] -use crate::Result; use crossterm::{cursor, queue, style, style::Color}; use std::io::Write; diff --git a/examples/key-test.rs b/examples/key-test.rs new file mode 100644 index 00000000..ffe7e7ab --- /dev/null +++ b/examples/key-test.rs @@ -0,0 +1,17 @@ +//! Demonstrates how to match on modifiers like: Control, alt, shift. +//! +//! cargo run --example event-poll-read + +use std::{io, time::Duration}; + +use crossterm::{ + cursor::position, + event::{poll, read, DisableMouseCapture, EnableMouseCapture, Event, KeyCode}, + execute, + terminal::{disable_raw_mode, enable_raw_mode}, +}; +pub fn main() { + crossterm::terminal::enable_raw_mode().unwrap(); + let result = crossterm::event::read(); + eprintln!("RESULT: {:?}", result); +} diff --git a/src/event.rs b/src/event.rs index b93c8acd..30194ead 100644 --- a/src/event.rs +++ b/src/event.rs @@ -255,6 +255,7 @@ bitflags! { const DISAMBIGUATE_ESCAPE_CODES = 0b0000_0001; /// Add extra events with [`KeyEvent.kind`] set to [`KeyEventKind::Repeat`] or /// [`KeyEventKind::Release`] when keys are autorepeated or released. + /// IMPORTANT: Requires feature `event-kind` to be enabled. const REPORT_EVENT_TYPES = 0b0000_0010; // Send [alternate keycodes](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#key-codes) // in addition to the base keycode. The alternate keycode overrides the base keycode in diff --git a/src/event/sys/unix/parse.rs b/src/event/sys/unix/parse.rs index c40cebc5..93b51686 100644 --- a/src/event/sys/unix/parse.rs +++ b/src/event/sys/unix/parse.rs @@ -340,6 +340,7 @@ fn parse_key_event_kind(kind: u8) -> KeyEventKind { match kind { 1 => KeyEventKind::Press, 2 => KeyEventKind::Repeat, + #[cfg(feature = "event-kind")] 3 => KeyEventKind::Release, _ => KeyEventKind::Press, } diff --git a/src/event/sys/windows/parse.rs b/src/event/sys/windows/parse.rs index 288b7479..9ea94c19 100644 --- a/src/event/sys/windows/parse.rs +++ b/src/event/sys/windows/parse.rs @@ -223,7 +223,11 @@ fn parse_key_event_record(key_event: &KeyEventRecord) -> Option let kind = if key_event.key_down { KeyEventKind::Press } else { - KeyEventKind::Release + if cfg!(feature = "event-kind") { + KeyEventKind::Release + } else { + KeyEventKind::Press + } }; let key_event = KeyEvent::new_with_kind(key_code, modifiers, kind); return Some(WindowsKeyEvent::KeyEvent(key_event)); @@ -235,10 +239,20 @@ fn parse_key_event_record(key_event: &KeyEventRecord) -> Option let is_numpad_numeric_key = (VK_NUMPAD0..=VK_NUMPAD9).contains(&virtual_key_code); let is_only_alt_modifier = modifiers.contains(KeyModifiers::ALT) && !modifiers.contains(KeyModifiers::SHIFT | KeyModifiers::CONTROL); + if is_only_alt_modifier && is_numpad_numeric_key { return None; } + if !key_event.key_down && virtual_key_code == VK_RETURN { + // For some reason in some cases we receive a release ENTER event here at the application start. + // This might have to do with the initial enter when running a CLI command. + // We early exit here to prevent confusion. + // + // https://github.com/crossterm-rs/crossterm/issues/752 + return None; + } + let parse_result = match virtual_key_code { VK_SHIFT | VK_CONTROL | VK_MENU => None, VK_BACK => Some(KeyCode::Backspace), @@ -286,7 +300,11 @@ fn parse_key_event_record(key_event: &KeyEventRecord) -> Option let kind = if key_event.key_down { KeyEventKind::Press } else { - KeyEventKind::Release + if cfg!(feature = "event-kind") { + KeyEventKind::Release + } else { + KeyEventKind::Press + } }; let key_event = KeyEvent::new_with_kind(key_code, modifiers, kind); return Some(WindowsKeyEvent::KeyEvent(key_event));