ocornut / imgui

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

Several ImGui::InputText widgets and virtual keyboard in openframeworks #1554

Open sebasobotka opened 6 years ago

sebasobotka commented 6 years ago

I am using https://github.com/jvcleave/ofxImGui addon and I would like to use ImGui::InputText widgets and virtual keyboard. I did some tests and I cannot figure out how it should be.

My first approach: imgui_01

ImGui::InputText("##text1", buf1, bufSize);
ImGui::InputText("##text2", buf2, bufSize);
ImGui::InputText("##text3", buf3, bufSize); 

if (ImGui::Button("focus-1")) {
    keyboardFocus = 0;
    ImGui::SetKeyboardFocusHere(keyboardFocus);
}
ImGui::SameLine();
if (ImGui::Button("focus-2")) {
    keyboardFocus = 1;
    ImGui::SetKeyboardFocusHere(keyboardFocus);
}
ImGui::SameLine();
if (ImGui::Button("focus-3")) {
    keyboardFocus = 2;
    ImGui::SetKeyboardFocusHere(keyboardFocus);
}

if (ImGui::Button("a")) {
    virtualKey('a');
}

virtualKey(char key) {
    switch (keyboardFocus) {
    case 0:
        inputSize = std::strlen(buf1);
        buf1[inputSize] = key;
        break;
    case 1:
        inputSize = std::strlen(buf2);
        buf2[inputSize] = key;
        break;
    case 2:
        inputSize = std::strlen(buf3);
        buf3[inputSize] = key;
        break;
    }
}
  1. ImGuiIO& io = ImGui::GetIO(); io.AddInputCharacter(key); doesn't work here.
  2. There is no Cursor inside the box after appending the buffer. The text doesn't move at the end of the field.
  3. When I change the "focus" number, the text inside the box is highlighted. How can I avoid this?

My second approach: imgui_02

There is a set keyboard focus on particular textinput every frame and it steals focus from other widgets but my virtual keyboard and "focus switcher" is outside the ImGui Window and it works. The cursor moves when the text grows.

ImGui::SetKeyboardFocusHere(keyboardFocus);
ImGui::InputText("##text1", buf1, bufSize);
ImGui::InputText("##text2", buf2, bufSize);
ImGui::InputText("##text3", buf3, bufSize); 

void ofApp::mouseReleased(int x, int y, int button) {
        if (area1.isOver(x, y)) {
            keyboardFocus = 0;
        } 
        else if (area2.isOver(x, y)) {
            keyboardFocus = 1;
        }
        else if (area3.isOver(x, y)) {
            keyboardFocus = 2;
        }
        else {
            //char 'x' for test now
            virtualKey('x');
        }   
}
virtualKey(char key) {
    ImGuiIO& io = ImGui::GetIO();
    io.AddInputCharacter(key);
}
  1. The problem is when I change the "focus of textinput" the cursor sometimes is somewhere in the middle of the text (not at the end). How can I avoid that?

  2. My last question is: How can I change the Height of the TextInput widget? The width we can change using ImGui::PushItemWidth(200);

ocornut commented 6 years ago
  1. io.AddInputCharacter(key); doesn't work here.

First, InputText() when active owns the character buffer, you should always transmit those character via io.AddInputCharacter().

Secondly, characters inputs are cleared at the end of the frame. If you want to create a virtual keyboard you need to submit those characters before NewFrame().

But this is all very confusing. It feels like you are trying to use InputText but if you don't have a full keyboard why using InputText at all instead of just a char buffer you can fill however you want?

How far do you expect to get with those "A" "B" "C" buttons, does your platform/OS provide a virtual keyboard that you could activate? How do you expect the user to move the cursor or select text? If they can do that using the mouse/touch, then why do you have "Focus" buttons at all if they could touch the text?

  1. The problem is when I change the "focus of textinput" the cursor sometimes is somewhere in the middle of the text (not at the end). How can I avoid that?

Not sure what is happening, isn't the cursor positioning based on your touch horizontal psition?

  1. My last question is: How can I change the Height of the TextInput widget? The width we can change using ImGui::PushItemWidth(200);

The height of most widgets is FontSize + FramePadding.y * 2 (same as GetFrameHeight()). You can alter FramePadding.y accordingly, using PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(w,h))/PopStyleVar().

Also see: #1418

(Adding a link to #787. As part of the Nav branch I have unfinished/uncommitted work to enable more flexible focusing features, but they are not done)

ocornut commented 6 years ago

The problem is when I change the "focus of textinput" the cursor sometimes is somewhere in the middle of the text (not at the end). How can I avoid that?

Not sure what is happening, isn't the cursor positioning based on your touch horizontal psition?

I think I have now fixed a bug for this (see commit above). I'm still thinking about the issue of auto-selecting all and will post some ideas later. It's a problem that relates to some of the work I've been doing on focus/activation schemes.

sebasobotka commented 6 years ago

Hi, you are fast :) imgui_03

I provide a full virtual keyboard. That was only a short test before. My idea is to set keyboard focus using red active areas showed in the picture.

Using this I can still have access to other widgets :)

if (ImGui::IsWindowFocused() && !ImGui::IsAnyItemActive())
    ImGui::SetKeyboardFocusHere(keyboardFocus);

The last issue is the changing position of cursor but you did some improvements. I will check it.

sebasobotka commented 6 years ago

It seems to work !!! Thank you ;) I noticed when I switch to filled InputText, the cursor is set to the position where I clicked. I should provide the key arrows to move cursor position.

sebasobotka commented 6 years ago

I don't need my active areas to set keyboard focus. Now I am using ImGui method to set it.

ImGui::InputText("##text", buf, bufSize);
if (ImGui::IsItemClicked()) {
    keyboardFocus = 0;
}

if (ImGui::IsWindowFocused() && !ImGui::IsAnyItemActive()) {
    ImGui::SetKeyboardFocusHere(keyboardFocus);
}
  1. There is still a problem with selecting the text field outside the box. The same situation is when mouse is used. Please, see GIF below. drag2rot

  2. The buffer inside the InputText blinks (is shown internal buffer or something) when I send virtual function keys like LEFT_ARROW, RIGHT_ARROW, BACKSPACE. It is happening when buffer inside the InputText must be scrolled. It works properly using the normal hardware keyboard. blinks

ocornut commented 6 years ago

It's really hard to guess what is happening without repro code.

And your explanation are missing details. e.g. "when I send virtual function keys" vs "properly using the normal hardware keyboard." if there is a difference of behavior it is necessarily because you are doing something different from imgui point of view.

When you make GIF try to enable the software mouse cursor io.MouseDrawCursor to make it easier to understand.

sebasobotka commented 6 years ago

I will try to explain it again. The hardware keyboard is based on onKeyPressed and onKeyReleased events in openframeworks. When the key is pressed then io.KeysDown[key] = true; and when is released then io.KeysDown[key] = false;. Everything works fine.

On the above gif it's not visible but I am touching or clicking the backspace key on the virtual keyboard. The virtual key has the same value as from hardware key (259). I set io.KeysDown[key] = true before NewFrame() and one frame after I set io.KeysDown[key] = false;. This also works but the buffer inside the InputText blinks. When its size is wider than the width of the box there is some old buffer printed or something. I will try to make a better gif. I think it's related to mouse/touch event and then something happens in the InputText. The same situation is with the left and right arrow key.

When you make GIF try to enable the software mouse cursor io.MouseDrawCursor to make it easier to understand. I tried once but the cursor wasn't visible under the finger.

hippyau commented 3 years ago

Hi @sebasobotka, any chance you can post the code for your keyboard? It's looks really useful.

Zangetsu38 commented 3 years ago

@sebasobotka i confirm, if you canshare code for your keyboard, i want one on my project, but no idea how code this

hippyau commented 3 years ago

https://github.com/ocornut/imgui/issues/4066

rvkennedy commented 2 years ago

Very grateful for the above; here is my implementation: a-virtual-keyboard-in-dear-imgui The key I found was to implement a counter that resets when a key Button is pressed. When the counter reaches 2, the InputText is ready to receive keys from the buffer. As stated above, AddInputCharacter won't work for backspace, you must use io.KeysDown[VK_BACK] for this.

0lru commented 2 years ago

Hi. I tried the same. It works with InputText (yay). Unfortunately, it does not work with "numeric" (InputScalar) because it selects the whole text right after reactivation and thus deletes the content after each keystroke: image

(https://github.com/0lru/p3ui/blob/main/p3ui/widgets/keyboard.py)

Zangetsu38 commented 2 years ago

oups, i have forget share my proper keyboard works to 0 here is my code when i have improved it image here https://github.com/Vita3K/Vita3K/pull/1246 initial and more basic https://github.com/Vita3K/Vita3K/pull/1240