Skip to content

Commit

Permalink
Add is_* and as_* methods to the event enums (#949)
Browse files Browse the repository at this point in the history
* Add is_ and as_ methods to the event enums

Often application code only cares about a small subset of possible
events. These methods make it simpler to write code which checks whether
an event is a particular event type or converts events into the specific
type (returning an Option).

This can help simplify some nested match blocks. E.g.:

```rust
match event {
    Event::Key(key) if key.kind == KeyEventKind::Press => { ... }
}
```

becomes:

```rust
if let Some(key) = event.as_key_press() { ... }
```

Similar flexible methods are aded across all the event enums:

- `Event::is_focus_gained()`
- `Event::is_focus_lost()`
- `Event::is_key()`
- `Event::is_mouse()`
- `Event::is_paste()`
- `Event::is_resize()`
- `Event::is_key_press()`
- `Event::as_key_press() -> Option<&KeyEvent>`
- `MouseEventKind::is_*()`
- `MouseButton::is_*()`
- `KeyEventKind::is_*()`
- `KeyEvent::is_press()`
- `KeyEvent::is_release()`
- `KeyEvent::is_repeat()`
- `KeyCode::is_*()`
- `KeyCode::is_function_key(n)`
- `KeyCode::is_char(c)`
- `KeyCode::as_char() -> Option<char>`
- `KeyCode::is_media_key(media)`
- `KeyCode::is_modifier(modifier)`
- add is_key_release() and is_key_repeat() checks
- add as_key_event()
- rename as_key_press() to as_key_press_event()
- add as_key_repeat_event()
- add as_key_release_event()
- add as_mouse_event()
- add as_paste_event()
- more tests
- update event-match and key-display examples
  • Loading branch information
joshka authored Feb 2, 2025
1 parent 1bcfa97 commit e063091
Show file tree
Hide file tree
Showing 4 changed files with 450 additions and 55 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ use-dev-tty = ["filedescriptor", "rustix/process"]

[dependencies]
bitflags = { version = "2.3" }
derive_more = { version = "1.0.0", features = ["is_variant"] }
document-features = "0.2.10"
futures-core = { version = "0.3", optional = true, default-features = false }
parking_lot = "0.12"
Expand Down
67 changes: 33 additions & 34 deletions examples/event-match-modifiers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,42 @@
use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};

fn match_event(read_event: Event) {
match read_event {
// Match one one modifier:
Event::Key(KeyEvent {
modifiers: KeyModifiers::CONTROL,
code,
..
}) => {
println!("Control + {:?}", code);
}
Event::Key(KeyEvent {
modifiers: KeyModifiers::SHIFT,
code,
..
}) => {
println!("Shift + {:?}", code);
}
Event::Key(KeyEvent {
modifiers: KeyModifiers::ALT,
code,
..
}) => {
println!("Alt + {:?}", code);
}
fn match_event(event: Event) {
if let Some(key) = event.as_key_press_event() {
match key {
KeyEvent {
modifiers: KeyModifiers::CONTROL,
code,
..
} => {
println!("Control + {:?}", code);
}
KeyEvent {
modifiers: KeyModifiers::SHIFT,
code,
..
} => {
println!("Shift + {:?}", code);
}
KeyEvent {
modifiers: KeyModifiers::ALT,
code,
..
} => {
println!("Alt + {:?}", code);
}

// Match on multiple modifiers:
Event::Key(KeyEvent {
code, modifiers, ..
}) => {
if modifiers == (KeyModifiers::ALT | KeyModifiers::SHIFT) {
println!("Alt + Shift {:?}", code);
} else {
println!("({:?}) with key: {:?}", modifiers, code)
// Match on multiple modifiers:
KeyEvent {
code, modifiers, ..
} => {
if modifiers == (KeyModifiers::ALT | KeyModifiers::SHIFT) {
println!("Alt + Shift {:?}", code);
} else {
println!("({:?}) with key: {:?}", modifiers, code)
}
}
}

_ => {}
}
}

Expand Down
29 changes: 13 additions & 16 deletions examples/key-display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
use std::io;

use crossterm::event::{KeyEventKind, KeyModifiers};
use crossterm::event::KeyModifiers;
use crossterm::{
event::{read, Event, KeyCode},
event::{read, KeyCode},
terminal::{disable_raw_mode, enable_raw_mode},
};

Expand All @@ -29,20 +29,17 @@ fn main() -> io::Result<()> {
}

fn print_events() -> io::Result<()> {
loop {
let event = read()?;
match event {
Event::Key(event) if event.kind == KeyEventKind::Press => {
print!("Key pressed: ");
if event.modifiers != KeyModifiers::NONE {
print!("{}+", event.modifiers);
}
println!("{}\r", event.code);
if event.code == KeyCode::Esc {
break;
}
}
_ => {}
while let Ok(event) = read() {
let Some(event) = event.as_key_press_event() else {
continue;
};
let modifier = match event.modifiers {
KeyModifiers::NONE => "".to_string(),
_ => format!("{:}+", event.modifiers),
};
println!("Key pressed: {modifier}{code}\r", code = event.code);
if event.code == KeyCode::Esc {
break;
}
}
Ok(())
Expand Down
Loading

0 comments on commit e063091

Please sign in to comment.