segross / UnrealImGui

Unreal plug-in that integrates Dear ImGui framework into Unreal Engine 4.
MIT License
664 stars 212 forks source link

Improvements to sharing mouse input #63

Open benui-dev opened 2 years ago

benui-dev commented 2 years ago

Creating a new ticket as the old one was closed https://github.com/segross/UnrealImGui/issues/49

I read the description of input sharing and the issues with mouse being that there is an ImGui Slate widget covering the whole screen and intercepting mouse events. I'm not a complete expert on how your plugin works so maybe this is a naive idea but...

I see that ImGuiInputHandler returns FReply::Handled for MouseDown and MouseUp events and that seems to be what make sure that mouse clicks on the UI don't accidentally go through to the game.

Is there no way to only return FReply::Handled if the cursor is over a UI element? That way the Slate widget can behave kind of like HitTestInvisible?

Edit: Okay yeah it was mega naive, checking for WantCaptureMouse and IsWindowHovered doesn't work, even though the imgui demo window seems to show the flags correctly.

FReply UImGuiInputHandler::OnMouseButtonDown(const FPointerEvent& MouseEvent)
{
    if (MouseEvent.IsTouchEvent())
    {
        return ToReply(false);
    }

    //const bool bHandled = ImGui::GetIO().WantCaptureMouse;
    const bool bHandled = ImGui::IsWindowHovered();

    InputState->SetMouseDown(MouseEvent, true);
    return ToReply(bHandled);
}
benui-dev commented 2 years ago

I wonder if input preprocessors might be helpful? FSlateApplication::Get().RegisterInputPreProcessor

benui-dev commented 2 years ago

Made some progress by adding this to ImGuiInputHandler.cpp

With mouse input sharing disabled, the payer controller still receives clicks when clicking outside ImGui windows, and ImGui receives events when clicking inside ImGui windows.

It's probably a naive solution and I'm going to hit some big problem soon, but maybe it will help someone develop a better solution?

FReply UImGuiInputHandler::OnMouseButtonDown(const FPointerEvent& MouseEvent)
{
    if (MouseEvent.IsTouchEvent())
    {
        return ToReply(false);
    }

    InputState->SetMouseDown(MouseEvent, true);
    if (ModuleManager)
    {
        FImGuiContextProxy* Proxy = ModuleManager->GetContextManager().GetContextProxy(0);
        if (Proxy)
        {
            GEngine->AddOnScreenDebugMessage(15, 10, Proxy->WantsMouseCapture() ? FColor::Green : FColor::Red, TEXT("Handler Down"));
            return ToReply(Proxy->WantsMouseCapture());
        }
    }
    return ToReply(true);
}
livingisgood commented 2 years ago

I know it is not likely a proper way to do this, but it seems to work by just comment out those two lines of code in SImGuiWidget.cpp

if (bTransparentMouseInput)
{
    // If mouse is in transparent input mode and focus is lost to viewport, let viewport keep it and disable
    // the whole input to match that state.
    if (GameViewport->GetGameViewportWidget()->HasMouseCapture())
    {
        //Properties.SetInputEnabled(false);
        //UpdateInputState();
    }
}

I am wondering if we just don't disable the input when viewport has taken the focus, what could go wrong?