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

ImGui::InputText freezes in v1.87+ in a Win32 IME ImmAssociateContextEx() call #5535

Open
BullyWiiPlaza opened this issue Aug 1, 2022 · 23 comments

Comments

@BullyWiiPlaza
Copy link

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 #4972 and #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.

@ocornut
Copy link
Owner

ocornut commented Aug 1, 2022

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!

@BullyWiiPlaza
Copy link
Author

  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.

@PathogenDavid
Copy link
Contributor

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

@BullyWiiPlaza
Copy link
Author

BullyWiiPlaza commented Aug 3, 2022

@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.

@ocornut
Copy link
Owner

ocornut commented Aug 3, 2022

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 ocornut added the bug label Aug 3, 2022
@BullyWiiPlaza
Copy link
Author

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.

ocornut added a commit that referenced this issue Aug 8, 2022
@ocornut
Copy link
Owner

ocornut commented Aug 8, 2022

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

@ocornut ocornut closed this as completed Aug 8, 2022
@ocornut
Copy link
Owner

ocornut commented Aug 8, 2022

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

@ocornut ocornut reopened this Aug 8, 2022
@ocornut
Copy link
Owner

ocornut commented Aug 8, 2022

@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 added a commit that referenced this issue Aug 8, 2022
@BullyWiiPlaza
Copy link
Author

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

@ocornut
Copy link
Owner

ocornut commented Aug 8, 2022

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
Copy link
Owner

ocornut commented Aug 8, 2022

@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
Copy link
Owner

ocornut commented Aug 8, 2022

@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.

@BullyWiiPlaza
Copy link
Author

BullyWiiPlaza commented Aug 9, 2022

@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.

@ocornut
Copy link
Owner

ocornut commented Aug 9, 2022

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.

@BullyWiiPlaza
Copy link
Author

@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.

@ocornut
Copy link
Owner

ocornut commented Aug 9, 2022

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.

@BullyWiiPlaza
Copy link
Author

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.

@ddengster
Copy link

ddengster commented Aug 14, 2022

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.

@ocornut
Copy link
Owner

ocornut commented Aug 14, 2022 via email

@ghost
Copy link

ghost commented Aug 15, 2022

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.

imgui/imgui.cpp

Line 12235 in 2685650

if (HIMC himc = ::ImmGetContext(hwnd))

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

@ocornut
Copy link
Owner

ocornut commented Aug 15, 2022

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

@ocornut ocornut changed the title ImGui::InputText freezes in v1.87+ ImGui::InputText freezes in v1.87+ in a Win32 IME ImmAssociateContextEx() call Sep 4, 2022
Dwarfius added a commit to Dwarfius/VulkanRTSEngine that referenced this issue Nov 1, 2022
My guess is that it's caused by non-main thread invocation of winapi, but I can't test it easily in my app. Waiting on ocornut/imgui#5535 to be fixed
@BullyWiiPlaza
Copy link
Author

BullyWiiPlaza commented May 1, 2023

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.

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

No branches or pull requests

4 participants