Virtual keyboard used for Qt Quick applications. Implemented as in-process keyboard (loaded as plugin into your application). Even though it is not packed with many features (handwriting, word suggestion, etc.), you may find it right fit for your project. It gives you an option to customize style, layouts, appearance behaviour and some more features. Plus it's free (MIT) and you can use it even in your commercial projects. Implemented against and works with Qt 5.12 as minimal version.
- Features
- Integration
- Customizing keyboard style
- Customizing keyboard background
- Customizing default key
- Customizing Enter key
- Customizing Backspace key
- Customizing Shift key
- Customizing Space key
- Customizing Hide key
- Customizing Symbol key
- Customizing Next Page key
- Customizing Language key
- Customizing language menu
- Customizing character preview
- Customizing alternative characters preview
- Customizing layouts
- Logging
- Inspiration
- License
Even though the OpenVirtualKeyboard is already usable, I still need to implement some features. From the top of my head, this is the todo list.
- use logging category
- load custom styles from styles directory next to plugin
- custom layouts
- load custom layouts from layouts directory next to plugin
- validate scheme of custom layouts
- language switch
- language switch disabled for user when only one layout available
- Space key should be feed with name of current layout (language) selected
- key alternatives uppercase
- disallow shift change when Qt::ImhUppercaseOnly hint is recognized
- special action on Enter key
- add default icons for enter key actions
- lazy loading vs immediate loading of keyboard (configuration parameter QT_IM_MODULE=openvirtualkeyboard:immediateLoading)
- keyboard in own top level window vs. keyboard component "injected" into applications window (configuration parameter QT_IM_MODULE=openvirtualkeyboard:ownWindow)
- show keyboard window on screen where focused TextInput window is located ?
- fix when contentItem is scrolled and and one clicks on another monitor and then into different TextField of window
- fix when focus is in text field and tab is pressed, comntentItem is not scrolled
- why keyboard in own window is not animated when first time shown (only on second monitor)
- fix position of keyboard when displayed and one clicks another window and then back onto keyboard window but into different input (animationRollout enabled)
- injected keyboard: setParentItem( focusedWindow->contentItem() )
- fix when application starts and keyboard is not loaded yet and someone clicks into TextFielkd
- focus item overlap
- make focused input component visible even if keyboard overlaps it (scroll contentItem)
- make contentItem scrolling optional (QT_IM_MODULE=openvirtualkeyboard:noContentScrolling)
- use mapToItem when handling overlap
- animated keyboard show/hide (configuration parameter QT_IM_MODULE=openvirtualkeyboard:animateRollout)
- fullscreen mode
- show embedded input field on keyboard if focused item will not fit into window (or based on aspect ratio of window)
- follow settings of focused input field (Qt::ImhHiddenText (password) etc.)
- try Drawer instead of item for keyboard panel (not neccessary)
- alternative key characters
- pressed key popup
- test pressed key popup on touch based device
- repeating press
- follow Qt::ImhNoAutoUppercase hint
- press and hold for shift lock
- clean-up default en-US layout (alternative characters, ...)
- optimizations
- allow disabling of some layout types (e.g. just use alphabet type and do not load dial, digits, ...) to optimize keyboard loading time
- do not load all 4 layout rows if layout does not specify all rows
- adapt height of keyboard based on count of keyboard rows
So far it is not feature rich as Android keyboard or original Qt virtual keyboard, but the list of features it provides may be found at least interresting :)
- works with Qt Quick based UIs (not for widget based UIs)
- support for special enter key actions (search, done, go, next, send, ...)
- shift and shift lock feature
- follows input method hints (different layouts for alphabet, dial, digits, numbers or symbols)
- key preview and key alternatives preview bubbles
- customization of style (every single key type can be customized)
- customization of layouts (add your own custom layouts or different language layouts)
- auto uppercase when new sentence starts (follows Qt::ImhNoAutoUppercase hint)
- roll out animation of keyboard panel (can be turned on/off)
- keyboard panel in own window or injected into focused application window (configurable feature)
- immediate vs. lazy loading of keyboard during application start (configurable)
- auto scrolling of window contentItem to make focused input field visible (only for injected keyboard)
- implementation is javascript free, key handling is done on C++ side and principle of Qt Quick Controls 2 is followed
- ...
OpenVirtualKeyboard is ment to be out-of-the-box solution which in its base does not require to write any additional code into target application. Therefore basic integration is just a two step process:
- deploy OpenVirtualKeyboard plugin in platforminputcontexts folder next to your application executable
├─ yourApplication(.exe)
└─ platforminputcontexts
└─ openvirtualkeyboard(.dll|.so)
- set QT_IM_MODULE environment variable like this
QT_IM_MODULE=openvirtualkeyboard
Behaviour of the keyboard can be tweaked by additional optional parameters provided as colon
separated values as part of QT_IM_MODULE environment variable. Full list of supported values
looks like this QT_IM_MODULE=openvirtualkeyboard:animateRollout:ownWindow:immediateLoading:noContentScrolling
,
but you can just use the values you want, not all of them.
When set, keyboard roll out animation will be used when show/hide happens. If not set (default), animation won't be used.
When set, keyboard will be rendered in own window and fills full width of the screen where
it is shown. Keyboard in own window always follows the screen where focused input field window
is displayed. Therefore if you have multiple screens and move focused window from one screen
to another, keyboard will render itself on that screen as well. If ownWindow
is not set (default),
keyboard will be "injected" into window where input field was focused. Injected keyboard always
follows focused window and therefore works properly also for multi-windowed applications.
Because this keyboard is implemented as in-process type of keyboard and is loaded as plugin when
application is about to start, it may slightly affect loading time of the application. You have
an option to tweak the behaviour based on your requirements. By default (immediateLoading
not set),
keyboard component is loaded when first time requested by application (input field focused). Loading
of keyboard component means loading of all QMLs which defines keyboard UI and all the layouts. So
in this case, when input field is focused for the first time, there may be a short time visible until
keyboard is loaded and displayed.
On the other hand, when immediateLoading
is set, start time of application may be affected little bit,
but keyboard is then displayed instantly when requested by application, even when it is displaying for
the first time.
Note: This has effect only when
ownWindow
is not defined.
When keyboard by its height overlaps focused text input, contentItem of the window is scrolled
so that the text input is still visible. This automatic scrolling can be disabled by setting
noContentScrolling
into list of additional parameters set to QT_IM_MODULE environment variable.
TODO document + test + add example
Style of keyboard is fully customizable, which means that you can provide your own style for every key type, keyboard background, key and key alternatives preview bubbles and layout (language) selection menu. You don't have to provide style for all of these mentioned, but if you're interested in changing style for e.g. enter button only, you just create style for that key type and the default style will be used for all the rest.
To define new style you just have to add subdirectory styles
with specific QML files next to keyboard
plugin library as following.
├─ yourApplication(.exe)
└─ platforminputcontexts
├─ openvirtualkeyboard(.dll|.so)
└─ styles
├─ Background.qml
├─ Key.qml
├─ EnterKey.qml
├─ BackspaceKey.qml
├─ ShiftKey.qml
├─ SpaceKey.qml
├─ HideKey.qml
├─ SymbolKey.qml
├─ NextPageKey.qml
├─ KeyPreview.qml
├─ KeyAlternativesPreview.qml
├─ LanguageKey.qml
└─ LanguageMenu.qml
Particular style components reference to specific parent properties which should be used in style implementation (text property for plain key style, shift state etc.). See sections below.
Example: for complete example of how to implement own style, you can inspire yourself with
example/03_custom_style/out/platforminputcontexts/styles
. Keyboard from the example looks like following.
It defines whole background of keyboard panel. Simplest style would be just colored rectangle. But image may work as well.
Style file name | Available parent properties |
---|---|
Background.qml |
none |
import QtQuick 2.12
Rectangle {
color: "#cfd2d9"
}
Defines the style for plain non special key with character (alphabet, number or symbol).
Style file name | Available parent properties |
---|---|
Key.qml |
parent.active (bool - key pressed and hovered) parent.text (string - key character) |
import QtQuick 2.12
Rectangle {
id: key
color: parent.active ? Qt.lighter( "#343434", 1.2 ) : "#343434"
anchors.fill: parent
Text {
anchors.centerIn: parent
color: "white"
text: key.parent.text
}
}
Style file name | Available parent properties |
---|---|
EnterKey.qml |
parent.active (bool - key pressed and hovered) parent.enterKeyActionEnabled (bool - key is enabled/disabled) parent.enabled/enabled (bool - same as parent.enterKeyActionEnabled) parent.enterKeyAction (int - one of Qt::EnterKeyType enum values) |
import QtQuick 2.12
Rectangle {
id: key
color: enabled ? parent.active ? Qt.darker( "#3478f2", 1.1 ) : "#3478f2"
: Qt.lighter( "#3478f2", 1.2 )
anchors.fill: parent
Text {
anchors.centerIn: parent
color: "white"
text: {
if (key.parent.enterKeyAction === Qt.EnterKeySearch)
return "Search"
else if (key.parent.enterKeyAction === Qt.EnterKeyDone)
return "Done"
else if (key.parent.enterKeyAction === Qt.EnterKeyGo)
return "Go"
else if (key.parent.enterKeyAction === Qt.EnterKeySend)
return "Send"
else if (key.parent.enterKeyAction === Qt.EnterKeyNext)
return "->"
else if (key.parent.enterKeyAction === Qt.EnterKeyPrevious)
return "<-"
else
return "Enter"
}
}
}
From your application you can provide hint about special Enter key handling by keyboard via
definition of two additional properties (enterKeyActionEnabled
and enterKeyAction
) to text
input component. Virtual keyboard will check if these properties are defined on focused text
input field and uses their values to visualise state of Enter key properly.
Example:
TextField {
property bool enterKeyActionEnabled: text.length > 0 // Enter key will be enabled/disabled
// on virtual keyboard and also Enter
// key style should properly display
// disabled state
property int enterKeyAction: Qt.EnterKeySearch // virtual keyboard's Enter key style should
// display 'Search' text or appropriate icon
}
Style for the backspace key should just display backspace icon or backspace text, no more no less.
Style file name | Available parent properties |
---|---|
BackspaceKey.qml |
parent.active (bool - key pressed and hovered) |
Style file name | Available parent properties |
---|---|
ShiftKey.qml |
parent.active (bool - key pressed and hovered) parent.enabled/enabled (bool - key is enabled/disabled) parent.shiftOn (bool - shift is active for one character input) parent.shiftLocked (bool - shift is active for multiple characters input; like caps lock) |
import QtQuick 2.12
Rectangle {
id: key
color: parent.active ? Qt.darker( "#3478f2", 1.1 ) : "#3478f2"
anchors.fill: parent
Text {
anchors.centerIn: parent
font.bold: key.parent.shiftOn
font.underline: key.parent.shiftLocked
color: "white"
text: "Shift"
}
}
Shift can be activated/deactivated by single click on shift key. By double click or press and hold, shift lock (a.k.a. caps lock)is activated/deactivated. Moreover state of the shift key is distinguished from input method hints of focused text input field.
Example:
TextField {
inputMethodHints: ... // check Qt documentation for
// Qt.ImhNoAutoUppercase
// Qt.ImhPreferUppercase
// Qt.ImhUppercaseOnly
}
Style file name | Available parent properties |
---|---|
SpaceKey.qml |
parent.active (bool - key pressed and hovered) parent.selectedLayout (string - name of selected language layout) |
import QtQuick 2.12
import QtQml 2.12
Rectangle {
id: key
color: parent.active ? Qt.lighter( "#343434", 1.2 ) : "#343434"
anchors.fill: parent
Text {
anchors.centerIn: parent
font.pixelSize: parent.height * 0.4
color: "dimgray"
text: Qt.locale( key.parent.selectedLayout ).nativeLanguageName
}
}
Style for the hide key should just display hide keyboard icon or appropriate text, no more no less.
Style file name | Available parent properties |
---|---|
HideKey.qml |
parent.active (bool - key pressed and hovered) |
Style for the symbol key, which serves to switch between alphabet and symbol keyboard layout.
Style file name | Available parent properties |
---|---|
SymbolKey.qml |
parent.active (bool - key pressed and hovered) parent.text (string - text for symbol key taken from layout definition; usualy "&123") |
Style for the next page key, which serves to switch between the pages of currently displayed layout.
Style file name | Available parent properties |
---|---|
NextPageKey.qml |
parent.active (bool - key pressed and hovered) parent.text (string - text for next page key taken from layout definition; usualy "1/2", "2/2", etc.) |
Style for the language layout selection key should just display appropriate icon or text, no more no less.
Style file name | Available parent properties |
---|---|
LanguageKey.qml |
parent.active (bool - key pressed and hovered) parent.enabled/enabled (bool - key is enabled/disabled; when there are no language layouts to select from) |
TODO describe layout types (alpha, numeric, ..) and explain json structure for each
OpenVirtualKeyboard plugin uses logging category with name 'openvirtualkeyboard'. By default logs are disabled. To enable them, just configure logging filter in your appication before you instantiate QCoreApplication class.
QLoggingCategory::setFilterRules( "openvirtualkeyboard=true" );
QGuiApplication app( argc, argv );
...
https://www.kdab.com/qt-input-method-virtual-keyboard/
https://github.com/githubuser0xFFFF/QtFreeVirtualKeyboard
Distributed under the MIT License. See LICENSE file for more information.