ocornut / imgui

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

Popup without input blocking? #718

Open harold-b opened 8 years ago

harold-b commented 8 years ago

Hello, fantastic library!

I'm trying to implement an autocomplete popup, but I've not been able to find a way to create a popup that can received mouse input and not block input from flowing through the underlying windows.

To be more specific of the context in which I'm trying to use it. I'd like to create an autocomplete popup a la google search. In which the popup does not close when you click elsewhere, you can hover and click it's items, and the input box ( or other widget ) retains keyboard input throughout.

Example: imgui_popup

Is it possible to do currently with the public API?

Thank you.

harold-b commented 8 years ago

I got it working... The biggest issues was that I wanted the helper window to show on top of the console, which is why I was having a hard time... Since by using a popup, whatever is underneath it loses input. I ended up managing to get it to work by having the console window use the ImGuiWindowFlags_NoBringToFrontOnFocus flag while the history window is showing. Then drawing the popup as a regular window after the console. This ensures that it's always on top of it and I still retain keyboard input on the console. I then hacked around listening to the keyboard events on the input box to control the selection and scrolling on the history window. Had I opted for having it pop-up below the console window, it would have been simple... But I really wanted it above! :)

Results: console_01 anim

ocornut commented 8 years ago

Nice! Sorry I hadn't had time to look into this in details. I was thinking about ChildWindow would provide something close to what you want but haven't looked at all the input details yet. Have you had to make a change to imgui.cpp to get it working?

harold-b commented 8 years ago

No worries at all!

I didn't have to make any changes whatsoever to imgui.cpp, managed to get it functioning with just the public API, thankfully. Though I'm eager to dig into the internals I'm in a rush to get back to another task and was hoping to avoid it for the time being.

Here's another little gif showing mouse interaction with the windows as well, since I forgot it on the other gif. anim2

A ChildWindow or some sort of per-window z-layering (which I guess itself a child window of sorts) would certainly be useful for these types of situations.

ocornut commented 8 years ago

@harold-b Could you clarify your description and maybe provide pseudo-code? I am interested in this and investigating if it can be made easier to the end-user.

I got it working... The biggest issues was that I wanted the helper window to show on top of the console, which is why I was having a hard time... Since by using a popup, whatever is underneath it loses input. I ended up managing to get it to work by having the console window use the ImGuiWindowFlags_NoBringToFrontOnFocus flag while the history window is showing. Then drawing the popup as a regular window after the console. This ensures that it's always on top of it and I still retain keyboard input on the console. I then hacked around listening to the keyboard events on the input box to control the selection and scrolling on the history window. Had I opted for having it pop-up below the console window, it would have been simple... But I really wanted it above! :)

ocornut commented 8 years ago

The dumb version that you can't interact with is to use a tooltip (created within the calback because we love living dangerously!)

if (data->EventFlag == ImGuiInputTextFlags_CallbackAlways && candidates.Size > 0)
{
    ImGui::SetNextWindowPos(ImVec2(ImGui::GetItemRectMin().x, ImGui::GetItemRectMax().y));
    ImGui::SetNextWindowSize(ImVec2(200,400));
    ImGui::BeginTooltip();
    for (int i = 0; i < candidates.Size; i++)
        ImGui::TextUnformatted(candidates[i]);
    ImGui::EndTooltip();
}

completion

harold-b commented 8 years ago

The dumb version that you can't interact with is to use a tooltip (created within the calback because we love living dangerously!)

Why you daredevil! :rage2:

Here's an image to facilitate explaining more specifically what I wanted to achieve, realizing now my initial description was lacking:

mguiwin

What I wanted to do was open an arbitrary #popup window that shows on top of the current #window but does not block mouse input to the bottom window. ( I wanted to maintain keyboard input on the #input box however.

I think the best working example would be Google's search box as per my initial post. If you leave an auto-suggest popup open and click around the page, etc. The popup remains open and unaltered. This what I wanted to mimic.

With a regular imgui popup the input below the popup gets blocked. I wanted my #popup to stay up as long as I wanted and I wanted it to be able to take mouse input and not block mouse input of the underlying window. So if I selected text, or clicked a button, etc. on the main #window, the #popup would be unaffected and still be drawn on top.

I managed to fake that by having the popup be a regular window and using the ImGuiWindowFlags_NoBringToFrontOnFocus flag on the main window as mentioned above.

It went something like this:

ImGuiWindowFlags winFlags = ImGuiWindowFlags_MenuBar;

if( isPopupVisible )
    winFlags |= ImGuiWindowFlags_NoBringToFrontOnFocus;

if( !ImGui::Begin( "Developer Console", &isWinOpen, winFlags ) )
{
    ImGui::End();
    return;
}

// Draw arbitrary stuff...

// Done drawing window
ImGui::End();

// Draw the popup as a new regular window on top of the last one
if( isPopupVisible )
{
    // Draw popup window
    ImGuiWindowFlags popupFlags = 
        ImGuiWindowFlags_NoTitleBar          | 
        ImGuiWindowFlags_NoResize            |
        ImGuiWindowFlags_NoMove              |
        ImGuiWindowFlags_HorizontalScrollbar |
        ImGuiWindowFlags_NoSavedSettings     |
        ImGuiWindowFlags_ShowBorders;

    bool isOpenDummy = true;

    ImGui::Begin( "history_popup", &isOpenDummy, popupFlags );
    ImGui::PushAllowKeyboardFocus( false );

    // Draw arbitrary popup content...

    ImGui::PopAllowKeyboardFocus();
    ImGui::End();
}

There was some tricky focus checking stuff I had to do too if I recall, but nothing fancy.

Perhaps the simplest way to facilitate this kind of behavior would be to have some kind of z-layering per root window, allowing each window to have it's own stack of regular windows drawn on top of it (but not intersecting other root windows and their z-layered stack)?

inflex commented 8 years ago

@harold-b I'm trying to implement the same sort of thing, though I'm fine with it being a popup/window that is located underneath/below the position of the input text field (in fact, that is how I need it).

I can partially get what I want using BeginPopup(), but like your initial attempts the keyboard focus stealing keeps getting in the way.

Do you have a functional outline handy? I've tried to replicate based on your work above without success (right now soon as I press the first key it just closes the modal popup I have where I have my search fields ) and the single character I pressed is all that gets put in to the said field.

Regards, Paul.

harold-b commented 8 years ago

If I recall, there was no way to do it with the regular Popup, because whatever is underneath is simply loses input. This is why I went hunting for workarounds.

If you don't need mouse interaction with the popup, you can use the technique @ocornut presented above which uses the Tooltip instead. You can then listen to the keyboard events on the text input's callbacks and change the current selection on the popup.

If you need mouse interaction with the popup, I'm afraid you're probably stuck the workaround I used with the regular window on top, by using the ImGuiWindowFlags_NoBringToFrontOnFocus flag on the base window while the pseudo-popup is up. If you need it to act like a regular popup you can probably just check if the input lost keyboard focus or the mouse was pressed anywhere outside the input box or the popup.

I'll strip out the bloat from my implementation and post in a few minutes so you can have a functional example.

inflex commented 8 years ago

Thanks for that @harold-b . Ideally what I'd be trying to do is have the popup of candidates respond to up/down/enter (to select a candidate) or mouseclick, which then collapses the popup giving the main dialog full keyboard control again.

At the moment I'm doing a real "hack job" and simply building a list of small buttons under the field, only downside is that they have no keyboard control (ie, I can't pick a specific one with up/down->enter).

ss

harold-b commented 8 years ago

For some reason I'm not getting some events fired on the popup window now in the stripped down version... It's very late here so unfortunately I'm going to have to pause it for tonight. But I can fix it up and post it tomorrow. Please bare with me.

inflex commented 8 years ago

That's fine, no rush. I'm only looking to improve the usability of things here, it's not 'critical' Just was happy that there was an issue-thread with similar requirement.

:+1:

harold-b commented 8 years ago

@inflex Thanks for your patience. Here's the gist for the example, I tried to keep it fairly simply:

https://gist.github.com/harold-b/7dcc02557c2b15d76c61fde1186e31d0

inflex commented 8 years ago

@harold-b simply brilliant, many thanks for that block of code, certainly an item to come in great use with many people I think :+1:

harold-b commented 8 years ago

My pleasure :)

rokups commented 4 years ago

demo

static char input[32]{""};
ImGui::InputText("##input", input, sizeof(input));
ImGui::SameLine();
static bool isOpen = false;
bool isFocused = ImGui::IsItemFocused();
isOpen |= ImGui::IsItemActive();
if (isOpen)
{
    ImGui::SetNextWindowPos({ImGui::GetItemRectMin().x, ImGui::GetItemRectMax().y});
    ImGui::SetNextWindowSize({ImGui::GetItemRectSize().x, 0});
    if (ImGui::Begin("##popup", &isOpen, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_Tooltip))
    {
        ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow());
        isFocused |= ImGui::IsWindowFocused();
        static const char* autocomplete[] = {"cats", "dogs", "rabbits", "turtles"};
        for (int i = 0; i < IM_ARRAYSIZE(autocomplete); i++)
        {
            if (strstr(autocomplete[i], input) == NULL)
                continue;
            if (ImGui::Selectable(autocomplete[i]) || (ImGui::IsItemFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Enter)))
            {
                strcpy(input, autocomplete[i]);
                isOpen = false;
            }
        }
    }
    ImGui::End();
    isOpen &= isFocused;
}

There are still problems:

gallickgunner commented 4 years ago

@ocornut - Are there any plans to have a proper laid out solution for this? The above solutions don't work if you want the same functionality with popups or perhaps I might have missed something. For example in my case, my file dialog is a Popup Modal and an InputText is rendered inside it. I want to show another autocomplete popup like the OP when the user starts typing on the Input Bar but there is no way around it since,

1) As soon as the popup comes the Input loses focus, If you try to regain focus the Popup closes as intended.

2) I can't hack my autocomplete popup as an ImGui Window (ImGui::Begin not child) since I'm currently inside a Popup Modal. Opening a Window over the modal by using ImGuiWindowFlags_NoBringToFrontOnFocus on the main Modal window brings the autocomplete Window to the top of the modal but it's not interactable at all since the Popup Modal is supposed to block interaction with windows prolly.

Any other way, you can think of, I can hack to get this working? Here is a picture.

Untitled

3) I tried using a child window ( ImGui::BeginChild ) for the autocomplete popup. While this does everything I want ( the input doesnt loses focus anymore) there seems to be a transparency issue which doesn't go away even after setting alpha to 1.0 by using ImGuiSetNextWindowBgAlpha()

Untitled

Code:

if(ImGui::BeginPopupModal("Open File", nullptr, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse))
{
    // Draw Top and Middle Region ...

    if(show_popup)
    {
        ImGuiWindowFlags popupFlags = ImGuiWindowFlags_NoTitleBar |
                                  ImGuiWindowFlags_NoResize   |
                                  ImGuiWindowFlags_NoMove     |
                                  ImGuiWindowFlags_NoFocusOnAppearing |
                                  ImGuiWindowFlags_NoScrollbar |
                                  ImGuiWindowFlags_NoSavedSettings;

        ImGui::PushClipRect(ImVec2(0,0), ImGui::GetIO().DisplaySize, false);
        ImGui::SetNextWindowBgAlpha(1.0);
        ImGui::SetNextWindowPos(popup_pos);
        ImGui::SetNextWindowSize(popup_sz);
        ImGui::BeginChild("##InputBarComboBox", popup_sz, true, popupFlags);

        //Draw List
        /*
        if(ImGui::ListBoxHeader("##InputBarComboBox", ImVec2(0,150))) ....
        */    

        ImGui::EndChild();
        ImGui::PopClipRect();
    }
    // Draw Checkbox, Buttons Inside Popup Modal
     ImGui::EndPopup() 
}
gallickgunner commented 4 years ago

Ok so I managed to solve the issue in 3. Apparently, either I misunderstood how the Z ordering works or there isn't proper support for it as the OP seems to be suggesting that as well.

The issue in 3 happened because I drew the child window first and then drew the bottom checkboxe and buttons in the parent window. I thought the child window should appear on top regardless of "when" it's drawn. Drawing the checkboxes and other things before drawing the child window solved the transparency issue.

sonoro1234 commented 4 years ago

I need a Popup that let use mouse input outside it (without closing) because it is a mesh editor that uses parameters from the Popup but also mouse actions done outside the Popup. Are the tips mentioned in this thread the only way to achieve it?

I think they are not applicable to my use case as I dont want to interactuate with other window but with the whole imgui viewport.

ocornut commented 4 years ago

Don’t use a popup then?

sonoro1234 commented 4 years ago

Yes!!

frink commented 4 years ago

I've seen several solutions here. Is there agreed canonical way to do this yet? I saw the note referring to this issue from #2119 which seems like most people's use case and looked at #1658 as well. Seems like there are a lot of ways to provide similar results. Would be nice to have a correct way to do it...

pixtur commented 3 years ago

It would be great if this would be a built in component/behavior for drop down lists.

EricStancliff commented 3 years ago

I spent all day messing with this and I think I finally figured out a hack/workaround that works for me - maybe someone else will benefit. I was unable to use the above "fake" popup implementation because when the item was selected, it would close my parent window, which happened to be a different popup. After much messing around and reading how menus are done,I figured out that if I pass the ImGuiWindowFlags_ChildWindow to the BeginPopup function, everything works as expected!. Here is my code (edited to remove my actual list contents):

        ImGui::InputText("##searchText", &currentText, flags);

        auto id = ImGui::GetItemID();
        ImVec2 textPos{ ImGui::GetItemRectMin().x, ImGui::GetItemRectMax().y };

        if (ImGui::IsItemActive())
        {
            ImGui::OpenPopup("##SearchBar");
        }
        auto textInputState = ImGui::GetInputTextState((ImGuiID)id);
        if (textInputState)
        {
            ImGui::SetNextWindowPos(textPos, ImGuiCond_Always);
            if (ImGui::BeginPopup("##SearchBar", ImGuiWindowFlags_ChildWindow))
            {
                ImGui::PushAllowKeyboardFocus(false);

                int numHints = 0;
                std::string inputStr;
                inputStr.resize(textInputState->TextW.size());

                ImTextStrToUtf8(inputStr.data(), (int)inputStr.size(), textInputState->TextW.Data, textInputState->TextW.Data + textInputState->TextW.Size);
                inputStr.resize((size_t)textInputState->CurLenW);

                for (auto&& option : optionList)
                {
                    if (nameContainsPhrase(option, inputStr))
                    {
                        if (ImGui::Selectable(option.c_str()))
                        {
                            output = option;
                            edited = true;
                        }
                        ++numHints;
                    }
                    if (numHints > 10)
                    {
                        ImGui::Text("...");
                        break;
                    }
                }

                ImGui::PopAllowKeyboardFocus();
                ImGui::EndPopup();
            }
        }
nukeulater commented 2 years ago

I got it working by creating a new flag for the TextInput item, called ImGuiInputTextFlags_DisplaySuggestions, which will create a popup window that subsequently has a new internal flag ImGuiWindowFlags_SuggestionPopup, preventing ClearActiveID() to execute inside ImGui::FocusWindow() like this:

if (window == NULL || !(window->Flags & ImGuiWindowFlags_SuggestionPopup))
{
    if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window)
        if (!g.ActiveIdNoClearOnFocusLoss)
            ClearActiveID();
}

And the code at the end of InputTextEx():

    const bool input_text_is_active = ImGui::IsItemActive();

    // create the suggestions popup window
    if (is_displaying_suggestion_popup && input_text_is_active)
    {
        ImGuiID suggestion_menu_id = g.CurrentWindow->GetID("##sugestions");
        bool popup_open = IsPopupOpen(suggestion_menu_id, ImGuiPopupFlags_None);
        if (!popup_open /*there's any things to display*/)
        {
            OpenPopupEx(suggestion_menu_id, 0);
        }

        // set the next popup position to the last caret position
        ImVec2 suggestion_menu_pos = ImGui::GetCursorScreenPos();
        ImGui::SetNextWindowPos(suggestion_menu_pos);

        if (BeginTextInputSuggestionPopup(suggestion_menu_id, 0))
        {
            //TODO: add suggestion implementation
            for (int i = 0; i < 5; i++)
                if (ImGui::Selectable("test completion", true)) {}

            EndPopup();
        }
    }

    IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
    if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0)
        return enter_pressed;
    else
        return value_changed;
}

This allows the popup window to display over the console, without taking the keyboard input away from the text input widget. I have no idea if this will introduce any bugs, didn't really dig in too deep into ImGui's internals to get a better understanding of how the code works, although I couldn't find any issues so far, at the point of writing this. If anyone else has any suggestions on how to improve this or potential issues please let me know!

Here is how it looks: image

squadack commented 2 years ago

Moving here from duplicate issue #5513. I’m looking for a way to display an intractable popup, like code completion in regular code editor. I have tried rokups’ solution, which works nice, but I have two main problems:

  1. I have multiple widgets, where I want to be able to show clickable hints, so static variable doesn’t mix well with that (the same goes for any solutions that require some global state).
  2. Creating window by hand and forcing it to be on top works nice in regular scenario, but putting it inside a modal popup breaks interactabilty.

The big question is - and I know I’m going to sound like an echo in here, but maybe something has emerged since this thread started - is there any Correct™ way to implement this? If not, are there any plans to add something like “interactive tooltip” as a built-in widget (or any component that could be used for this)?

ocornut commented 2 years ago

I had a better look at this thread today. I'll try to do a recap, with comments and fixes.

Rokups' suggestion ( https://github.com/ocornut/imgui/issues/718#issuecomment-578391838 ) It is essentially using a regular Begin() with the ImGuiWindowFlags_Tooltip flag. It's technically ill-defined behavior but gets us most of the way. Some of the property of a tooltip is to always be on top, while not taking focus. Until today it didn't work when used inside a modal but as mentioned that's fixed now. One of the issue is if the parent window has a title bar (e.g. a modal) then at the time you click on one of the selectable, you'll see the parent window lose focus in the title bar while clicking, which is a bit displeasing. Keyboard navigation doesn't work because the suggestion window is never focused.

EricStancliff's suggestion ( https://github.com/ocornut/imgui/issues/718#issuecomment-806165480 ) Using BeginPopup() + ImGuiWindowFlags_Child. Intuitively this seems even less defined behavior that the earlier solution. But somehow it generally works better now and does make sense (~Child window are over their Parent but don't steal focus when appearing). With the right glue code, you can get it to react to keyboard input, have the popup be closed with Esc, etc.

Here's what a believe is a decent solution based on the later: (reminder: need 1dd964f8)

// State
static char input[32]{ "" };

// Code
const bool is_input_text_enter_pressed = ImGui::InputText("##input", input, sizeof(input), ImGuiInputTextFlags_EnterReturnsTrue);
const bool is_input_text_active = ImGui::IsItemActive();
const bool is_input_text_activated = ImGui::IsItemActivated();

if (is_input_text_activated)
    ImGui::OpenPopup("##popup");

{
    ImGui::SetNextWindowPos(ImVec2(ImGui::GetItemRectMin().x, ImGui::GetItemRectMax().y));
    //ImGui::SetNextWindowSize({ ImGui::GetItemRectSize().x, 0 });
    if (ImGui::BeginPopup("##popup", ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_ChildWindow))
    {
        static const char* autocomplete[] = { "cats", "dogs", "rabbits", "turtles" };

        for (int i = 0; i < IM_ARRAYSIZE(autocomplete); i++)
        {
            //if (strstr(autocomplete[i], input) == NULL)
            //    continue;
            if (ImGui::Selectable(autocomplete[i]))
            {
                ImGui::ClearActiveID();
                strcpy(input, autocomplete[i]);
            }
        }

        if (is_input_text_enter_pressed || (!is_input_text_active && !ImGui::IsWindowFocused()))
            ImGui::CloseCurrentPopup();

        ImGui::EndPopup();
    }
}

It's not ideal but seemingly does the job decently. It does work better with ImGuiConfigFlags_NavEnableKeyboard as this allows closing the popup with ESC (but with two presses), so maybe best adding custom code for that now.

I'll try to massage that, add regression tests for it, and see if some of it can be standardized or demoed. Working on that made be really want #5606 too..

BanditTech commented 1 year ago

https://github.com/BanditTech/Triggered/blob/4a19bd56fece77f30cd8b2be35965ad12091fb76/DropdownBoxUtility.cs

For anyone who is trying to recreate this solution in C# YxSLsCEv3Z

parbo commented 1 year ago

I have a somewhat related question. How can I make a popup (using any of the methods in https://github.com/ocornut/imgui/issues/718#issuecomment-1249822993) be positioned where the text cursor currently is? Especially for InputTextMultiLine. Like a completion popup works in text editors. Is there a way to get that info?

parbo commented 1 year ago

I managed to hack something together:

    static auto ime_fn = io.SetPlatformImeDataFn;
    static auto *app = spim_app.get();
    io.SetPlatformImeDataFn = [](ImGuiViewport *viewport, ImGuiPlatformImeData *data) {
      app->setInputPos(data->InputPos[0], data->InputPos[1]);
      return ime_fn(viewport, data);
    };

Is there a better way?

parbo commented 1 year ago

Is there anyway to intercept the up/down arrow when using InputTextMultiLine? I'm trying to implement an auto-complete popup: image

It seem like the only key I can use to do stuff is TAB.

damian-kos commented 10 months ago

https://github.com/ocornut/imgui/issues/718#issuecomment-1249822993 Following this proposal there is an issue where I run this popup as a child of Begin() with passed bool *p_open. When Popup was activated, and it's parent window is closed by upper_right Close buton, it throws Assertion failed: window == window->RootWindow, file \...\imgui.cpp, line 7659 However if we activate it and before using Close button x we change focus to any other window on viewport it does not occur.

Anything I can follow to resolve this?

PapaNaxos commented 10 months ago

EDIT Sorry, it looks like this has been address in your recent commit 0860671

Original Comment:

https://github.com/ocornut/imgui/issues/718#issuecomment-1811071012

Posting to confirm I also have encountered this bug.

If the auto-complete popup is open when you click the 'X' button of the window, you'll get the failed assertion, mentioned by @damian-kos

Here is a minimal reproduction, using 1.90 WIP imgui-docking branch (viewports enabled)

void MinimalBug()
{
    static bool open = true;

    if (!open) return;

    if (ImGui::Begin("Bug Window", &open))
    {
        // State
        static char input[32]{ "" };

        // Code
        const bool is_input_text_enter_pressed = ImGui::InputText("##input", input, sizeof(input), ImGuiInputTextFlags_EnterReturnsTrue);
        const bool is_input_text_active = ImGui::IsItemActive();
        const bool is_input_text_activated = ImGui::IsItemActivated();

        if (is_input_text_activated)
            ImGui::OpenPopup("##popup");

        {
            ImGui::SetNextWindowPos(ImVec2(ImGui::GetItemRectMin().x, ImGui::GetItemRectMax().y));
            //ImGui::SetNextWindowSize({ ImGui::GetItemRectSize().x, 0 });
            if (ImGui::BeginPopup("##popup", ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_ChildWindow))
            {
                static const char* autocomplete[] = { "cats", "dogs", "rabbits", "turtles" };

                for (int i = 0; i < IM_ARRAYSIZE(autocomplete); i++)
                {
                    //if (strstr(autocomplete[i], input) == NULL)
                    //    continue;
                    if (ImGui::Selectable(autocomplete[i]))
                    {
                        ImGui::ClearActiveID();
                        strcpy(input, autocomplete[i]);
                    }
                }

                if (is_input_text_enter_pressed || (!is_input_text_active && !ImGui::IsWindowFocused()))
                    ImGui::CloseCurrentPopup();

                ImGui::EndPopup();
            }
        }
    }
    ImGui::End();
}
ocornut commented 9 months ago

Is there anyway to intercept the up/down arrow when using InputTextMultiLine? [...] It seem like the only key I can use to do stuff is TAB.

You can use ImGuiInputTextFlags_CallbackHistory: // Callback on pressing Up/Down arrows (for history handling)

Was named this way as I initially envisioned is for history of e.g. a console input.

I'll spend some time now working on this and #2057 and see if I can come up with canonical or out-of-box code.