Newer
Older
/****************************************************************************
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
** This file is part of the Qt Virtual Keyboard module of the Qt Toolkit.
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
****************************************************************************/
#include "inputcontext.h"
#include "inputengine.h"
#include "shifthandler.h"
#include "shadowinputcontext.h"
#include "enterkeyaction.h"
bool operator==(const QInputMethodEvent::Attribute &attribute1, const QInputMethodEvent::Attribute &attribute2)
{
return attribute1.start == attribute2.start &&
attribute1.length == attribute2.length &&
attribute1.type == attribute2.type &&
attribute1.value == attribute2.value;
}
\inmodule QtVirtualKeyboard
\brief Namespace for the Qt Virtual Keyboard C++ API.
enum StateFlag {
ReselectEventState = 0x1,
InputMethodEventState = 0x2,
KeyEventState = 0x4,
InputMethodClickState = 0x8,
SyncShadowInputState = 0x10
};
Q_DECLARE_FLAGS(StateFlags, StateFlag)
QObjectPrivate(),
inputContext(0),
inputEngine(0),
shiftHandler(0),
keyboardRect(),
previewRect(),
previewVisible(false),
animating(false),
focus(false),
shift(false),
capsLock(false),
cursorPosition(0),
anchorPosition(0),
forceAnchorPosition(-1),
inputMethodHints(Qt::ImhNone),
preeditText(),
selectionControlVisible(false),
anchorRectIntersectsClipRect(false),
cursorRectIntersectsClipRect(false)
#ifdef QT_VIRTUALKEYBOARD_ARROW_KEY_NAVIGATION
, activeNavigationKeys()
#endif
{
}
InputEngine *inputEngine;
ShiftHandler *shiftHandler;
QRectF previewRect;
bool previewVisible;
bool animating;
bool focus;
bool shift;
bool capsLock;
int anchorPosition;
int forceAnchorPosition;
Qt::InputMethodHints inputMethodHints;
QString preeditText;
QList<QInputMethodEvent::Attribute> preeditTextAttributes;
bool anchorRectIntersectsClipRect;
bool cursorRectIntersectsClipRect;
#ifdef QT_VIRTUALKEYBOARD_ARROW_KEY_NAVIGATION
QSet<int> activeNavigationKeys;
#endif
QSet<quint32> activeKeys;
ShadowInputContext shadow;
Q_DECLARE_OPERATORS_FOR_FLAGS(InputContextPrivate::StateFlags)
\inqmlmodule QtQuick.VirtualKeyboard
\ingroup qtvirtualkeyboard-qml
\brief Provides access to an input context.
The InputContext can be accessed as singleton instance.
*/
/*!
\inmodule QtVirtualKeyboard
\brief Provides access to an input context.
Constructs an input context with \a parent as the platform input
InputContext::InputContext(PlatformInputContext *parent) :
QObject(*new InputContextPrivate(), parent)
d->shadow.setInputContext(this);
connect(d->inputContext, SIGNAL(focusObjectChanged()), SLOT(onInputItemChanged()));
d->inputEngine = new InputEngine(this);
d->shiftHandler = new ShiftHandler(this);
}
/*!
\internal
Destroys the input context and frees all allocated resources.
*/
if (d->shift != enable) {
d->shift = enable;
emit shiftChanged();
if (!d->capsLock)
emit uppercaseChanged();
if (d->capsLock != enable) {
d->capsLock = enable;
emit capsLockChanged();
if (!d->shift)
emit uppercaseChanged();
bool InputContext::uppercase() const
{
Q_D(const InputContext);
return d->shift || d->capsLock;
}
int InputContext::anchorPosition() const
{
Q_D(const InputContext);
return d->anchorPosition;
}
Qt::InputMethodHints InputContext::inputMethodHints() const
void InputContext::setPreeditText(const QString &text, QList<QInputMethodEvent::Attribute> attributes, int replaceFrom, int replaceLength)
// Add default attributes
if (!text.isEmpty()) {
if (!testAttribute(attributes, QInputMethodEvent::TextFormat)) {
QTextCharFormat textFormat;
textFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline);
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, text.length(), textFormat));
}
addSelectionAttribute(attributes);
sendPreedit(text, attributes, replaceFrom, replaceLength);
QList<QInputMethodEvent::Attribute> InputContext::preeditTextAttributes() const
{
Q_D(const InputContext);
return d->preeditTextAttributes;
}
QRectF InputContext::anchorRectangle() const
{
Q_D(const InputContext);
return d->anchorRectangle;
}
void InputContext::setKeyboardRectangle(QRectF rectangle)
if (d->keyboardRect != rectangle) {
d->keyboardRect = rectangle;
emit keyboardRectangleChanged();
d->inputContext->emitKeyboardRectChanged();
}
}
void InputContext::setPreviewRectangle(QRectF rectangle)
if (d->previewRect != rectangle) {
d->previewRect = rectangle;
emit previewRectangleChanged();
}
}
void InputContext::setPreviewVisible(bool visible)
if (d->previewVisible != visible) {
d->previewVisible = visible;
emit previewVisibleChanged();
}
}
VIRTUALKEYBOARD_DEBUG() << "InputContext::setAnimating():" << animating;
d->animating = animating;
emit animatingChanged();
d->inputContext->emitAnimatingChanged();
}
}
void InputContext::setLocale(const QString &locale)
Q_D(InputContext);
VIRTUALKEYBOARD_DEBUG() << "InputContext::setLocale():" << locale;
QLocale newLocale(locale);
if (newLocale != d->inputContext->locale()) {
d->inputContext->setLocale(newLocale);
d->inputContext->setInputDirection(newLocale.textDirection());
emit localeChanged();
}
}
void InputContext::updateAvailableLocales(const QStringList &availableLocales)
{
Settings *settings = Settings::instance();
if (settings)
settings->setAvailableLocales(availableLocales);
}
return d->inputContext ? d->inputContext->focusObject() : 0;
}
return d->inputEngine;
}
/*!
\qmlmethod void InputContext::hideInputPanel()
This method hides the input panel. This method should only be called
when the user initiates the hide, e.g. by pressing a dedicated button
\fn void QtVirtualKeyboard::InputContext::hideInputPanel()
This method hides the input panel. This method should only be called
when the user initiates the hide, e.g. by pressing a dedicated button
d->inputContext->hideInputPanel();
}
/*!
\qmlmethod void InputContext::sendKeyClick(int key, string text, int modifiers = 0)
Sends a key click event with the given \a key, \a text and \a modifiers to
the input item that currently has focus.
Sends a key click event with the given \a key, \a text and \a modifiers to
the input item that currently has focus.
void InputContext::sendKeyClick(int key, const QString &text, int modifiers)
if (d->focus && d->inputContext) {
QKeyEvent pressEvent(QEvent::KeyPress, key, Qt::KeyboardModifiers(modifiers), text);
QKeyEvent releaseEvent(QEvent::KeyRelease, key, Qt::KeyboardModifiers(modifiers), text);
VIRTUALKEYBOARD_DEBUG() << "InputContext::::sendKeyClick():" << key;
d->stateFlags |= InputContextPrivate::KeyEventState;
d->inputContext->sendKeyEvent(&pressEvent);
d->inputContext->sendKeyEvent(&releaseEvent);
d->stateFlags &= ~InputContextPrivate::KeyEventState;
qWarning() << "InputContext::::sendKeyClick():" << key << "no focus";
}
}
/*!
\qmlmethod void InputContext::commit()
Commits the current pre-edit text.
*/
/*!
\fn void QtVirtualKeyboard::InputContext::commit()
QString text = d->preeditText;
commit(text);
}
/*!
\qmlmethod void InputContext::commit(string text, int replaceFrom = 0, int replaceLength = 0)
Commits the final \a text to the input item and optionally
modifies the text relative to the start of the pre-edit text.
If \a replaceFrom is non-zero, the \a text replaces the
contents relative to \a replaceFrom with a length of
\a replaceLength.
Commits the final \a text to the input item and optionally
modifies the text relative to the start of the pre-edit text.
If \a replaceFrom is non-zero, the \a text replaces the
contents relative to \a replaceFrom with a length of
\a replaceLength.
void InputContext::commit(const QString &text, int replaceFrom, int replaceLength)
Q_D(InputContext);
VIRTUALKEYBOARD_DEBUG() << "InputContext::commit():" << text << replaceFrom << replaceLength;
bool preeditChanged = !d->preeditText.isEmpty();
d->preeditText.clear();
d->preeditTextAttributes.clear();
QList<QInputMethodEvent::Attribute> attributes;
addSelectionAttribute(attributes);
QInputMethodEvent inputEvent(QString(), attributes);
inputEvent.setCommitString(text, replaceFrom, replaceLength);
d->stateFlags |= InputContextPrivate::InputMethodEventState;
d->stateFlags &= ~InputContextPrivate::InputMethodEventState;
}
if (preeditChanged)
emit preeditTextChanged();
}
/*!
\qmlmethod void InputContext::clear()
\fn void QtVirtualKeyboard::InputContext::clear()
bool preeditChanged = !d->preeditText.isEmpty();
d->preeditText.clear();
d->preeditTextAttributes.clear();
QList<QInputMethodEvent::Attribute> attributes;
addSelectionAttribute(attributes);
QInputMethodEvent event(QString(), attributes);
d->stateFlags |= InputContextPrivate::InputMethodEventState;
d->stateFlags &= ~InputContextPrivate::InputMethodEventState;
}
if (preeditChanged)
emit preeditTextChanged();
}
bool InputContext::fileExists(const QUrl &fileUrl)
QString fileName;
if (fileUrl.scheme() == QLatin1String("qrc")) {
fileName = QLatin1Char(':') + fileUrl.path();
} else {
fileName = fileUrl.toLocalFile();
}
return !fileName.isEmpty() && QFile::exists(fileName);
bool InputContext::hasEnterKeyAction(QObject *item) const
{
return item != 0 && qmlAttachedPropertiesObject<EnterKeyAction>(item, false);
}
/*!
\internal
*/
void InputContext::setSelectionOnFocusObject(const QPointF &anchorPos, const QPointF &cursorPos)
{
QPlatformInputContext::setSelectionOnFocusObject(anchorPos, cursorPos);
}
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
/*!
\internal
*/
void InputContext::forceCursorPosition(int anchorPosition, int cursorPosition)
{
Q_D(InputContext);
if (!d->shadow.inputItem())
return;
if (!d->inputContext->m_visible)
return;
if (d->stateFlags.testFlag(InputContextPrivate::ReselectEventState))
return;
if (d->stateFlags.testFlag(InputContextPrivate::SyncShadowInputState))
return;
VIRTUALKEYBOARD_DEBUG() << "InputContext::forceCursorPosition():" << cursorPosition << "anchorPosition:" << anchorPosition;
if (!d->preeditText.isEmpty()) {
d->forceAnchorPosition = -1;
d->forceCursorPosition = cursorPosition;
if (cursorPosition > d->cursorPosition)
d->forceCursorPosition += d->preeditText.length();
d->inputEngine->update();
} else {
d->forceAnchorPosition = anchorPosition;
d->forceCursorPosition = cursorPosition;
setPreeditText("");
if (!d->inputMethodHints.testFlag(Qt::ImhNoPredictiveText) &&
cursorPosition > 0 && d->selectedText.isEmpty()) {
d->stateFlags |= InputContextPrivate::ReselectEventState;
if (d->inputEngine->reselect(cursorPosition, InputEngine::WordAtCursor))
d->stateFlags |= InputContextPrivate::InputMethodClickState;
d->stateFlags &= ~InputContextPrivate::ReselectEventState;
}
}
}
bool InputContext::anchorRectIntersectsClipRect() const
{
Q_D(const InputContext);
return d->anchorRectIntersectsClipRect;
}
bool InputContext::cursorRectIntersectsClipRect() const
{
Q_D(const InputContext);
return d->cursorRectIntersectsClipRect;
}
bool InputContext::selectionControlVisible() const
{
Q_D(const InputContext);
return d->selectionControlVisible;
}
ShadowInputContext *InputContext::shadow() const
{
Q_D(const InputContext);
return const_cast<ShadowInputContext *>(&d->shadow);
}
if (!inputItem() && !d->activeKeys.isEmpty()) {
// After losing keyboard focus it is impossible to track pressed keys
d->activeKeys.clear();
d->stateFlags &= ~InputContextPrivate::KeyEventState;
d->stateFlags &= ~InputContextPrivate::InputMethodClickState;
emit inputItemChanged();
VIRTUALKEYBOARD_DEBUG() << "InputContext::setFocus():" << enable;
d->focus = enable;
emit focusChanged();
}
emit focusEditorChanged();
}
void InputContext::sendPreedit(const QString &text, const QList<QInputMethodEvent::Attribute> &attributes, int replaceFrom, int replaceLength)
Q_D(InputContext);
VIRTUALKEYBOARD_DEBUG() << "InputContext::sendPreedit():" << text << replaceFrom << replaceLength;
bool textChanged = d->preeditText != text;
bool attributesChanged = d->preeditTextAttributes != attributes;
if (textChanged || attributesChanged) {
d->preeditText = text;
d->preeditTextAttributes = attributes;
if (d->inputContext) {
QInputMethodEvent event(text, attributes);
const bool replace = replaceFrom != 0 || replaceLength > 0;
if (replace)
event.setCommitString(QString(), replaceFrom, replaceLength);
d->stateFlags |= InputContextPrivate::InputMethodEventState;
d->inputContext->sendEvent(&event);
d->stateFlags &= ~InputContextPrivate::InputMethodEventState;
// Send also to shadow input if only attributes changed.
// In this case the update() may not be called, so the shadow
// input may be out of sync.
if (d->shadow.inputItem() && !replace && !text.isEmpty() &&
!textChanged && attributesChanged) {
VIRTUALKEYBOARD_DEBUG() << "InputContext::sendPreedit(shadow):" << text << replaceFrom << replaceLength;
event.setAccepted(true);
QGuiApplication::sendEvent(d->shadow.inputItem(), &event);
}
if (textChanged)
emit preeditTextChanged();
if (d->preeditText.isEmpty())
d->preeditTextAttributes.clear();
void InputContext::update(Qt::InputMethodQueries queries)
// No need to fetch input clip rectangle during animation
if (!(queries & ~Qt::ImInputItemClipRectangle) && d->animating)
return;
QInputMethodQueryEvent imQueryEvent(Qt::InputMethodQueries(Qt::ImHints |
Qt::ImQueryInput | Qt::ImInputItemClipRectangle));
d->inputContext->sendEvent(&imQueryEvent);
Qt::InputMethodHints inputMethodHints = Qt::InputMethodHints(imQueryEvent.value(Qt::ImHints).toInt());
const int cursorPosition = imQueryEvent.value(Qt::ImCursorPosition).toInt();
const int anchorPosition = imQueryEvent.value(Qt::ImAnchorPosition).toInt();
QRectF anchorRectangle;
QRectF cursorRectangle;
if (const QGuiApplication *app = qApp) {
anchorRectangle = app->inputMethod()->anchorRectangle();
cursorRectangle = app->inputMethod()->cursorRectangle();
} else {
anchorRectangle = d->anchorRectangle;
cursorRectangle = d->cursorRectangle;
}
QString surroundingText = imQueryEvent.value(Qt::ImSurroundingText).toString();
QString selectedText = imQueryEvent.value(Qt::ImCurrentSelection).toString();
// check against changes
bool newInputMethodHints = inputMethodHints != d->inputMethodHints;
bool newSurroundingText = surroundingText != d->surroundingText;
bool newSelectedText = selectedText != d->selectedText;
bool newAnchorPosition = anchorPosition != d->anchorPosition;
bool newCursorPosition = cursorPosition != d->cursorPosition;
bool newAnchorRectangle = anchorRectangle != d->anchorRectangle;
bool newCursorRectangle = cursorRectangle != d->cursorRectangle;
bool selectionControlVisible = d->inputContext->isInputPanelVisible() && (cursorPosition != anchorPosition) && !inputMethodHints.testFlag(Qt::ImhNoTextHandles);
bool newSelectionControlVisible = selectionControlVisible != d->selectionControlVisible;
QRectF inputItemClipRect = imQueryEvent.value(Qt::ImInputItemClipRectangle).toRectF();
QRectF anchorRect = imQueryEvent.value(Qt::ImAnchorRectangle).toRectF();
QRectF cursorRect = imQueryEvent.value(Qt::ImCursorRectangle).toRectF();
bool anchorRectIntersectsClipRect = inputItemClipRect.intersects(anchorRect);
bool newAnchorRectIntersectsClipRect = anchorRectIntersectsClipRect != d->anchorRectIntersectsClipRect;
bool cursorRectIntersectsClipRect = inputItemClipRect.intersects(cursorRect);
bool newCursorRectIntersectsClipRect = cursorRectIntersectsClipRect != d->cursorRectIntersectsClipRect;
// update
d->inputMethodHints = inputMethodHints;
d->surroundingText = surroundingText;
d->selectedText = selectedText;
d->anchorPosition = anchorPosition;
d->anchorRectangle = anchorRectangle;
d->selectionControlVisible = selectionControlVisible;
d->anchorRectIntersectsClipRect = anchorRectIntersectsClipRect;
d->cursorRectIntersectsClipRect = cursorRectIntersectsClipRect;
if ((newSurroundingText || newCursorPosition) &&
!d->stateFlags.testFlag(InputContextPrivate::InputMethodEventState)) {
d->inputEngine->update();
}
if (newInputMethodHints) {
d->inputEngine->reset();
}
// notify
if (newInputMethodHints) {
emit inputMethodHintsChanged();
}
if (newSurroundingText) {
emit surroundingTextChanged();
}
if (newAnchorPosition) {
emit anchorPositionChanged();
}
if (newCursorPosition) {
emit cursorPositionChanged();
}
if (newAnchorRectangle) {
emit anchorRectangleChanged();
}
if (newCursorRectangle) {
emit cursorRectangleChanged();
}
if (newSelectionControlVisible) {
emit selectionControlVisibleChanged();
}
if (newAnchorRectIntersectsClipRect) {
emit anchorRectIntersectsClipRectChanged();
}
if (newCursorRectIntersectsClipRect) {
emit cursorRectIntersectsClipRectChanged();
}
// word reselection
if (newInputMethodHints || newSurroundingText || newSelectedText)
d->stateFlags &= ~InputContextPrivate::InputMethodClickState;
if ((newSurroundingText || newCursorPosition) && !newSelectedText && (int)d->stateFlags == 0 &&
!d->inputMethodHints.testFlag(Qt::ImhNoPredictiveText) &&
d->cursorPosition > 0 && d->selectedText.isEmpty()) {
d->stateFlags |= InputContextPrivate::ReselectEventState;
if (d->inputEngine->reselect(d->cursorPosition, InputEngine::WordAtCursor))
d->stateFlags |= InputContextPrivate::InputMethodClickState;
d->stateFlags &= ~InputContextPrivate::ReselectEventState;
if (!d->stateFlags.testFlag(InputContextPrivate::SyncShadowInputState)) {
d->stateFlags |= InputContextPrivate::SyncShadowInputState;
d->shadow.update(queries);
d->stateFlags &= ~InputContextPrivate::SyncShadowInputState;
}
void InputContext::invokeAction(QInputMethod::Action action, int cursorPosition)
switch (action) {
case QInputMethod::Click:
if ((int)d->stateFlags == 0) {
bool reselect = !d->inputMethodHints.testFlag(Qt::ImhNoPredictiveText) && d->selectedText.isEmpty() && cursorPosition < d->preeditText.length();
if (reselect) {
d->stateFlags |= InputContextPrivate::ReselectEventState;
d->forceCursorPosition = d->cursorPosition + cursorPosition;
d->inputEngine->update();
d->inputEngine->reselect(d->cursorPosition, InputEngine::WordBeforeCursor);
d->stateFlags &= ~InputContextPrivate::ReselectEventState;
} else if (!d->preeditText.isEmpty() && cursorPosition == d->preeditText.length()) {
d->inputEngine->update();
}
}
d->stateFlags &= ~InputContextPrivate::InputMethodClickState;
break;
case QInputMethod::ContextMenu:
break;
}
bool InputContext::filterEvent(const QEvent *event)
QEvent::Type type = event->type();
if (type == QEvent::KeyPress || type == QEvent::KeyRelease) {
const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event);
// Keep track of pressed keys update key event state
if (type == QEvent::KeyPress)
d->activeKeys += keyEvent->nativeScanCode();
else if (type == QEvent::KeyRelease)
d->activeKeys -= keyEvent->nativeScanCode();
d->stateFlags &= ~InputContextPrivate::KeyEventState;
d->stateFlags |= InputContextPrivate::KeyEventState;
#ifdef QT_VIRTUALKEYBOARD_ARROW_KEY_NAVIGATION
int key = keyEvent->key();
if ((key >= Qt::Key_Left && key <= Qt::Key_Down) || key == Qt::Key_Return) {
if (type == QEvent::KeyPress && d->inputContext->isInputPanelVisible()) {
d->activeNavigationKeys += key;
emit navigationKeyPressed(key, keyEvent->isAutoRepeat());
return true;
} else if (type == QEvent::KeyRelease && d->activeNavigationKeys.contains(key)) {
d->activeNavigationKeys -= key;
emit navigationKeyReleased(key, keyEvent->isAutoRepeat());
return true;
}
}
#endif
// Break composing text since the virtual keyboard does not support hard keyboard events
if (!d->preeditText.isEmpty())
d->inputEngine->update();
}
void InputContext::addSelectionAttribute(QList<QInputMethodEvent::Attribute> &attributes)
{
Q_D(InputContext);
if (!testAttribute(attributes, QInputMethodEvent::Selection) && d->forceCursorPosition != -1) {
if (d->forceAnchorPosition != -1)
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, d->forceAnchorPosition, d->forceCursorPosition - d->forceAnchorPosition, QVariant()));
else
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, d->forceCursorPosition, 0, QVariant()));
}
d->forceAnchorPosition = -1;
d->forceCursorPosition = -1;
}
bool InputContext::testAttribute(const QList<QInputMethodEvent::Attribute> &attributes, QInputMethodEvent::AttributeType attributeType) const
{
for (const QInputMethodEvent::Attribute &attribute : qAsConst(attributes)) {
if (attribute.type == attributeType)
return true;
}
return false;
}
/*!
\qmlproperty bool InputContext::focus
This property is changed when the input method receives or loses focus.
*/
/*!
\brief the focus status.
This property is changed when the input method receives or loses focus.
*/
/*!
\qmlproperty bool InputContext::shift
This property is changed when the shift status changes.
*/
/*!
\brief the shift status.
This property is changed when the shift status changes.
*/
/*!
\qmlproperty bool InputContext::capsLock
This property is changed when the caps lock status changes.
*/
/*!
\property QtVirtualKeyboard::InputContext::capsLock
\brief the caps lock status.
This property is changed when the caps lock status changes.
*/
/*!
\qmlproperty bool InputContext::uppercase
\since QtQuick.VirtualKeyboard 2.2
This property is \c true when either \l shift or \l capsLock is \c true.
*/
/*!
\property QtVirtualKeyboard::InputContext::uppercase
\brief the uppercase status.
This property is \c true when either \l shift or \l capsLock is \c true.
*/
/*!
\qmlproperty int InputContext::anchorPosition
\since QtQuick.VirtualKeyboard 2.2
This property is changed when the anchor position changes.
*/
/*!
\property QtVirtualKeyboard::InputContext::anchorPosition
\brief the anchor position.
This property is changed when the anchor position changes.
*/
/*!
\qmlproperty int InputContext::cursorPosition
This property is changed when the cursor position changes.
*/
/*!
\property QtVirtualKeyboard::InputContext::cursorPosition