Event handling in winit: How does it work?

Hello, I am rather new to Rust and have been trying to get at least a very rough understanding of how the winit library is working under the hood. I have been looking through the source code on github, but seem to have hit a wall very early. My problem lies in understanding how listening to events and handling of said events are connected.

Note added: I am looking into the winit implementation for Windows systems.

So, the event loop in winit is run via:

event_loop.run(move |event, _, control_flow| { //(…)
}

To my understanding, what the run() function here does is:

  • Runs the ‘main loop in event_loop.rs , which continuously listens to and dispatches events
  • Passes the content of the closure (the user instructions on what to do on specific events) to the function set_event_handler() in runner.rs .

Now, naively, I would have expected that the event handling instructions (the content of the closure) need to be part of the ‘main loop in event_loop.rs . So that the ‘main loop would look somewhat like this (pseudo code):

'main: loop {

//(…)

winuser::TranslateMessage(&mut msg);

winuser::DispatchMessageW(&mut msg);

match msg {

Event::MouseButtonPressed => make_click_sound(),

Event::EnterKeyPressed => do_whatever(),

//(…)

But obviously the event matching is not part of the ‘main loop. So, this is what I don’t understand:

How do the events which are retrieved in the ‘main loop even cause a reaction? How do the instructions on how to handle certain events (or in other words, the closure which is passed to the run() function) even come into play here?

Could someone please give me a hint to understand how/why this is working?

I looked a bit. Not terribly familiar with the code or windows GUI but it seems like the part you’re missing is public_window_callback in the event_loop module. It’s a callback registered with Windows that gets called by DispatchMessageW. You’d need to look at it more to trace the path of how the events end up getting passed the the event_handler but hopefully that helps you along a bit.

1 Like

Thanks a lot for looking into it, this is really helpful!

public_window_callback really seems to be the right track, now I see that this function is even commented with: “This is the callback that is called by DispatchMessage in the events loop.”

I think I understand how the event_handler is supplied with the user defined event instructions from event_loop.run(move |event, _, control_flow| { (…) }.
But what I still don’t understand is how public_window_callback knows about event_handler. If I see it correctly, public_window_callback already contains definitions of how to handle a number of system events (such as WM_ENTERSIZEMOVE, for example). But how the user defined event instructions within event_handler are being checked upon, this is still not clear to me.

But this brought me one step further. I'll look further into it, maybe I can proceed from here.