Using Input Text Callbacks for Validation and Custom Processing in Dear ImGui
Dear ImGui’s input text callbacks allow you to intercept, filter, and transform user input in real-time by implementing a custom function that receives an ImGuiInputTextCallbackData structure and returns 0 to accept changes or a non-zero value to reject them.
The ocornut/imgui repository provides a sophisticated callback mechanism for the InputText() widget that enables immediate validation and custom processing without requiring post-validation loops. By specifying flags when calling ImGui::InputText(), you can register a callback function that inspects and manipulates buffer contents during specific lifecycle events, keeping UI logic tight and performant.
How Input Text Callbacks Work in Dear ImGui
The callback system centers on two core declarations in imgui.h (around line 2658): the ImGuiInputTextCallback function pointer type and the ImGuiInputTextCallbackData structure. When you invoke ImGui::InputText() with specific flags, Dear ImGui dispatches events to your callback function, passing a mutable pointer to an ImGuiInputTextCallbackData instance containing the current buffer state and event context.
Your callback must return 0 to indicate success, or a negative value to abort the input operation entirely. For character filtering specifically, returning any non-zero value discards the candidate character.
Callback Flags and Event Types
You combine the following flags to determine when your callback executes:
ImGuiInputTextFlags_CallbackCharFilter– Invoked for each typed character before it enters the buffer. Return non-zero to reject the character or replaceEventCharto substitute it.ImGuiInputTextFlags_CallbackResize– Triggered when text exceeds the current buffer capacity, allowing dynamic reallocation.ImGuiInputTextFlags_CallbackEdit– Called after any insertion, deletion, or paste operation completes. Ideal for validation or formatting transformations.ImGuiInputTextFlags_CallbackAlways– Executed on every frame the widget remains active, regardless of whether editing occurred.
The ImGuiInputTextCallbackData Structure
The data structure passed to your callback provides comprehensive context for manipulation:
| Member | Purpose |
|---|---|
Buf |
Pointer to the mutable text buffer (including the terminating \0). |
BufTextLen |
Current length of the text in bytes, excluding the null terminator. |
BufSize |
Total allocated capacity of the buffer. |
Flags |
The ImGuiInputTextFlags originally passed to InputText(). |
EventFlag |
Specific flag indicating why the callback was triggered (CallbackCharFilter, CallbackEdit, etc.). |
EventChar |
The character code for CallbackCharFilter events. |
EventKey |
The key index for keyboard-related events. |
DeleteChars(), InsertChars() |
Helper functions to modify buffer contents programmatically during CallbackEdit. |
Practical Code Examples for Input Validation
Filtering Numeric Input with CallbackCharFilter
To restrict input to digits only, inspect EventChar during CallbackCharFilter events and return 1 to reject non-numeric characters:
int MyNumericCallback(ImGuiInputTextCallbackData* data)
{
if (data->EventFlag == ImGuiInputTextFlags_CallbackCharFilter)
{
if (!isdigit((unsigned char)data->EventChar))
return 1; // Discard non-digit characters
}
return 0;
}
// Usage
static char buf[64] = "";
ImGui::InputText("##num", buf, IM_ARRAYSIZE(buf),
ImGuiInputTextFlags_CallbackCharFilter,
MyNumericCallback);
Automatic Text Transformation with CallbackEdit
Use the edit callback to enforce formatting rules, such as converting all text to uppercase after each modification:
int UppercaseCallback(ImGuiInputTextCallbackData* data)
{
if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
{
for (int i = 0; i < data->BufTextLen; ++i)
data->Buf[i] = (char)toupper((unsigned char)data->Buf[i]);
}
return 0;
}
// Usage
static char name[128] = "";
ImGui::InputText("##name", name, IM_ARRAYSIZE(name),
ImGuiInputTextFlags_CallbackEdit,
UppercaseCallback);
Dynamic Buffer Resizing with CallbackResize
For inputs with unknown maximum length, implement a resize callback to reallocate memory when the user exceeds the current buffer capacity:
int ResizeCallback(ImGuiInputTextCallbackData* data)
{
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
{
size_t new_size = data->BufSize;
char* new_buf = (char*)malloc(new_size);
memcpy(new_buf, data->Buf, data->BufTextLen);
new_buf[data->BufTextLen] = '\0';
data->Buf = new_buf; // ImGui adopts this new pointer
}
return 0;
}
// Usage with heap-allocated buffer
char* dynamic_buf = (char*)malloc(128);
dynamic_buf[0] = '\0';
ImGui::InputTextMultiline("##dyn", dynamic_buf, 128,
ImVec2(0,0),
ImGuiInputTextFlags_CallbackResize,
ResizeCallback);
Complex Validation: Character Filtering and Length Constraints
Combine multiple validation rules within a single callback to enforce both content type and length restrictions:
int NumericAndLengthCallback(ImGuiInputTextCallbackData* data)
{
if (data->EventFlag == ImGuiInputTextFlags_CallbackCharFilter)
{
if (!isdigit((unsigned char)data->EventChar))
return 1; // Reject non-digits
if (data->BufTextLen >= 5)
return 1; // Enforce maximum length of 5 characters
}
return 0;
}
// Usage
static char pin[8] = "";
ImGui::InputText("##pin", pin, IM_ARRAYSIZE(pin),
ImGuiInputTextFlags_CharsDecimal |
ImGuiInputTextFlags_CallbackCharFilter,
NumericAndLengthCallback);
Core Implementation Files
Understanding where these mechanisms reside helps when debugging or extending functionality:
imgui.h– DeclaresImGuiInputTextCallback,ImGuiInputTextCallbackData, and all related flags.imgui.cpp– Contains theInputText()widget implementation and the dispatch logic that invokes your callbacks based on the activeEventFlag.misc/cpp/imgui_stdlib.cpp– Providesstd::stringoverloads that handleCallbackResizeautomatically, eliminating the need for manual memory management when using C++ strings.
Summary
- Input text callbacks in Dear ImGui provide real-time interception of user input through the
ImGuiInputTextCallbackfunction pointer andImGuiInputTextCallbackDatastructure. - Four distinct flags control callback timing:
CallbackCharFilterfor per-character filtering,CallbackEditfor post-modification processing,CallbackResizefor dynamic memory management, andCallbackAlwaysfor per-frame updates. - Return values determine flow: return
0to proceed, non-zero forCallbackCharFilterto discard characters, or negative values to abort the widget entirely. - Buffer manipulation occurs through direct pointer access (
Buf) or helper methods (InsertChars,DeleteChars) withinimgui.h’s callback data structure.
Frequently Asked Questions
How do I reject specific characters in ImGui::InputText?
Implement a CallbackCharFilter callback and inspect the EventChar member of the ImGuiInputTextCallbackData structure. Return any non-zero value (typically 1) to discard the character, or modify EventChar to substitute a different character before it enters the buffer.
Can I use std::string with input text callbacks instead of raw char buffers?
Yes. Include misc/cpp/imgui_stdlib.h and use the InputText overloads that accept std::string references. These implementations automatically handle the CallbackResize event by resizing the underlying string, eliminating the need for manual memory management in your callback code.
What is the difference between CallbackEdit and CallbackAlways?
CallbackEdit fires only after the buffer content actually changes due to insertion, deletion, or paste operations, making it efficient for validation and formatting. CallbackAlways executes on every frame while the widget is active, regardless of whether editing occurred, which is useful for implementing time-dependent features or continuous validation checks.
How do I enforce a maximum input length when using callbacks?
Check the BufTextLen member during CallbackCharFilter events and return non-zero if the current length already meets your limit. This prevents additional characters from entering the buffer. Alternatively, use the built-in ImGuiInputTextFlags_CharsDecimal or ImGuiInputTextFlags_CharsHexadecimal flags for common cases, and reserve the callback for custom business logic.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →