Virtual keyboard

Started by eugustus, 30 March 2021, 19:29:14

eugustus

Hello to everybody. Has anyone implemented a virtual keyboard with tgui? Can he do it at all? :)

texus

It depends on what you want to do.
If you just want some virtual keyboard to be displayed then you might be better of with calling some OS-specific function.
If you want to create a window with a virtual keyboard yourself then you could use TGUI for it, each key is simply a button.
If you want the virtual keyboard in the same window as your application then it might cause some issues: pressing a key on the keyboard will move the focus to that button, so the edit box that you had selected to type in will lose focus.

eugustus

I do not want OS-specific keyboard.
I see this so that the keyboard object must 'bind' to the input field. Each time the button is clicked, the input field must be re-focused programmatically. Which would mean that there could be two versions of how the keyboard can be binded to the input field. Either one 'singleton' for all input fields, or one 'no sengleton' for each input field?

texus

#3
They keyboard could be a Panel widget with a lot of buttons then. To show the keyboard you call gui.add(panel) and when you want to hide it you call gui.remove(panel).

I would implement it similar to what I describe below. Note that I didn't test any of this code or think about it for long, there might be other/better ways to do it (e.g. I know that the keyboardShown boolean could be replaced by querying the gui for whether it contains the panel).

Code (cpp) Select
void EditBoxOrTextAreaFocused(tgui::Widget::Ptr widget, const tgui::String& /*signalName*/)
{
    focusedTextField = widget;
    if (!keyboardShown)
    {
        keyboardShown = true;
        gui.add(keyboardPanel);
    }
}

Code (cpp) Select
void EditBoxOrTextAreaUnfocused()
{
    focusedTextField = nullptr;
    if (keyboardShown)
    {
        keyboardShown = false;
        gui.remove(keyboardPanel);
    }
}

Code (cpp) Select
editBoxOrTextArea->onFocus.connectEx(&EditBoxOrTextAreaFocused);
editBoxOrTextArea->onUnfocus(&EditBoxOrTextAreaUnfocused);


I'm using connectEx on onFocus instead of a normal connect in this example so that the callback function gets the widget as parameter without you having to pass it yourself. Otherwise you would need something like `editBoxOrTextArea->onFocus(&EditBoxOrTextAreaFocused, editBoxOrTextArea)` in which copy-paste errors are more likely to happen as you always need to pass the same argument as the widget on which you call onFocus.

For each button on the keyboard you could do something like this:
Code (cpp) Select
void VirtualKeyboardKeyPressed(char32_t key)
{
    assert(focusedTextField != nullptr);

    focusedTextField->setFocus(true);

    tgui::Event event;
    event.type = tgui::Event::Type::TextEntered;
    event.text.unicode = key;
    gui.handleEvent(event);
}

Code (cpp) Select
buttonKeyA->onPress(&VirtualKeyboardKeyPressed, 'a');

Backspace and other special keys need a separate function. You can use a KeyEvent instead of TextEvent to pass a backspace to TGUI.

EDIT: After typing this I just realized that unfocus is going to be a bit more difficult. In this code the EditBoxOrTextAreaUnfocused would be called and hide the keyboard each time you press a keyboard key.

eugustus

I'll Try to implement something. But it won't be in closely the days, I stumble into a new housing ... But I have to emphasize that I don't have to recall gui.handleEvent(...) inside the event handler again ..