Window/Document-level Keyboard Events in Tauri and Yew

I’m writing a GUI app in Rust, trying to get it working with Tauri’s tooling, using Yew to generate the actual user-facing code. I thought it would be easy to get a thing that notices when I hit a key, and do stuff with it. Pre-yew-0.19 you could do this with a KeyboardService, now it’s a whole thing with gloo.

The example they provide doesn’t indicate how to do this without binding it to a HTML element. Turns out, you just have to hold your tongue differently and bind it to the document. It’s even neater at the end for me, because I loathe the magic behind their function_component implementations.

Someone pointed me to this issue in the yewstack repo which involved adding gloo to my app so I could use the EventListener functionality.

This took me days to find a working example of, provided by a very helpful person on Tauri’s Discord server… so here’s the code:

use gloo::events::EventListener;
use web_sys::KeyboardEvent;



// Yew component messages
enum Msg{
    KeyEvent { event: KeyboardEvent },
}

pub struct App {
    /// Holds the listener once it's stood up. Can't be done before rendering because... the document doesn't exist yet!
    pub kbd_listener: Option<EventListener>,
}


impl Component for App {
    //<snip other stuff>

    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
        match msg {
            Msg::KeyEvent { event } => {
                let logline = &format!(
                    "Key event in browser, no action required. Pressed: {:?}",
                    event.key_code()
                );
                true
            }
        }
    }

fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
        // we only need to run the below stuff the first time
        if !first_render {
            return;
        }

        let document = web_sys::window().unwrap().document().unwrap();
        let ct = ctx.link().to_owned();
        let listener = EventListener::new(&document, "keydown", move |event| {
            let event = event
                .dyn_ref::<KeyboardEvent>()
                .unwrap_throw()
                .to_owned();
            ct.send_message(Msg::KeyEvent { event });
        });

        self.kbd_listener.replace(listener);
    }
}


#rust #yew #tauri #gloo #onkeydown #onkeyup #keypress