I am trying to create an on screen keyboard to edit text on systems without a keyboard.
Something like that.

The problem is that pressing any button "steals" the keyboard focus from the input text widget.
What's the most intelligent way of handling this scenario?
I have seen a few similar topics in the issues but nothing 100% equal to this case.
Hello Stefano,
At the moment there's no way to avoid that with the default button behavior.
Here are a few ideas and workaround:
You may create your own button using ButtonBehavior() with ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_NoHoldingActiveID and it should work, but you would be losing the regular "need to hold and release over button to press" behavior, instead it will activate the button on press.
You may do like the demo console and force reactivate focus after it has been lost, which will work but will probably look awkward ("flickering" cursor). Also note that current syntax may be obsolete as the Nav branch will provide more complete control over focus, but it won't be too hard to fix later.
The demo code does the awkward:
if (ImGui::IsItemHovered() || (ImGui::IsRootWindowOrAnyChildFocused() && !ImGui::IsAnyItemActive() && !ImGui::IsMouseClicked(0)))
ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
Current Nav branch uses an explicit flag that you could set when pressing a keyboard key:
// Demonstrate keeping focus on the input box
if (reclaim_focus)
ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
Also linking to #622 and #727 which relate to similar things.
Hello Omar,
Thanks for the response, just incredibly fast as always.
Your first option to use ButtonBehavior with the NoHoldingActiveID doesn't look correct to me because it's clearing the active id and not restoring InputText one
The second tip, will not preserve the state of the input text. If you use the SetKeyboardFocusHere, InputText will select all text inside of it.
I have also tried (hacking in the internal api) to save and restore the entire ActiveID* state variables and it works, but I have found another problem that prevents me from getting the behavior I like.
The textbox is using the X component of the mouseclick to move the current cursor position, so even if you restore the focus correctly you get the character inserted in the wrong place.

The relevant code in InputTextEx is:
// Edit in progress
const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX;
const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f));
const bool osx_double_click_selects_words = io.OSXBehaviors; // OS X style: Double click selects by word instead of selecting whole text
if (select_all || (hovered && !osx_double_click_selects_words && io.MouseDoubleClicked[0]))
{
edit_state.SelectAll();
edit_state.SelectedAllMouseLock = true;
}
else if (hovered && osx_double_click_selects_words && io.MouseDoubleClicked[0])
{
// Select a word only, OS X style (by simulating keystrokes)
edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT);
edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT);
}
else if (io.MouseClicked[0] && !edit_state.SelectedAllMouseLock)
{
stb_textedit_click(&edit_state, &edit_state.StbState, mouse_x, mouse_y);
edit_state.CursorAnimReset();
}
else if (io.MouseDown[0] && !edit_state.SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f))
{
stb_textedit_drag(&edit_state, &edit_state.StbState, mouse_x, mouse_y);
edit_state.CursorAnimReset();
edit_state.CursorFollow = true;
}
if (edit_state.SelectedAllMouseLock && !io.MouseDown[0])
edit_state.SelectedAllMouseLock = false;
I was trying to get this done without modifying imgui core, but I am thinking that is not possible.
Thanks again for your inputs.
Your first option to use ButtonBehavior with the NoHoldingActiveID doesn't look correct to me because it's clearing the active id and not restoring InputText one
That's correct. Removing the ClearActiveID() in that block would be harmless and we could do that (but your other problem stands).
The second tip, will not preserve the state of the input text. If you use the SetKeyboardFocusHere, InputText will select all text inside of it.
I cannot reproduce that. The code is normally programmed to restore cursor/selection of an InputText (it works as tested in "Focus from code" now).
I see the problem with testing for io.MouseDown[0] if we try to restore the ActiveID, to handle that "ActiveID stack" we should be perhaps tracking which active ID is owning which click. I will look try to look into that later.
In the meanwhile it may be worth investigating why SetKeyboardFocusHere() is losing your selection/cursor because it should not. It does if the ImGuiInputTextFlags_AutoSelectAll flag is set.
You are right, I cannot reproduce the issue with the text being selected automatically with SetKeyboardFocusHere, I was probably doing something wrong during the many tests I've been doing.
I have found one very simple way of getting rid of the problem with io.MouseDown[0] when restoring ActiveID...I just draw the keyboard before the input text!

It's not ideal but works for what I need. I am thinking that I could "reserve" the space for the text box without drawing it, draw the keyboard and then roll-back the Cursor position to draw the inputtext...or force another window or a child/popup window to be drawn before the input text.
A true hack would be to use a second imgui context just for the keyboard...
It's output then gets sent to the primary context that hold the textbox.
This is an excellent idea!
I got it working somehow but if I will ever revisit this topic that's something I would try for sure.
Part of the issue here and #1554 (but that's not all there is to it), is that the code path when programmatically focusing an InputText() automatically select all the text. This was an arbitrary decision but I think it came mostly to mimic the behavior of Tabbing through widgets (which auto select the text).
When I rework the focus/activation API (it's currently a big big mess) I imagine there could be different flags to specify more detailed behavior (positioning the Nav focus/selection vs activating the widget vs activating + selecting all). If this is specified on the calling function the flags have to be designed in an InputText-agnostic way (focus vs activate vs xxx?). This is a perfect use case to design that focus/activation API.
Short term I could either:
A. Introduce a flag to disable this. I don't have a name yet that's both accurate and not awkward (e.g. ImGuiInputTextFlags_NoSelectOnProgrammaticFocus).
B. Reverse the behavior: do NOT select on programmatic focus by default but tabbing will keep the selection. If the input text doesn't have a cursor set the cursor at the end of text.
I think (B) is best though it is technically breaking the existing select-all behavior.
Any opinion on that? @Pagghiu @sebasobotka, Anyone using SetKeyboardFocusHere() to activate InputText() fields?
I have found one very simple way of getting rid of the problem with io.MouseDown[0] when restoring ActiveID...I just draw the keyboard before the input text!
Btw I think this is the bug I fixed in https://github.com/ocornut/imgui/commit/7ccbb765e2c0acc84b3e5d7335050e0af8bb555f
Thanks for the bugfix, I will try at some point. I have solved also by reserving space for the input box, draw the keyboard first and the input box later, rolling back the cursor position appropriately. It's a little bit of a hack but it works.
I will try removing this hack at some point once I will update to latest version of the lib.
Regarding the behaviour I prefer option B, that is not to select on programmatic focus.
I would figure out if it's possible (and not too complex) to add a kinda of ImGuiInputTextFlags_NoSelectOnProgrammaticFocus (or the reverse) to SetKeyboardFocusHere() as a parameter and not to the InputText. If that's possible, the default could be either selecting or not selecting, it doesn't really matter to me.
Thanks!
Yes I intend to move those flag to the focus functions it makes a lot more sense. My short term plan will be to try to merge the Navigation branch (what's done of it) because it add extra emphasis on focus concepts, and then I can work on the focus functions over the upcoming weeks/months.
Ok, in other words you will be able to focus more on focus related things ;)
Most helpful comment
Part of the issue here and #1554 (but that's not all there is to it), is that the code path when programmatically focusing an InputText() automatically select all the text. This was an arbitrary decision but I think it came mostly to mimic the behavior of Tabbing through widgets (which auto select the text).
When I rework the focus/activation API (it's currently a big big mess) I imagine there could be different flags to specify more detailed behavior (positioning the Nav focus/selection vs activating the widget vs activating + selecting all). If this is specified on the calling function the flags have to be designed in an InputText-agnostic way (focus vs activate vs xxx?). This is a perfect use case to design that focus/activation API.
Short term I could either:
A. Introduce a flag to disable this. I don't have a name yet that's both accurate and not awkward (e.g.
ImGuiInputTextFlags_NoSelectOnProgrammaticFocus).B. Reverse the behavior: do NOT select on programmatic focus by default but tabbing will keep the selection. If the input text doesn't have a cursor set the cursor at the end of text.
I think (B) is best though it is technically breaking the existing select-all behavior.
Any opinion on that? @Pagghiu @sebasobotka, Anyone using SetKeyboardFocusHere() to activate InputText() fields?