Skip to content

Instantly share code, notes, and snippets.

@fwflunky
Created September 8, 2025 13:25
Show Gist options
  • Select an option

  • Save fwflunky/2f6979def791d6bacfd5259c99c0a7c9 to your computer and use it in GitHub Desktop.

Select an option

Save fwflunky/2f6979def791d6bacfd5259c99c0a7c9 to your computer and use it in GitHub Desktop.
I migrated from CEF to WebView2 to render in-game overlays. Here's a catch

I migrated from CEF to WebView2 to render in-game overlays for better stability and performance. By default, you can't use WebView2 to render overlay using d3d11, but you can workaround this using https://gist.github.com/pabloko/5b5bfb71ac52d20dfad714c666a0c428

But here's a problem - when you click on the overlay html content, child window (Chrome_WidgetWin_0) will steal focus from main window, and all your keyboard input will be received by Chrome_WidgetWin_0 window, that means your main window WndProc won't be able to receive WM_KEYDOWN, WM_SYSKEYDOWN, etc while Chrome_WidgetWin_0 window have focus. To workaround this too, you can use my method below:

  1. In browser creation code edit:
HRESULT __stdcall EdgeBrowser::Invoke(HRESULT errorCode, ICoreWebView2CompositionController *_comp) {
    if (FAILED(errorCode) || !GetWindow(mainWindow, GW_CHILD)) {
        return failFast();
    }

    if(onChildWindowCreated) //make your own callback
        onChildWindowCreated(GetWindow(mainWindow, GW_CHILD));
  1. In your method where's browser is created:
Factory::createBrowser(..., [](HWND child) {
        executeOnMainThread([&]() {
            Overlay::originalWebView2ChildProc = (HRESULT (*)(HWND, UINT, WPARAM, LPARAM)) SetWindowLongPtrW(child, GWLP_WNDPROC, (LONG_PTR)Overlay::handleWebView2ChildProc);
        }).wait();
});
  1. Define handleWebView2ChildProc function:
HRESULT(*originalWebView2ChildProc)(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) = nullptr;
HRESULT Overlay::handleWebView2ChildProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch(message) {
        case WM_SYSKEYDOWN:
        case WM_KEYDOWN:
        case WM_INPUT:
        case WM_CHAR:
        case WM_SYSKEYUP:
        case WM_SYSCHAR:
        case WM_SYSCOMMAND:
        case WM_KEYUP: {
            Overlay::handleMessages(hwnd, message, wParam, lParam); //steal keyboard input from child window while it's focused and send to your message processing function to handle keys such open/close overlay, etc
            if(!isOverlayShown) //restore focus when overlay became not visible so handleWebView2ChildProc won't be called until you click on overlay content again
                SetFocus(MainWindow::windowHWND);
            return 0;
        }
        default:
            return originalWebView2ChildProc(hwnd, message, wParam, lParam);
    }
}
  1. Done. You can also send keyboard input manually from your code to the browser using originalWebView2ChildProc.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment