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

Exclusive mouse control to imgui #1

Open
arnaud-jamin opened this issue Nov 16, 2023 · 3 comments
Open

Exclusive mouse control to imgui #1

arnaud-jamin opened this issue Nov 16, 2023 · 3 comments

Comments

@arnaud-jamin
Copy link

arnaud-jamin commented Nov 16, 2023

Hello,

Thanks for your library. I find it very well designed.
I'm looking at replacing my Unreal Imgui integration (inspired by UnrealImGui) by yours in my project https://github.com/arnaud-jamin/Cog.

I have the following use case which forces me to modify your sources in a way I do not really like. Maybe you will come up with a better idea.

I want to give the option to the imgui user to change this dynamically:

  1. Disable imgui mouse. Then only the game handle the mouse.
  2. Share mouse between the game and imgui (imgui uses the mouse only over a imgui window otherwise it is for the game)
  3. Give exclusive control of the mouse to imgui. The game doesn't receive the mouse anymore.

Point 1) Can be done by using the flag ImGuiConfigFlags_NoMouse
Point 2) Can be done by disabling the flag ImGuiConfigFlags_NoMouse
Point 3) Can be done in different ways:

A) dynamically change the return value of the functions in input processor:

The InputProcessor could have a member variable "OnlyEnableImGuiMouse". Related functions would return true when this variable is true.

	virtual bool HandleMouseMoveEvent(FSlateApplication& SlateApp, const FPointerEvent& Event) override
	{
		[...]

                if (OnlyEnableImGuiMouse)
                {
                    return true;
                }    
		
                return IO.WantCaptureMouse;
	}

To be able to change that variable I would need to expose an accessor to the Overlay or the Context inside FScopedContext. Or I could create the Context by calling this:

TSharedPtr<FImGuiContext> ImGuiContext = FImGuiModule::Get().FindOrCreateContext();

Then I could keeping a reference to the created context and call a SetOnlyEnableImGuiMouse() on it. I would need to get the context from FScopedContext to do:

	virtual bool HandleMouseMoveEvent(FSlateApplication& SlateApp, const FPointerEvent& Event) override
	{
		ImGui::FScopedContext ScopedContext(Owner->GetContext());
                [...]

                if (ScopedContext.GetContext()->GetOnlyEnableImGuiMouse())
                {
                    return true;
                }    
		
                return IO.WantCaptureMouse;
	}

This doesn't seem great.

B) Another way to do this is to have a transparent imgui widget the cover the whole screen so IO.WantCaptureMouse always return true. (it could be the docking central node without ImGuiDockNodeFlags_PassthruCentralNode but made transparent)

Any suggestion ?

Thanks!

@VesCodes
Copy link
Owner

Hey Arnaud, sorry for taking so long to respond! Work got busy with the run-up to the holidays.

One of my goals was to keep the public API as concise as possible so I kind of settled with Unreal's built-in mechanisms where I could. The input processor only pipes through mouse moves to ImGui when no other widget has mouse capture - this functionality should technically cover points 1 and 2 as users can swap between UI and Game input modes to effectively enable/disable ImGui input handling respectively.

For point 3 I think your first approach sounds reasonable, you could expose an ImGui extension method like the following:

IMGUI_API void SetExclusiveMouseMode(bool bValue)
{
	const TSharedPtr<FImGuiContext> Context = FImGuiContext::Get(GetCurrentContext());
	if (Context.IsValid())
	{
		Context->ExclusiveMouseMode = bValue;
	}
}

I'll consider adding this functionality in some form with some other incoming changes :)

@arnaud-jamin
Copy link
Author

No problem. I've been trying to use the input processor too, but didn't find a way to not block editor inputs. Like pressing the stop button. I've switched back to using the input received by the widget, but i still don't know how to properly handle a shared mouse between the game and imgui.

@Wyverex42
Copy link

I have a similar issue at the moment where I have an in-game map view and I render a bunch of ImGui on top. Whenever I hold the middle mouse button to drag the map, afterwards ImGui doesn't receive any further mouse move events. I tracked this down to

	virtual bool HandleMouseMoveEvent(FSlateApplication& SlateApp, const FPointerEvent& Event) override
	{
               [...]
		if (SlateApp.HasAnyMouseCaptor())
		{
			IO.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
			return false;
		}

I first have to click once anywhere using the left mouse button to make it work again. So apparently when dragging with any mouse button, the Slate window captures the mouse which then ends in this early-out.

I basically want option 2 in the OP's post and I need to have both input for the game and ImGui available, depending on where the mouse is.
I'm not sure now whether the solution should be to make the Slate window not capture the mouse (not sure how to) or whether this should be an option in the ImGui plugin which then basically skips this check. Any recommendations?

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

No branches or pull requests

3 participants