Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
kavika13 opened this issue May 10, 2020 · 2 comments

Comments

@kavika13
Copy link

kavika13 commented May 10, 2020

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.

@floooh
Copy link
Owner

floooh commented May 12, 2020

Hi, there's another input-related request here: #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:

    sokol/util/sokol_imgui.h

    Lines 1322 to 1324 in 9b659b2

    if (ev->mouse_button < 3) {
    _simgui.btn_down[ev->mouse_button] = true;
    }

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

sokol/util/sokol_imgui.h

Lines 1151 to 1172 in 9b659b2

for (int i = 0; i < SAPP_MAX_MOUSEBUTTONS; i++) {
if (_simgui.btn_down[i]) {
_simgui.btn_down[i] = false;
io->MouseDown[i] = true;
}
else if (_simgui.btn_up[i]) {
_simgui.btn_up[i] = false;
io->MouseDown[i] = false;
}
}
for (int i = 0; i < SIMGUI_MAX_KEY_VALUE; i++) {
if (_simgui.keys_down[i]) {
io->KeysDown[i] = true;
_simgui_set_imgui_modifiers(io, _simgui.keys_down[i]);
_simgui.keys_down[i] = 0;
}
else if (_simgui.keys_up[i]) {
io->KeysDown[i] = false;
_simgui_set_imgui_modifiers(io, _simgui.keys_up[i]);
_simgui.keys_up[i] = 0;
}
}

Maybe a similar idea makes sense for Nuklear too?

@kavika13
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants