# A virtual keyboard in Dear ImGui

A virtual keyboard in Dear ImGui
================================

10 Nov

Written By [Roderick Kennedy](https://roderickkennedy.com/dbgdiary?author=5f08d2770b281846bf04ee3b)

There are a few kinks implementing a virtual keyboard in [Dear ImGui](https://github.com/ocornut/imgui) - the main problem is getting key inputs from the buttons into the InputText item.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707394742834/1d21c959-c09a-4b3e-a8dd-f695aef9e456.png)

Clicking a button changes focus to the button - away from the InputText. You can switch it back on the next pass, but ImGui won’t recognize it as being ready for input until two frames later.  
So I implemented a counter called “refocus”. It’s set to zero every time we click a keyboard button. It increments every frame. Only when it gets to 2 or greater do we pull the inputs from out of our buffer.

Our variables are:

        std::vector<unsigned int> keys_pressed;

        int refocus=0;

Here’s the code:

            ImGui::Begin("Virtual Keyboard");
            io.KeysDown[VK_BACK] = false;
            if(refocus==0)
            {
                ImGui::SetKeyboardFocusHere();
            }
            else if(refocus>=2)
            {
                while(keys_pressed.size())
                {
                    int k=keys_pressed[0];
                    if(k==VK_BACK)
                    {
                        io.KeysDown[k] = true;
                    }
                    else
                    {
                        io.AddInputCharacter(k);
                    }
                    keys_pressed.erase(keys_pressed.begin());
                }
            }
            static char buf[500];
            if(ImGui::InputText("", buf, IM_ARRAYSIZE(buf)))
            {
                current_url=buf;
            }
            refocus++;

We define a simple lambda function to add a line of keys to the keyboard:

            auto KeyboardLine = [&io,this](const char* key)
            {
                size_t num = strlen(key);
                for (size_t i = 0; i < num; i++)
                {
                     char key_label[] = "X";
                     key_label[0] = *key;
                     if (ImGui::Button(key_label,ImVec2(46,32)))
                     {
                         refocus=0;
                         keys_pressed.push_back(*key);
                     }
                     key++;
                     if (i<num-1)
                        ImGui::SameLine();
                }
            };

This allows us to add the number keys simply with:

            KeyboardLine("1234567890-");
            ImGui::SameLine();

Now here’s our backspace arrow button:

            if (ImGui::Button(ICON_FK_LONG_ARROW_LEFT,ImVec2(92,32)))
            {
                 refocus=0;
                 keys_pressed.push_back(ImGuiKey_Backspace);
            }

Using a Text() call to insert a bit of padding in front of the next row of keys:

            ImGui::Text("  ");
            ImGui::SameLine();
            KeyboardLine("qwertyuiop");
            ImGui::Text("    ");
            ImGui::SameLine();
            KeyboardLine("asdfghjkl");
            ImGui::SameLine();
            if (ImGui::Button("Return",ImVec2(92,32)))
            {
                 refocus=0;
                 keys_pressed.push_back(ImGuiKey_Enter);
            }
            ImGui::Text("      ");
            ImGui::SameLine();
            KeyboardLine("zxcvbnm,./");
            ImGui::End();

And done.

 [Roderick Kennedy](https://roderickkennedy.com/dbgdiary?author=5f08d2770b281846bf04ee3b)

A virtual keyboard in Dear ImGui
================================

10 Nov

Written By [Roderick Kennedy](https://roderickkennedy.com/dbgdiary?author=5f08d2770b281846bf04ee3b)

There are a few kinks implementing a virtual keyboard in [Dear ImGui](https://github.com/ocornut/imgui) - the main problem is getting key inputs from the buttons into the InputText item.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707394743906/40ce9636-e91e-42b3-a0ba-a3b6db0dd397.png)

Clicking a button changes focus to the button - away from the InputText. You can switch it back on the next pass, but ImGui won’t recognize it as being ready for input until two frames later.  
So I implemented a counter called “refocus”. It’s set to zero every time we click a keyboard button. It increments every frame. Only when it gets to 2 or greater do we pull the inputs from out of our buffer.

Our variables are:

        std::vector<unsigned int> keys_pressed;

        int refocus=0;

Here’s the code:

            ImGui::Begin("Virtual Keyboard");
            io.KeysDown[VK_BACK] = false;
            if(refocus==0)
            {
                ImGui::SetKeyboardFocusHere();
            }
            else if(refocus>=2)
            {
                while(keys_pressed.size())
                {
                    int k=keys_pressed[0];
                    if(k==VK_BACK)
                    {
                        io.KeysDown[k] = true;
                    }
                    else
                    {
                        io.AddInputCharacter(k);
                    }
                    keys_pressed.erase(keys_pressed.begin());
                }
            }
            static char buf[500];
            if(ImGui::InputText("", buf, IM_ARRAYSIZE(buf)))
            {
                current_url=buf;
            }
            refocus++;

We define a simple lambda function to add a line of keys to the keyboard:

            auto KeyboardLine = [&io,this](const char* key)
            {
                size_t num = strlen(key);
                for (size_t i = 0; i < num; i++)
                {
                     char key_label[] = "X";
                     key_label[0] = *key;
                     if (ImGui::Button(key_label,ImVec2(46,32)))
                     {
                         refocus=0;
                         keys_pressed.push_back(*key);
                     }
                     key++;
                     if (i<num-1)
                        ImGui::SameLine();
                }
            };

This allows us to add the number keys simply with:

            KeyboardLine("1234567890-");
            ImGui::SameLine();

Now here’s our backspace arrow button:

            if (ImGui::Button(ICON_FK_LONG_ARROW_LEFT,ImVec2(92,32)))
            {
                 refocus=0;
                 keys_pressed.push_back(ImGuiKey_Backspace);
            }

Using a Text() call to insert a bit of padding in front of the next row of keys:

            ImGui::Text("  ");
            ImGui::SameLine();
            KeyboardLine("qwertyuiop");
            ImGui::Text("    ");
            ImGui::SameLine();
            KeyboardLine("asdfghjkl");
            ImGui::SameLine();
            if (ImGui::Button("Return",ImVec2(92,32)))
            {
                 refocus=0;
                 keys_pressed.push_back(ImGuiKey_Enter);
            }
            ImGui::Text("      ");
            ImGui::SameLine();
            KeyboardLine("zxcvbnm,./");
            ImGui::End();

And done.

 [Roderick Kennedy](https://roderickkennedy.com/dbgdiary?author=5f08d2770b281846bf04ee3b)
