A virtual keyboard in Dear ImGui

A virtual keyboard in Dear ImGui

A virtual keyboard in Dear ImGui

10 Nov

Written By Roderick Kennedy

There are a few kinks implementing a virtual keyboard in Dear ImGui - the main problem is getting key inputs from the buttons into the InputText item.

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 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

A virtual keyboard in Dear ImGui

10 Nov

Written By Roderick Kennedy

There are a few kinks implementing a virtual keyboard in Dear ImGui - the main problem is getting key inputs from the buttons into the InputText item.

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 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