floooh / sokol

minimal cross-platform standalone C headers
https://floooh.github.io/sokol-html5
zlib License
6.82k stars 475 forks source link

made sokol_imgui event functions that were sapp agnostic public #855

Closed benjitrosch closed 1 year ago

benjitrosch commented 1 year ago

I was adding sokol_imgui with cimgui to my sokol_gfx and SDL2 project when I came across this comment:

The sokol_app.h dependency is optional and used for input event handling. If you only use sokol_gfx.h but not sokol_app.h in your application, define SOKOL_IMGUI_NO_SOKOL_APP before including the implementation of sokol_imgui.h, this will remove any dependency to sokol_app.h, but you must feed input events into Dear ImGui yourself.

I took a look and realized that almost all of the internal functions for event handling were platform agnostic between sokol_app and SDL2, with only two exceptions:

  1. _simgui_add_sapp_key_event
  2. _simgui_update_modifiers

I made the rest of them public and available even when SOKOL_IMGUI_NO_SOKOL_APP is defined, and added a new function called simgui_add_key_event which works like _simgui_add_sapp_key_event but takes in a function pointer that allows the user to map the keycodes to imgui themselves.

Doing this saves a lot of boilerplate. Here's how you can make sokol_imgui work with SDL2 pretty easily by exposing these functions:

static int imgui_sdl2_map_keycode(int key)
{
    switch (key)
    {
        case SDLK_SPACE:        return ImGuiKey_Space;
        case SDLK_QUOTE:        return ImGuiKey_Apostrophe;
        case SDLK_COMMA:        return ImGuiKey_Comma;
        // etc...
        default:                return ImGuiKey_None;
    }
}

static void imgui_sdl2_update_modifiers(ImGuiIO* io, uint16_t mod)
{
    simgui_add_imgui_key_event(io, ImGuiMod_Ctrl, (mod & KMOD_CTRL) != 0);
    simgui_add_imgui_key_event(io, ImGuiMod_Shift, (mod & KMOD_SHIFT) != 0);
    simgui_add_imgui_key_event(io, ImGuiMod_Alt, (mod & KMOD_ALT) != 0);
    simgui_add_imgui_key_event(io, ImGuiMod_Super, (mod & KMOD_GUI) != 0);
}

void imgui_handle_events(const SDL_Event* event)
{
#ifdef __cplusplus
    ImGuiIO* io = &ImGui::GetIO();
#else
    ImGuiIO* io = igGetIO();
#endif

    int mouse_button = -1;
    if (event->button.button == SDL_BUTTON_LEFT) mouse_button = 0;
    if (event->button.button == SDL_BUTTON_RIGHT) mouse_button = 1;
    if (event->button.button == SDL_BUTTON_MIDDLE) mouse_button = 2;
    if (event->button.button == SDL_BUTTON_X1) mouse_button = 3;
    if (event->button.button == SDL_BUTTON_X2) mouse_button = 4;

    switch (event->type)
    {
        case SDL_WINDOWEVENT_FOCUS_GAINED:
            simgui_add_focus_event(io, true);
            break;

        case SDL_WINDOWEVENT_FOCUS_LOST:
            simgui_add_focus_event(io, false);
            break;

        case SDL_MOUSEBUTTONDOWN:
            if (mouse_button == -1) break;

            simgui_add_mouse_pos_event(io, (float)event->button.x, (float)event->button.y);
            simgui_add_mouse_button_event(io, mouse_button, true);
            imgui_sdl2_update_modifiers(io, event->key.keysym.mod);
            break;

        case SDL_MOUSEBUTTONUP:
            if (mouse_button == -1) break;

            simgui_add_mouse_pos_event(io, (float)event->button.x, (float)event->button.y);
            simgui_add_mouse_button_event(io, mouse_button, false);
            imgui_sdl2_update_modifiers(io, event->key.keysym.mod);
            break;

        case SDL_MOUSEMOTION:
            simgui_add_mouse_pos_event(io, (float)event->motion.x, (float)event->motion.y);
            break;

        case SDL_MOUSEWHEEL:
            simgui_add_mouse_wheel_event(io, event->wheel.x, event->wheel.y);
            break;

        case SDL_KEYDOWN:
            imgui_sdl2_update_modifiers(io, event->key.keysym.mod);
            simgui_add_key_event(io, imgui_sdl2_map_keycode, (int)event->key.keysym.sym, true);
            break;

        case SDL_KEYUP:
            imgui_sdl2_update_modifiers(io, event->key.keysym.mod);
            simgui_add_key_event(io, imgui_sdl2_map_keycode, (int)event->key.keysym.sym, false);
            break;

        case SDL_TEXTINPUT:
            simgui_add_input_characters_utf8(io, event->text.text);
            break;
    }
}

Let me know if you think this would be a good addition or if you'd rather leave it out for people to implement themselves.

floooh commented 1 year ago

Looks like a good idea, but I need to roll this around in the back of my head for a bit ;) All those 'event' functions are actually fairly recent and it didn't occur to me that it might make sense to make them public.

floooh commented 1 year ago

Can you have a look at the CI errors? Looks like some places still call the old _simgui_... version (probably in sokol-app specific code paths).

benjitrosch commented 1 year ago

Can you have a look at the CI errors? Looks like some places still call the old _simgui_... version (probably in sokol-app specific code paths).

Good catch sorry for missing that earlier! Pushed up a fix and reran test_macos.sh locally (since that's what I'm developing on) and it's passing now, hopefully should mean the others pass as well.

floooh commented 1 year ago

A couple more changes needed, sorry that I missed this earlier:

floooh commented 1 year ago

Ok merged, many thanks!

benjitrosch commented 1 year ago

@floooh thanks so much! Hope others find it helpful 😄