imgui icon indicating copy to clipboard operation
imgui copied to clipboard

ImGui::InputText freezes in v1.87+

Open BullyWiiPlaza opened this issue 1 year ago • 6 comments

Version/Branch of Dear ImGui:

Version: v1.88 Branch: https://github.com/Microsoft/vcpkg/blob/master/ports/imgui/portfile.cmake

Back-end/Renderer/Compiler/OS

Back-ends: imgui_impl_win32.cpp + imgui_impl_dx11.cpp Compiler: MSVC Operating System: Windows 11 Pro

My Issue/Question:

I'm using ImGui::InputText() to create text fields. Since v.187 of Dear ImGui clicking into text fields freezes the entire application (no crash but "stopped responding"). The bug does not occur with v1.86 and the bug still occurs in v1.88.

Standalone, minimal, complete and verifiable example:

std::string input_text;
ImGui::Begin("Example Bug");
ImGui::InputText("My text field", &input_text);
ImGui::End();

I researched but didn't find a clear solution or workaround (besides downgrading to v1.86). I believe my issue is similar to https://github.com/ocornut/imgui/issues/4972 and https://github.com/ocornut/imgui/issues/5264. How exactly would you debug into ImGui::InputText() getting stuck if needed? ImGui::InputText() takes me to the imgui_stdlib.h file and not the .cpp file and input texts are probably handled somewhere else. What exactly changed between those versions which could cause this regression? Thanks in advance for taking a look into this.

BullyWiiPlaza avatar Aug 01 '22 22:08 BullyWiiPlaza

Based on the multiple reports and the fact we did make changes to Win32 IME code in 1.87, I am assuming we do have an issue but I would like to understand if it is tied to debugger loading symbols or something else.

How exactly would you debug into ImGui::InputText() getting stuck if needed?

If something appears stuck, you first want to break in the debugger to find where.

What exactly changed between those versions which could cause this regression?

Answer is in the changelog:

- Platform IME: moved io.ImeWindowHandle to GetMainViewport()->PlatformHandleRaw.
- Platform IME: add ImGuiPlatformImeData::WantVisible, hide IME composition window when not used. (#2589) [@actboy168]
- Platform IME: add ImGuiPlatformImeData::InputLineHeight. (#3113) [@liuliu]
- Platform IME: [windows] call ImmSetCandidateWindow() to position candidate window.

Diffing between 1.86 and 1.87, the important related changes here are that we want from:

static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y)
{
    // Notify OS Input Method Editor of text input position
    ImGuiIO& io = ImGui::GetIO();
    if (HWND hwnd = (HWND)io.ImeWindowHandle)
        if (HIMC himc = ::ImmGetContext(hwnd))
        {
            COMPOSITIONFORM cf;
            cf.ptCurrentPos.x = x;
            cf.ptCurrentPos.y = y;
            cf.dwStyle = CFS_FORCE_POSITION;
            ::ImmSetCompositionWindow(himc, &cf);
            ::ImmReleaseContext(hwnd, himc);
        }
}

to

static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data)
{
    // Notify OS Input Method Editor of text input position
    HWND hwnd = (HWND)viewport->PlatformHandleRaw;
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    if (hwnd == 0)
        hwnd = (HWND)ImGui::GetIO().ImeWindowHandle;
#endif
    if (hwnd == 0)
        return;

    ::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0);

    if (HIMC himc = ::ImmGetContext(hwnd))
    {
        COMPOSITIONFORM composition_form = {};
        composition_form.ptCurrentPos.x = (LONG)data->InputPos.x;
        composition_form.ptCurrentPos.y = (LONG)data->InputPos.y;
        composition_form.dwStyle = CFS_FORCE_POSITION;
        ::ImmSetCompositionWindow(himc, &composition_form);
        CANDIDATEFORM candidate_form = {};
        candidate_form.dwStyle = CFS_CANDIDATEPOS;
        candidate_form.ptCurrentPos.x = (LONG)data->InputPos.x;
        candidate_form.ptCurrentPos.y = (LONG)data->InputPos.y;
        ::ImmSetCandidateWindow(himc, &candidate_form);
        ::ImmReleaseContext(hwnd, himc);
    }
}

If you want to help I would need you to very precisely answer the following questions, one by one:

  1. Are you running with a debugger attached? Does it makes any difference if you have a debugger attached or not?
  2. If the "freeze" only happens with a debugger attached: have if you tried waiting for several minutes? Does Visual Studio shows a "loading symbol" window, if so, can you press ESC and does it resume the application?
  3. Try commenting the line ::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0);. Does it makes a difference?
  4. Try commenting only the line ::ImmSetCandidateWindow(himc, &candidate_form);. Does it makes a difference?
  5. Try commenting both lines above. Does it makes a difference?

Thank you very much!

ocornut avatar Aug 01 '22 23:08 ocornut

  1. Yes, I'm running with a debugger attached. However, it does not matter if I'm using a debugger or not, the bug always occurs. Users running the release build also report this issue and they obviously don't have a debugger attached.
  2. Not applicable, there is no symbols loading going on when it freezes. Generally symbols loading would take a few seconds and in this case, the process never unfreezes itself, even after minutes of waiting.
  3. Yes, this fixes the bug and it no longer freezes.
  4. This does not make a difference.
  5. I did not try since 3. worked fine.

Thanks for the feedback.

BullyWiiPlaza avatar Aug 03 '22 06:08 BullyWiiPlaza

@BullyWiiPlaza Do you have any third-party IMEs installed? (Or any IMEs in general?)

PathogenDavid avatar Aug 03 '22 13:08 PathogenDavid

@BullyWiiPlaza Do you have any third-party IMEs installed? (Or any IMEs in general?)

No, I didn't even know what IME was exactly. Also other users had the same problem and they are often using a fairly plain Windows installation. Not sure which third-party IMEs even exist out there someone might want to install. I actually have Chinese language support installed, does that matter? I don't want to go through the process of re-testing again though unless it's needed.

BullyWiiPlaza avatar Aug 03 '22 15:08 BullyWiiPlaza

I don't know if that's the desirable logic and haven't tested it yet, but does moving the ::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0); call to inside the if {} block fixes it for you?

ocornut avatar Aug 03 '22 15:08 ocornut

I don't know if that's the desirable logic and haven't tested it yet, but does moving the ::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0); call to inside the if {} block fixes it for you?

Yes, putting this line of code into the if {} block is fine as well and the freeze does not occur.

BullyWiiPlaza avatar Aug 03 '22 16:08 BullyWiiPlaza

Thank you for testing this. I verified that this still gets us the behavior desired by #2589. Pushed the fix now 133bbafa3cc7b7a1ca68808dacd1f6cee2552d4f

ocornut avatar Aug 08 '22 09:08 ocornut

My bad this actually never re-enable the IME aftet the first time.

ocornut avatar Aug 08 '22 10:08 ocornut

@BullyWiiPlaza Could you test again but with the following version:

static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data)
{
    // Notify OS Input Method Editor of text input position
    HWND hwnd = (HWND)viewport->PlatformHandleRaw;
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    if (hwnd == 0)
        hwnd = (HWND)ImGui::GetIO().ImeWindowHandle;
#endif
    if (hwnd == 0)
        return;

    ::ImmAssociateContextEx(hwnd, NULL, IACE_IGNORENOCONTEXT | (data->WantVisible ? IACE_DEFAULT : 0));
    if (HIMC himc = ::ImmGetContext(hwnd))
    {
        COMPOSITIONFORM composition_form = {};
        composition_form.ptCurrentPos.x = (LONG)data->InputPos.x;
        composition_form.ptCurrentPos.y = (LONG)data->InputPos.y;
        composition_form.dwStyle = CFS_FORCE_POSITION;
        ::ImmSetCompositionWindow(himc, &composition_form);
        CANDIDATEFORM candidate_form = {};
        candidate_form.dwStyle = CFS_CANDIDATEPOS;
        candidate_form.ptCurrentPos.x = (LONG)data->InputPos.x;
        candidate_form.ptCurrentPos.y = (LONG)data->InputPos.y;
        ::ImmSetCandidateWindow(himc, &candidate_form);
        ::ImmReleaseContext(hwnd, himc);
    }
}

Thank you.

ocornut avatar Aug 08 '22 10:08 ocornut

@ocornut Yes, your latest code snippet also works fine, no freeze occurs.

BullyWiiPlaza avatar Aug 08 '22 11:08 BullyWiiPlaza

Thanks. But unfortunately that's not correct either, my bad :( I'll study those API some more, but unfortunately the documentation are very obtuse. @actboy168 your fix #2589 appears to be causing problems and may be not the right way to achieve that.

ocornut avatar Aug 08 '22 14:08 ocornut

@BullyWiiPlaza Could you try again with this variant instead:

static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data)
{
    // Notify OS Input Method Editor of text input position
    HWND hwnd = (HWND)viewport->PlatformHandleRaw;
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    if (hwnd == 0)
        hwnd = (HWND)ImGui::GetIO().ImeWindowHandle;
#endif
    if (hwnd == 0)
        return;

    ::ImmAssociateContextEx(hwnd, NULL, (data->WantVisible ? IACE_DEFAULT : IACE_IGNORENOCONTEXT));
    if (HIMC himc = ::ImmGetContext(hwnd))
    {
        COMPOSITIONFORM composition_form = {};
        composition_form.ptCurrentPos.x = (LONG)data->InputPos.x;
        composition_form.ptCurrentPos.y = (LONG)data->InputPos.y;
        composition_form.dwStyle = CFS_FORCE_POSITION;
        ::ImmSetCompositionWindow(himc, &composition_form);
        CANDIDATEFORM candidate_form = {};
        candidate_form.dwStyle = CFS_CANDIDATEPOS;
        candidate_form.ptCurrentPos.x = (LONG)data->InputPos.x;
        candidate_form.ptCurrentPos.y = (LONG)data->InputPos.y;
        ::ImmSetCandidateWindow(himc, &candidate_form);
        ::ImmReleaseContext(hwnd, himc);
    }
}

Sorry for the back and forth but I still cannot repro a freeze here.

ocornut avatar Aug 08 '22 15:08 ocornut

@BullyWiiPlaza Another thing is could you confirm that your issue repro in vanilla example_win32_directx11 ? It's unclear from the message if you reproed in examples or if it only happens in your app. This is to try to understand if some form of application code would interference with it.

ocornut avatar Aug 08 '22 15:08 ocornut

@BullyWiiPlaza Could you try again with this variant instead:

static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data)
{
    // Notify OS Input Method Editor of text input position
    HWND hwnd = (HWND)viewport->PlatformHandleRaw;
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    if (hwnd == 0)
        hwnd = (HWND)ImGui::GetIO().ImeWindowHandle;
#endif
    if (hwnd == 0)
        return;

    ::ImmAssociateContextEx(hwnd, NULL, (data->WantVisible ? IACE_DEFAULT : IACE_IGNORENOCONTEXT));
    if (HIMC himc = ::ImmGetContext(hwnd))
    {
        COMPOSITIONFORM composition_form = {};
        composition_form.ptCurrentPos.x = (LONG)data->InputPos.x;
        composition_form.ptCurrentPos.y = (LONG)data->InputPos.y;
        composition_form.dwStyle = CFS_FORCE_POSITION;
        ::ImmSetCompositionWindow(himc, &composition_form);
        CANDIDATEFORM candidate_form = {};
        candidate_form.dwStyle = CFS_CANDIDATEPOS;
        candidate_form.ptCurrentPos.x = (LONG)data->InputPos.x;
        candidate_form.ptCurrentPos.y = (LONG)data->InputPos.y;
        ::ImmSetCandidateWindow(himc, &candidate_form);
        ::ImmReleaseContext(hwnd, himc);
    }
}

Sorry for the back and forth but I still cannot repro a freeze here.

This will still cause a freeze.

@BullyWiiPlaza Another thing is could you confirm that your issue repro in vanilla example_win32_directx11 ? It's unclear from the message if you reproed in examples or if it only happens in your app. This is to try to understand if some form of application code would interference with it.

I compiled the vanilla example and added an imgui::InputText element but the freeze does not occur when clicking into the input text field, typing and defocussing it. I can only reproduce the freezing with my app so far.

BullyWiiPlaza avatar Aug 09 '22 07:08 BullyWiiPlaza

I compiled the vanilla example and added an imgui::InputText element but the freeze does not occur when clicking into the input text field, typing and defocussing it. I can only reproduce the freezing with my app so far.

Thanks. We’ll need to follow that trail to get to the end of this problem, if you will. You may want to fork your app and start commenting/stripping out chunks based on their likehood to interfere, aka any code dealing directly or indirectly with win32 api.

ocornut avatar Aug 09 '22 07:08 ocornut

@ocornut I could reproduce it with a pretty simple hello world example. Now I'm a bit stuck regarding what could still cause this issue. Please take a look at my repository: https://github.com/BullyWiiPlaza/ImGuiFreezingTest I invited you as collaborator, please accept the invite and you can access this private repository. All instructions are provided in the README.

BullyWiiPlaza avatar Aug 09 '22 18:08 BullyWiiPlaza

Thanks! Hmm I didn’t realize you were injecting over an existing application. This seems too complicated for me to repro so I can’t garantee I’ll look at it. Other reports of the same issue were seemingly in the same situation so i’d say they are interferences with underlying apps.

ocornut avatar Aug 09 '22 19:08 ocornut

Too complicated? ImGui development is far more complicated than this lol. Either way, take your time, it's fine. 👍 Keep in mind that this worked before the ImGui update to v1.87 so that's quite odd nevertheless.

BullyWiiPlaza avatar Aug 09 '22 19:08 BullyWiiPlaza

FWIW, I have the freezing issues on windows, not using any IME, tried all of the suggestions and they didn't work. It seems to hang for a few seconds in ImmGetContext. For additional context also I use imgui on the non-main thread (with a custom event queue for the windows ~~pipe~~ message pump)

I've commented out the code in that function for the time being.

ddengster avatar Aug 14 '22 07:08 ddengster

It is entirely your code or are you injecting in a third party application? If the earlier that would help us constitute a full source repro.

ocornut avatar Aug 14 '22 07:08 ocornut

I think this was fixed in 1.88 since im not getting the bug anymore but this is what i used to fix it before: ImGui::GetIO().SetPlatformImeDataFn = nullptr;

If i remember correctly it got stuck in a winapi call that never returned, that's why it froze but it didn't crash.

https://github.com/ocornut/imgui/blob/268565079c56600c197602683391a1bc8afba014/imgui.cpp#L12235

^ this is where it gets stuck on, ImmGetContext is for some reason blocking and doesn't continue execution.

crwn1337 avatar Aug 15 '22 17:08 crwn1337

I commented that call a few commits ago while working on tracking the issue. A repro with sources would be great.

ocornut avatar Aug 15 '22 19:08 ocornut

Sadly, this bug still occurred today with imgui v1.89.4-8c703ccfb7 from vcpkg. Clicking into the text field/defocussing froze the process and crashed it. I had to revert to imgui v1.86-7944920afc.clean which still works fine. It would be great to be able to use the latest version of imgui again. If there's anything else I can contribute to getting this regression fixed, I'm happy to do so, thanks.

BullyWiiPlaza avatar May 01 '23 20:05 BullyWiiPlaza