use crossterm::event::{Event, KeyEvent, MouseEvent};
use std::rc::Rc;
use sycamore_reactive::{create_signal, use_context, use_current_scope};
use tokio::sync::broadcast;
use tokio::task::spawn_local;
#[derive(Debug, Clone)]
pub(crate) struct Events(pub Rc<broadcast::Receiver<Event>>);
#[inline]
#[track_caller]
pub fn on_event(mut fun: impl FnMut(Event) + 'static) {
let mut rx = use_context::<Events>().0.resubscribe();
let trigger = create_signal(());
let scope = use_current_scope();
spawn_local(async move {
while let Ok(event) = rx.recv().await {
if !trigger.is_alive() {
return;
} else {
scope.run_in(|| fun(event));
}
}
});
}
#[inline]
#[track_caller]
pub fn on_key(mut fun: impl FnMut(KeyEvent) + 'static) {
on_event(move |event| {
if let Some(key_event) = event.as_key_event() {
fun(key_event);
}
})
}
#[inline]
#[track_caller]
pub fn on_mouse(mut fun: impl FnMut(MouseEvent) + 'static) {
on_event(move |event| {
if let Some(mouse_event) = event.as_mouse_event() {
fun(mouse_event);
}
})
}
#[inline]
#[track_caller]
pub fn on_resize(mut fun: impl FnMut(u16, u16) + 'static) {
on_event(move |event| {
if let Some((x, y)) = event.as_resize_event() {
fun(x, y);
}
})
}
#[inline]
#[track_caller]
pub fn on_key_press(mut fun: impl FnMut(KeyEvent) + 'static) {
on_event(move |event| {
if let Some(key_event) = event.as_key_press_event() {
fun(key_event);
}
})
}