ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
61.15k stars 10.31k forks source link

ImGui::InputText not rendering key press using opengl #7427

Closed Shrimpy02 closed 7 months ago

Shrimpy02 commented 7 months ago

Version/Branch of Dear ImGui:

Version 1.90.4, Branch: master

Back-ends:

imgui_impl_glfw.h + imgui_impl_opengl3.h

Compiler, OS:

Windows 11 + MSVC2022

Full config/build information:

IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;

ImGui::StyleColorsDark();

ImGui_ImplGlfw_InitForOpenGL(mGLFWWindow, false); ImGui_ImplOpenGL3_Init("#version 130");

Details:

I apologize for what I imagine is a stupid question but I am still quite new to coding.

I am creating a c++ opengl project with ImGui. My issue is when I write to ImGui::InputText there is no text being created even though I can delete pre-existing text or copy paste in new text. I am trying to debug the problem myself but have kind of hit a wall and would love some advice on how to progress/fix the issue.

This is how i pass input to ImGui: void Window::KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { ImGui_ImplGlfw_KeyCallback(window, key, scancode, action, mods); ImGuiIO& io = ImGui::GetIO(); (void)io; io.AddInputCharacter(key);

if (ImGui::GetIO().WantCaptureKeyboard) return;

if (mScene)
    mScene->KeyCallback(this, key, scancode, action, mods);

}

Following "ImGui_ImplGlfw_KeyCallback" I can see the correct keys are being passed in and converted, however in the render function snipit bellow i cant pass if (io.InputQueueCharacters.Size > 0) because the characters are being added to InputEventsQueue and not inputQueCharacters. I tried manually calling io.AddInputCharacter(key) which adds the characters to the correct que but with incorrect values.

const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); if (io.InputQueueCharacters.Size > 0) { if (!ignore_char_inputs && !is_readonly && !input_requested_by_nav) for (int n = 0; n < io.InputQueueCharacters.Size; n++) { // Insert character if they pass filtering unsigned int c = (unsigned int)io.InputQueueCharacters[n]; if (c == '\t') // Skip Tab, see above. continue; if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) state->OnKeyPressed((int)c); }

// Consume characters
io.InputQueueCharacters.resize(0);

}

I'm pretty sure everything is set up correctly since all other ImGui functions work. For clarification I tried to use the demo window and I have the same issue where I cannot input any of the editable text blocks.

IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;

ImGui::StyleColorsDark();

ImGui_ImplGlfw_InitForOpenGL(mGLFWWindow, false); ImGui_ImplOpenGL3_Init("#version 130");

I'm sure I'm missing something obvious but can't find a way to fix this, so I would appreciate any pointers I could get.

Screenshots/Video:

No response

Minimal, Complete and Verifiable Example code:

No response

PathogenDavid commented 7 months ago

In the future please be mindful that your code is formatted correctly for GitHub.

Text input comes through ImGui_ImplGlfw_CharCallback rather than ImGui_ImplGlfw_KeyCallback, so chances are you're calling glfwSetKeyCallback somewhere without chaining to ImGui_ImplGlfw_CharCallback.

Ideally you should just install all your glFW callbacks before calling ImGui_ImplGlfw_InitForOpenGL(window, true) or ImGui_ImplGlfw_InstallCallbacks. The Dear ImGui callbacks will automatically call any callbacks you had installed.

Shrimpy02 commented 7 months ago

Thanks for the feedback and I apologize for the inappropriate formatting.

Using ImGui_ImplGlfw_CharCallback has the same issue of displaying the incorrect input as when I called io.AddInputCharacter(c); manually. For example I input w with a scan code of 17. but it is filtered out by the function InputTextFilterCharacter(), more specifically this section;

 if (c < 0x20)
 {
     bool pass = false;
     pass |= (c == '\n') && (flags & ImGuiInputTextFlags_Multiline) != 0; // Note that an Enter KEY will emit \r and be ignored (we poll for KEY in InputText() code)
     pass |= (c == '\t') && (flags & ImGuiInputTextFlags_AllowTabInput) != 0;
     if (!pass)
         return false;
     apply_named_filters = false; // Override named filters below so newline and tabs can still be inserted.
 }

They key values work well for the GLFW application, under is how i have setup the callback logic.

    glfwSetKeyCallback(mGLFWWindow, [](GLFWwindow* window, int key, int scancode, int action, int mods) {
        auto app = reinterpret_cast<Window*>(glfwGetWindowUserPointer(window));
        if (app) app->KeyCallback(window, key, scancode, action, mods);
        });

To call this function:

void Window::KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (ImGui::GetIO().WantCaptureKeyboard) 
     ImGui_ImplGlfw_CharCallback(window, scancode);

    if (mScene)
        mScene->KeyCallback(this, key, scancode, action, mods);
}

The ImGui_ImplGlfw_CharCallback does not have the same functionality as ImGui_ImplGlfw_KeyCallback considering the converting of int to ImGuiKey. So I figure I need to convert these values somehow, although everything I have tried has not worked. I assume there is built in support for this kind of thing so I suspect I might be overcomplicating this issue.

PathogenDavid commented 7 months ago

Don't call ImGui_ImplGlfw_CharCallback from your glfwSetKeyCallback callback. It needs to be called from the glfwSetCharCallback callback.

Additionally, this logic is incorrect:

if (ImGui::GetIO().WantCaptureKeyboard) 
    ImGui_ImplGlfw_CharCallback(window, scancode);

Events should be passed to Dear ImGui unconditionally.

I commend you for trying to debug this on your own, but you're diving into Dear ImGui's guts a bit prematurely when you need to be reevaluating what your code is doing.

I'm going to reiterate my suggestion that you should not be passing false for install_callbacks to ImGui_ImplGlfw_InitForOpenGL unless you're willing to put in the effort to understand how events flow from glFW to Dear ImGui. Setting it to false is meant for advanced users.

Install your own callbacks before ImGui_ImplGlfw_InitForOpenGL and let imgui_impl_glfw handle the event chaining.

Shrimpy02 commented 7 months ago

Ah yes of course, in hindsight it makes complete sense to use "char callbacks" for "char callbacks" and "key callbacks" for "key callbacks", I just heard "key" and stupidly assumed it meant all keyboard keys.. I now call ImGui_ImplGlfw_CharCallback with glfw`s glfwSetCharCallback and likewise for the key callbacks witch fixed my issue of text not being printed to ImGui editables.

void Window::CharCallback(GLFWwindow* window, unsigned int codepoint)
{
    ImGui_ImplGlfw_CharCallback(window, codepoint);
    if (ImGui::GetIO().WantCaptureKeyboard) return;

    if (mScene)
        mScene->CharCallback(this, codepoint);
}

void Window::KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    ImGui_ImplGlfw_KeyCallback(window, key, scancode, action, mods);
    if (ImGui::GetIO().WantCaptureKeyboard) return;

    if (mScene)
        mScene->KeyCallback(this, key, scancode, action, mods);
}

I will also let ImGui_ImplGlfw_InitForOpenGL handle the callbacks for now, following your suggestion since I am by no means an advanced user. Thank you for your Help!