Prevent from entering more than x characters in InputText?


#1

I adapted the demo console example into a chatbox system for my application, and I wondered something.

My buffer has a length of 2001 (2000 characters + the \0 character), and I provide a buffer size of 2000 to InputText. But when I tested, I was able to enter more than 2000 characters, which led to a segmentation fault as I tried to enter a 2002nd one.

Is there a way (maybe using a callback) of preventing the user from inputting of a 2001st character if there are already 2000 ?

Thanks in advance for your answer(s)!


#2

My buffer has a length of 2001 (2000 characters + the \0 character), and I provide a buffer size of 2000 to InputText .

InputText automatically limit the text size to whatever buffer size you gave it (minus 1 for the zero terminator).
So either you made a mistake in the code either you have a version with a bug.


#3

The version I have was cloned on the 4th of October 2018.


#4

See if it happens in the imgui demo. It doesn’t appear here.


#5

It doesn’t happen in the demo, so I fetched and pulled the new changes from the repo and rebuilt the lib completely.

I still get the issue. Even when I tested with ImGui::TextInput("##Chatbox", buf, 20, ImGuiInputTextFlags_EnterReturnsTrue); (my buffer still has a size of 2001).


#6

Well I don’t know what to tell you, there’s a bug in your code and you are not posting your code so we can’t magically figure what it is. This is NOT your actual code:

ImGui::TextInput("##Chatbox", buf, 20, ImGuiInputTextFlags_EnterReturnsTrue);

I can tell because there’s no function called TextInput() in ImGui, the function is called InputText(). When “translating” your code to a post here you are likely omitting the elements that are actually important to your issue.

This is a reason many places are asking for an actual MCVE (https://stackoverflow.com/help/mcve) in many places :slight_smile:

If I pasted this in a codebase now: (I just tried)

static char buf[1000];
ImGui::InputText("##Chatbox", buf, 20, ImGuiInputTextFlags_EnterReturnsTrue);

The text is limited to 20 characters regardless of using keyboard input or clipboard paste.


#7

This is my actual code (I wrote from memory before, as I wasn’t on the right machine until a few minutes ago):

ImGui::InputText("##MessageBox",
                 InputBuf,
                 20,
                 ImGuiInputTextFlags_EnterReturnsTrue|ImGuiInputTextFlags_CallbackResize,
                 &CharCounterCallback,
                 (void*)this);

I forgot I made that callback to implement a character counter. When I remove what’s between ImGuiInputTextFlags_EnterReturnsTrue and the closing ), the character limit works correctly.

Here’s the callback’s code (adapted from the console example in the demo):

static int CharCounterCallback(ImGuiInputTextCallbackData* data)
{
    Chatbox* chatbox = (Chatbox*)data->UserData;
    chatbox->Characters = data->BufTextLen;
    return 0;
}

#8

1/ You are not testing the event flag correctly in your callback.
2/ You are specifying the Resize flag which has the explicit purpose of requesting new buffer size to the callback. In other words, you are explicitely enabling a feature that allows resizing while misusing it (not honoring resize requests). (And omitted mentioning it until now)


#9

I think I understand this more clearly: you misunderstood the purpose of the ResizeCallback flag. Perhaps I should rename this flag or clarify the comments around it.

Since your strings are small (2000 is small) you may just test the return value of InputText and call strlen() on your buffer when it returns true.


#10

See this reference for callback handler:

Currently I’m not sure resize callback can be used if you cannot resize your underlying buffer. I’ll double check tomorrow and it’ll be nice to also support the use case you were intending to use, but it wasn’t the initial intent.


#11

Well, I managed to fix it. Partially.

So, I get either a charcounter that works without callbacks or the ability to send messages using Enter (as the EnterReturnsTrue flag prevents the editing of text from returning true).

Unless I’m doing something wrong.

I tried this:

if(ImGui::InputText("##MessageBox",
                    InputBuf,
                    IM_ARRAYSIZE(InputBuf)))
{
    if(ImGui::IsKeyPressed(ImGuiKey_Enter))
    {
        // Code I took from the console example in the demo
        char* s = InputBuf;
        Strtrim(s);
        if (s[0])
            SendMessage(s);
        strcpy(s, "");
    }
    else
    {
        CharCounter = strlen(InputBuf);
    }
    reclaim_focus = true;
}

I also tried with IsKeyDown and IsKeyReleased, but nothing worked.

I guess there are other ways of doing what I want, but I can’t think of any at the moment.


#12

I guess a night of sleep helped me. This works:

// Input box
bool reclaim_focus = false;
ImGui::PushItemWidth(-90);
if(ImGui::InputText("##MessageBox",
                    InputBuf,
                    IM_ARRAYSIZE(InputBuf),
                    ImGuiInputTextFlags_EnterReturnsTrue))
{
    char* s = InputBuf;
    Strtrim(s);
    if (s[0])
        SendMessage(s);
    strcpy(s, "");
    reclaim_focus = true;
}
ImGui::PopItemWidth();
ImGui::SameLine();
ImGui::Text("%i/2000", strlen(InputBuf));

#13

I guess a night of sleep helped me. This works:

Yes this is good :slight_smile:

(as the EnterReturnsTrue flag prevents the editing of text from returning true).

From 1.63 you can call ImGui::IsItemEdited() which serves this purpose (generally returns the same as the bool return value of most widgets).

I made a mistake with the design of ImGuiInputTextFlags_CallbackResize which serves both of purpose of notifying of a size change and requesting capacity changes. I will work something out…