xiaoxiao921 / DearImGuiInjection

18 stars 3 forks source link

ClickEvent Pass through #8

Open krulci opened 8 months ago

krulci commented 8 months ago

General Issue: Click events pass through and blockage

Observations: https://github.com/xiaoxiao921/DearImGuiInjection/blob/af1e9534c67088d11779ad09d1aab2c19226e34a/DearImGuiInjection/BepInEx/DearImGuiInjectionBasePluginIL2CPP.cs#L59C4-L80C1 Seems like you are blocking Unity's EventSystem conditionally by IsCursorVisible boolean. https://github.com/xiaoxiao921/DearImGuiInjection/blob/af1e9534c67088d11779ad09d1aab2c19226e34a/DearImGuiInjection/Backends/ImGuiWin32Impl.cs#L460 However, ImGuiWin32Impl.WndProcHandler seems to be always capturing mouse event.

Observed Behaviors: What this leads to are as followed

  1. Mouse events will always pass through ImGui windows.
  2. Unity's UI object will not capture mouse event because UnityEngine.EventSystems.EventSystem.Update is patched with false prefix when IsCursorVisible is true.

Specific Issues:

  1. UnityEngine.EventSystems.EventSystem.Update could be stripped when the game is shipped. This leads to everything clicked outside or within ImGui windows region when IsCursorVisible is true is always captured by Unity's UI objects, a.k.a pass through. Actually, I am not sure if is due to stripping. For the game priconner with Unity version 2021.3.20f1, I do see this class in interop dlls; however, it will always pass through.
  2. No inputs are allowed outside of ImGui windows region when IsCursorVisible is true. (not sure if you intended like this). It seems like a transparent canvas exist when IsCursorVisible is true.

Desired Behaviors:

  1. When IsCursorVisible is true, mouse events within ImGui windows region should not be captured by Unity's UI object, a.k.a no pass through.
  2. When IsCursorVisible is true, mouse events outside ImGui windows region should be captured by Unity's UI object., a.k.a GUI Overlay.

Changes

  1. https://github.com/xiaoxiao921/DearImGuiInjection/blob/af1e9534c67088d11779ad09d1aab2c19226e34a/DearImGuiInjection/Backends/ImGuiWin32Impl.cs#L460 Change the return type of ImGuiWin32Impl.WndProcHandler to a boolean so that it will only return true when system message should be captured, false otherwise.

  2. https://github.com/xiaoxiao921/DearImGuiInjection/blob/af1e9534c67088d11779ad09d1aab2c19226e34a/DearImGuiInjection/Backends/ImGuiDX11.cs#L106 https://github.com/xiaoxiao921/DearImGuiInjection/blob/af1e9534c67088d11779ad09d1aab2c19226e34a/DearImGuiInjection/Backends/ImGuiDX12.cs#L180 For ImGuiDX11.WndProcHandler and ImGuiDX12.WndProcHandler, add a condition to return IntPtr.Zero when IsCursorVisible is true and when system message should be captured .

    private static unsafe IntPtr WndProcHandler(IntPtr windowHandle, WindowMessage message, IntPtr wParam, IntPtr lParam)
    {
    if (message == WindowMessage.WM_KEYUP && (VirtualKey)wParam == DearImGuiInjection.CursorVisibilityToggle.Get())
    {
        SaveOrRestoreCursorPosition();
    
        DearImGuiInjection.ToggleCursor();
    }
    
    if (DearImGuiInjection.IsCursorVisible && ImGuiWin32Impl.WndProcHandler(windowHandle, message, wParam, lParam))
        return IntPtr.Zero;
    
    return User32.CallWindowProc(_originalWindowProc, windowHandle, message, wParam, lParam);
    }
  3. https://github.com/xiaoxiao921/DearImGuiInjection/blob/af1e9534c67088d11779ad09d1aab2c19226e34a/DearImGuiInjection/BepInEx/DearImGuiInjectionBasePluginIL2CPP.cs#L76 Make it to return !false so that UnityEngine.EventSystems.EventSystem.Update is never patched. Honestly, I don't think SetupIgnoreUIObjectsWhenImGuiCursorIsVisible is needed anymore since we are now determining when to listen to mouse events through Window Message instead of Unity's EventSystem. Let me know if it is better to remove this.