Qt Virtual Keyboard

24Jul 2015

Qt Virtual Keyboard

In this article, I show how to build a simple virtual keyboard in Qt. Many questions about this topic can be found, but unfortunately not many complete answers. I try to fill this gap with a straight forward solution that I believe is elegant and applicable in many situations.

The code is available on Github.

What is Available?

Depending on the platform where you use Qt, a virtual keyboard might already be present. This is the case for e.g. Windows CE or Android. In such cases, Qt should pick up the keyboard for you and everything should work.

In case there is no keyboard provided by the platform, you need a custom solution. Qt has a commercial offering of a virtual keyboard. This looks like a strong offering (though I have never used it so far). It has many advanced features and looks really nice. If you need a full-fledged keyboard, consider this option.

In many cases however, a simpler solution is good enough, especially in the embedded world. There, often a numeric-only keyboard is enough to change some settings.

How do we build it?

There are several options to build a virtual keyboard. The first is to use the Qt Platform Abstraction and write a QPlatformInputContext. While this is the most generic solution, it is a bit involved to build, and has its own set of of problems. One difficulty I had when trying this option was to avoid popup windows, which do not work on EGLFS.

For this reason, we use a simpler option and build the keyboard in pure QML. Below is a picture of what the final application looks like. There is an input field and two rows of keys from 1 - 3 plus some modifier keys.

Application with Virtual Keyboard.

The advantage of this solution is that it doesn’t have any dependency. It is a built-in keyboard.

What does the Concept Look Like?

Conceptually, we use a couple of QML buttons that, when pressed, send a specific keycode to a C++ class. This class then transforms the keycode into a QKeyEvent. This key event is then picked up by the Qt event loop and used by the input field.

The beauty of this solution is that pressing a virtual key behaves exactly the same as pressing the same key on a physical keyboard. Also, as you will see, the resulting code is very clean.

The reason we need to send the key events from C++ is that it is not yet possible to send such events directly from QML. But this is a small overhead and easy to code.

The QML Code

Below is the relevant QML code with the InputField and the Buttons. Whenever a button is pressed, it invokes the emitKey slot on the KeyEmitter C++ class. The result of this is a key event which is received by the currently focused component. If this is our text field, it processes the event. We can do whatever we want with this event. In this example, we attach two different behaviours. If an input is accepted (e.g. when OK is clicked), the focus is set to false. When the escape key is clicked, the text fields undo functionality is used to revert the last modification.

Window {

    TextField {
        text: "123"
        onAccepted: focus = false
        Keys.onEscapePressed: undo()
    }

    Row {
        Button {
            text: qsTr("1")
            onClicked: keyEmitter.emitKey(Qt.Key_1)
        }
        Button {
            text: qsTr("2")
            onClicked: keyEmitter.emitKey(Qt.Key_2)
        }
        Button {
            text: qsTr("3")
            onClicked: keyEmitter.emitKey(Qt.Key_3)
        }
    }
    Row {
        Button {
            text: qsTr("DEL")
            onClicked: keyEmitter.emitKey(Qt.Key_Backspace)
        }
        Button {
            text: qsTr("OK")
            onClicked: keyEmitter.emitKey(Qt.Key_Enter)
        }
        Button {
            text: qsTr("ESC")
            onClicked: keyEmitter.emitKey(Qt.Key_Escape)
        }
    }
}

As you can see in the code above, there is not dependency between the text field and the keyboard or its buttons. It is easy to create a reusable keyboard in a dedicated qml file. Also, the mechanism works on any component that has the keyboard input focus.

The C++ Code

Below is the C++ code that creates the QKeyEvent from the keycode that was sent from the QML buttons. It first searches for the widget that currently has the focus. If there is such a widget, it sends two key events to that widget. The first is the key press event, the second the key release event. This imitates a key that is clicked.

void KeyEmitter::emitKey(Qt::Key key)
{
	QQuickItem* receiver = qobject_cast<QQuickItem*>(QGuiApplication::focusObject());
	if(!receiver) {
		return;
	}
	QKeyEvent pressEvent = QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier, QKeySequence(key).toString());
	QKeyEvent releaseEvent = QKeyEvent(QEvent::KeyRelease, key, Qt::NoModifier);
	QCoreApplication::sendEvent(receiver, &pressEvent);
	QCoreApplication::sendEvent(receiver, &releaseEvent);
}

This is actually the complete code that is required to send the key event. This code again has no dependency and can be easily reused.

That’s all, nothing else is required. Try the sample application.

Conclusion

When I first searched, I could not find much information on how to build a virtual keyboard in Qt. I’m not sure what the reason for this is, but this article shows that it is not difficult to do. Even more, the given solution is simple to understand, reusable, and flexible to extend.

Of course, the example is very basic, both in terms of functionality and design. But it shows the principle of how a virtual keyboard can be built. It should be easy to see how it can be extended to build a complete solution.

Please contact us in case we can support you. wisol provides programming related consulting, including Qt. We also appreciate it if you contact us in case you find any issues in the article, or simply if you find it useful.

Tags: programming