veeso / tui-realm

👑 tui-rs framework to build stateful applications with a React/Elm inspired approach
MIT License
558 stars 25 forks source link

[QUESTION] - How to handle ctrl+c on raw mode? #39

Closed stevefan1999-personal closed 2 years ago

stevefan1999-personal commented 2 years ago

I tried adding it to any components, which here I used the Label component from the example, but it doesn't work so far:

impl Component<Msg, NoUserEvent> for Label {
    fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
        match ev {
            Event::Keyboard(KeyEvent {
                code: Key::Char('c'),
                modifiers: KeyModifiers::CONTROL,
            })
            | Event::Keyboard(KeyEvent {
                code: Key::Esc,
                modifiers: KeyModifiers::NONE,
            }) => Some(Msg::AppClose),

            _ => None,
        }
    }
}

Envionrment

OS: Windows 11 tuirealm version: 1.6.0

stevefan1999-personal commented 2 years ago

I tried to handle this by using an external ctrl+c handler from tokio, then I sent an empty tuple using a MPSC channel, and did blocking receive on the TUI thread for each loop, then send AppClose event over there. But it didn't work as well.

veeso commented 2 years ago

Does the esc key work? Did you give focus to the label?

Just for the record, to terminate the application, it is better to use subscriptions to a phantom component, in order to always listen for that event, beside of what component has the focus.

You can view an example here:

#[derive(Default, MockComponent)]
pub struct GlobalListener {
    component: Phantom,
}

impl Component<Msg, NoUserEvent> for GlobalListener {
    fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
        match ev {
            Event::Keyboard(KeyEvent {
                code: Key::Esc | Key::Function(10),
                ..
            }) => Some(Msg::Ui(UiMsg::ShowQuitPopup)),
            Event::Keyboard(KeyEvent {
                code: Key::Char('c'),
                modifiers: KeyModifiers::CONTROL,
            }) => Some(Msg::Form(FormMsg::EnterSetup)),
            Event::WindowResize(_, _) => Some(Msg::Ui(UiMsg::WindowResized)),
            _ => None,
        }
    }
}

            self
            .app
            .mount(
                Id::GlobalListener,
                Box::new(components::GlobalListener::default()),
                vec![
                    Sub::new(
                        SubEventClause::Keyboard(KeyEvent {
                            code: Key::Esc,
                            modifiers: KeyModifiers::NONE,
                        }),
                        Self::no_popup_mounted_clause(),
                    ),
                    Sub::new(
                        SubEventClause::Keyboard(KeyEvent {
                            code: Key::Function(10),
                            modifiers: KeyModifiers::NONE,
                        }),
                        Self::no_popup_mounted_clause(),
                    ),
                    Sub::new(
                        SubEventClause::Keyboard(KeyEvent {
                            code: Key::Char('c'),
                            modifiers: KeyModifiers::CONTROL,
                        }),
                        Self::no_popup_mounted_clause(),
                    ),
                    Sub::new(SubEventClause::WindowResize, SubClause::Always)
                ]
            )