sokol icon indicating copy to clipboard operation
sokol copied to clipboard

Add sokol_app callback before event queue is iterated (or add an input polling API)

Open kavika13 opened this issue 5 years ago • 2 comments

For some third-party libraries (right now I'm just thinking about Nuklear) it would be useful to have a callback that is called before the event queue gets processed for the given frame.

E.g. for the win32 implementation:

_sapp_before_events();  // Adding this callback would be useful

MSG msg;
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
    if (WM_QUIT == msg.message) {
        done = true;
        continue;
    }
    else {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}
_sapp_frame();

The reason this would be useful is Nuklear requires you to call nk_input_begin before you call its input event hooks, and nk_input_end afterwards.

It is possible to get around this limitation by just calling nk_input_begin and nk_input_end inside your frame_cb implementation. But you then need to have a way to query the current state with an input polling API.

Other app frameworks (e.g. GLFW) support this input polling style, but sokol_app only supports an event-based push model. You can build your own state cache and implement a polling model on top of sokol_app, but that's more work.

Alternate Proposal

I'm not sure if that proposed callback is going to be possible for MacOS (and other app models that don't seem to require the app implementation to manually pump the event queue - I'm not 100% sure of these, it just looked this way while browsing the sokol_app source code).

If this isn't going to work, an alternate proposal would be to implement an input state cache and polling API to sokol_app.

E.g.

int is_c_pressed = sokol_key_is_pressed(SAPP_KEYCODE_C);
int is_ctrl_pressed = sokol_key_modifier_is_pressed(SAPP_MODIFIER_CTRL);
sokol_mouse_pos_t mouse_pos = sokol_mouse_current_pos();
sokol_mouse_scroll_t mouse_scroll = sokol_mouse_current_scroll();

Edit: Also would probably be useful to have just_pressed variants, since Nuklear seems to need them to work like that.

I don't think this would be very complicated, and I think it would be more likely to work on all app types.

The thing that would prevent it from working is you don't have enough hooks to properly clear state before each frame. It would also require the Sokol API to deal with problems like switching windows while holding a key down, then switching back.

kavika13 avatar May 10 '20 00:05 kavika13

Hi, there's another input-related request here: https://github.com/floooh/sokol/issues/283, it's not really closely related, but all in all it looks like the current sokol_app.h input model isn't flexible enough for different usage scenarios...

Some thoughts:

  • Such a "before-events callback" would most likely be hard to implement on the web platform and probably also Mac, because there the input callbacks are dispatched outside our control, unlike Windows where the event dispatching happens inside our own code (in DispatchMessage), a workaround for web and Mac would be to call this callback from the event handler of the first input event in a frame.

  • instead of adding more callbacks I'd probably prefer to add new event types (e.g. SAPP_EVENTTYPE_BEGIN_INPUT, SAPP_EVENTTYPE_END_INPUT, and all regular input events would be sent within those two other event types. This would suffer from the same problems on web and Mac as described above though.

  • I implemented a similar "polled system" as you describe in your alternative proposal in the sokol_imgui.h header for mouse clicks and button presses. This was necessary because in ImGui it may happen that a button down/up happens within the same frame, such a button press would be completely invisible to ImGui. As a workaround I'm not directly forwarding button and key presses to ImGui, but instead only record down/up state in the event handler: https://github.com/floooh/sokol/blob/9b659b23ae04db3f967b69282468a3c2e2cf845d/util/sokol_imgui.h#L1322-L1324

...and then once per frame in the frame callback I update the Dear ImGui input state similar to polling:

https://github.com/floooh/sokol/blob/9b659b23ae04db3f967b69282468a3c2e2cf845d/util/sokol_imgui.h#L1151-L1172

Maybe a similar idea makes sense for Nuklear too?

floooh avatar May 12 '20 10:05 floooh

Yeah I am doing something quite similar for Nuklear already, though like you mentioned (same frame down and up events) there's a number of cases I haven't handled yet.

My thought was that maybe the common caching stuff could be extracted if there's multiple targets it would be useful for. It seems Oryol already has such an API.

kavika13 avatar May 12 '20 17:05 kavika13