sokol_app.h: add custom win32 hook to handle windows events

Created on 22 Apr 2020  路  2Comments  路  Source: floooh/sokol

I am using gainput (https://github.com/jkuhlmann/gainput) for input management and on windows I have to pass in all windows message manually for gainput to correctly register mouse and keyboard events

        // Update Gainput
        manager.Update();

        MSG msg;
        while (PeekMessage(&msg, hWnd,  0, 0, PM_REMOVE)) 
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);

            // Forward any input messages to Gainput
            manager.HandleMessage(msg);
        }

unfortunately sokol_app "swallows" all win32 event messages and I have no way to stop sokol from stealing my events.

I found a workaround that makes me handle win32 events before sokol does. I have to paste the following code before the #define SOKOL_IMPL

#if defined(_WIN32)
#  ifdef WIN32_LEAN_AND_MEAN
#    undef WIN32_LEAN_AND_MEAN
#  endif
#  include <Windows.h>
   // "hook" TranslateMessage call from sokol 
   extern "C" void hook_TranslateMessage(const MSG *lpMsg);

#  define TranslateMessage(MSG) \
    hook_TranslateMessage(MSG); \
    TranslateMessage(MSG);
#endif

#define SOKOL_IMPL
#define SOKOL_GLCORE33
#include <sokol/sokol_app.h>

then in my main app I just have to implement

#ifdef _WIN32
extern "C" void hook_TranslateMessage(const MSG *msg) {
  manager.HandleMessage(*msg);
}
#endif

this works fine, but I am wondering if it is possible to add "native" event callbacks to sapp_desc to handle such cases.

Greetings!
~ Rico (Ex Bigpoint Member)

enhancement

Most helpful comment

Here is a workaround that works for my use case:

It is possible to replace the WNDPROC callback that handles events for a specific window.
I do so with the following call in init_cb().

SetWindowLongPtr((HWND)sapp_win32_get_hwnd(), GWLP_WNDPROC, (LONG_PTR)hook_sapp_win32_wndproc);

I define the function alongside the sokol_app implementation to get access to the original callback _sapp_win32_wndproc():

_SOKOL_PRIVATE LRESULT CALLBACK hook_sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case ...:
            ...
        default:
            break;
    }
    return _sapp_win32_wndproc(hWnd, uMsg, wParam, lParam);
}

Now about Gainput specifically. They are using MSG structures but they seem to only use the message, wParam, and lParam members. I think you can forward the messages from a custom WNDPROC.

All 2 comments

Hi Rico :)

Hmm yeah that's a good point. I need to think of a good way to expose this type of stuff though because I can't have any Win32-types in the "public API". So basically a callback which takes a void* which would need to be cast to a MSG* in the user-provided callback.

The callback should be passed in via sapp_desc, e.g.

void my_win32_msg_callback(const void* msg) {
    const MSG* win32_msg = (const MSG*) msg;
    ...
}

sapp_desc sokol_main(int argc, char* argv[]) {
    return (sapp_desc) {
        .win32_msg_intercept_cb = my_win32_msg_callback
        ....
    };
}

There should also be a second sapp_desc callback type with a user_data pointer (same as with the init/frame/event/cleanup callbacks).

I probably won't get around implementing this for a little while because I'm still focused on the WebGPU backend, but you could provide a pull request in the meantime if you want :)

Here is a workaround that works for my use case:

It is possible to replace the WNDPROC callback that handles events for a specific window.
I do so with the following call in init_cb().

SetWindowLongPtr((HWND)sapp_win32_get_hwnd(), GWLP_WNDPROC, (LONG_PTR)hook_sapp_win32_wndproc);

I define the function alongside the sokol_app implementation to get access to the original callback _sapp_win32_wndproc():

_SOKOL_PRIVATE LRESULT CALLBACK hook_sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case ...:
            ...
        default:
            break;
    }
    return _sapp_win32_wndproc(hWnd, uMsg, wParam, lParam);
}

Now about Gainput specifically. They are using MSG structures but they seem to only use the message, wParam, and lParam members. I think you can forward the messages from a custom WNDPROC.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sherjilozair picture sherjilozair  路  7Comments

amerkoleci picture amerkoleci  路  4Comments

PeterHiber picture PeterHiber  路  5Comments

bqqbarbhg picture bqqbarbhg  路  3Comments

floooh picture floooh  路  7Comments