use std::time::Duration;
use bevy::{app::AppExit, prelude::*};
use ratatui::crossterm::event::{self, Event::Key, KeyCode, KeyEventKind, KeyModifiers};
use ratatui::layout::Size;
pub struct EventPlugin {
pub control_c_interrupt: bool,
}
impl Default for EventPlugin {
fn default() -> Self {
Self {
control_c_interrupt: true,
}
}
}
impl Plugin for EventPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
app.add_message::<KeyMessage>()
.add_message::<MouseMessage>()
.add_message::<FocusMessage>()
.add_message::<ResizeMessage>()
.add_message::<PasteMessage>()
.add_message::<CrosstermMessage>()
.configure_sets(
Update,
(
InputSet::Pre,
InputSet::EmitCrossterm,
InputSet::CheckEmulation,
InputSet::EmitBevy,
InputSet::Post,
)
.chain(),
)
.add_systems(
PreUpdate,
crossterm_event_system.in_set(InputSet::EmitCrossterm),
);
if self.control_c_interrupt {
app.add_systems(Update, control_c_interrupt_system.in_set(InputSet::Post));
}
}
}
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
pub enum InputSet {
Pre,
EmitCrossterm,
CheckEmulation,
EmitBevy,
Post,
}
#[derive(Message, Deref, Clone, PartialEq, Eq, Hash, Debug)]
pub struct CrosstermMessage(pub event::Event);
#[derive(Message, Deref, Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct KeyMessage(pub event::KeyEvent);
#[derive(Message, Deref, Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct MouseMessage(pub event::MouseEvent);
#[derive(Message, Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum FocusMessage {
Gained,
Lost,
}
#[derive(Message, Deref, Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct ResizeMessage(pub Size);
#[derive(Message, Deref, Clone, PartialEq, Eq, Hash, Debug)]
pub struct PasteMessage(pub String);
pub fn crossterm_event_system(
mut messages: MessageWriter<CrosstermMessage>,
mut keys: MessageWriter<KeyMessage>,
mut mouse: MessageWriter<MouseMessage>,
mut focus: MessageWriter<FocusMessage>,
mut paste: MessageWriter<PasteMessage>,
mut resize: MessageWriter<ResizeMessage>,
) -> Result {
while event::poll(Duration::ZERO)? {
let event = event::read()?;
match event {
Key(event) => {
keys.write(KeyMessage(event));
}
event::Event::FocusLost => {
focus.write(FocusMessage::Lost);
}
event::Event::FocusGained => {
focus.write(FocusMessage::Gained);
}
event::Event::Mouse(event) => {
mouse.write(MouseMessage(event));
}
event::Event::Paste(ref s) => {
paste.write(PasteMessage(s.clone()));
}
event::Event::Resize(columns, rows) => {
resize.write(ResizeMessage(Size::new(columns, rows)));
}
}
messages.write(CrosstermMessage(event));
}
Ok(())
}
fn control_c_interrupt_system(
mut key_messages: MessageReader<KeyMessage>,
mut exit: MessageWriter<AppExit>,
) {
for message in key_messages.read() {
if message.kind == KeyEventKind::Press
&& message.modifiers == KeyModifiers::CONTROL
&& message.code == KeyCode::Char('c')
{
exit.write_default();
}
}
}