diff options
Diffstat (limited to 'src/virtualkeyboard/inputcontext.cpp')
-rw-r--r-- | src/virtualkeyboard/inputcontext.cpp | 154 |
1 files changed, 131 insertions, 23 deletions
diff --git a/src/virtualkeyboard/inputcontext.cpp b/src/virtualkeyboard/inputcontext.cpp index 50255e6e..d069927b 100644 --- a/src/virtualkeyboard/inputcontext.cpp +++ b/src/virtualkeyboard/inputcontext.cpp @@ -31,6 +31,7 @@ #include "inputengine.h" #include "shifthandler.h" #include "platforminputcontext.h" +#include "shadowinputcontext.h" #include "virtualkeyboarddebug.h" #include "enterkeyaction.h" #include "settings.h" @@ -70,7 +71,8 @@ public: ReselectEventState = 0x1, InputMethodEventState = 0x2, KeyEventState = 0x4, - InputMethodClickState = 0x8 + InputMethodClickState = 0x8, + SyncShadowInputState = 0x10 }; Q_DECLARE_FLAGS(StateFlags, StateFlag) @@ -87,6 +89,8 @@ public: shift(false), capsLock(false), cursorPosition(0), + anchorPosition(0), + forceAnchorPosition(-1), forceCursorPosition(-1), inputMethodHints(Qt::ImhNone), preeditText(), @@ -116,6 +120,8 @@ public: bool capsLock; StateFlags stateFlags; int cursorPosition; + int anchorPosition; + int forceAnchorPosition; int forceCursorPosition; Qt::InputMethodHints inputMethodHints; QString preeditText; @@ -131,6 +137,7 @@ public: QSet<int> activeNavigationKeys; #endif QSet<quint32> activeKeys; + ShadowInputContext shadow; }; Q_DECLARE_OPERATORS_FOR_FLAGS(InputContextPrivate::StateFlags) @@ -162,6 +169,7 @@ InputContext::InputContext(PlatformInputContext *parent) : { Q_D(InputContext); d->inputContext = parent; + d->shadow.setInputContext(this); if (d->inputContext) { d->inputContext->setInputContext(this); connect(d->inputContext, SIGNAL(focusObjectChanged()), SLOT(onInputItemChanged())); @@ -225,6 +233,12 @@ bool InputContext::uppercase() const return d->shift || d->capsLock; } +int InputContext::anchorPosition() const +{ + Q_D(const InputContext); + return d->anchorPosition; +} + int InputContext::cursorPosition() const { Q_D(const InputContext); @@ -247,29 +261,24 @@ void InputContext::setPreeditText(const QString &text, QList<QInputMethodEvent:: { // Add default attributes if (!text.isEmpty()) { - bool containsTextFormat = false; - for (QList<QInputMethodEvent::Attribute>::ConstIterator attribute = attributes.constBegin(); - attribute != attributes.constEnd(); attribute++) { - if (attribute->type == QInputMethodEvent::TextFormat) { - containsTextFormat = true; - break; - } - } - if (!containsTextFormat) { + if (!testAttribute(attributes, QInputMethodEvent::TextFormat)) { QTextCharFormat textFormat; textFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline); attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, text.length(), textFormat)); } } else { - Q_D(InputContext); - if (d->forceCursorPosition != -1) - attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, d->forceCursorPosition, 0, QVariant())); - d->forceCursorPosition = -1; + addSelectionAttribute(attributes); } sendPreedit(text, attributes, replaceFrom, replaceLength); } +QList<QInputMethodEvent::Attribute> InputContext::preeditTextAttributes() const +{ + Q_D(const InputContext); + return d->preeditTextAttributes; +} + QString InputContext::surroundingText() const { Q_D(const InputContext); @@ -491,13 +500,11 @@ void InputContext::commit(const QString &text, int replaceFrom, int replaceLengt VIRTUALKEYBOARD_DEBUG() << "InputContext::commit():" << text << replaceFrom << replaceLength; bool preeditChanged = !d->preeditText.isEmpty(); d->preeditText.clear(); + d->preeditTextAttributes.clear(); if (d->inputContext) { QList<QInputMethodEvent::Attribute> attributes; - if (d->forceCursorPosition != -1) { - attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, d->forceCursorPosition, 0, QVariant())); - d->forceCursorPosition = -1; - } + addSelectionAttribute(attributes); QInputMethodEvent inputEvent(QString(), attributes); inputEvent.setCommitString(text, replaceFrom, replaceLength); d->stateFlags |= InputContextPrivate::InputMethodEventState; @@ -524,13 +531,11 @@ void InputContext::clear() Q_D(InputContext); bool preeditChanged = !d->preeditText.isEmpty(); d->preeditText.clear(); + d->preeditTextAttributes.clear(); if (d->inputContext) { QList<QInputMethodEvent::Attribute> attributes; - if (d->forceCursorPosition != -1) { - attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, d->forceCursorPosition, 0, QVariant())); - d->forceCursorPosition = -1; - } + addSelectionAttribute(attributes); QInputMethodEvent event(QString(), attributes); d->stateFlags |= InputContextPrivate::InputMethodEventState; d->inputContext->sendEvent(&event); @@ -576,6 +581,42 @@ void InputContext::setSelectionOnFocusObject(const QPointF &anchorPos, const QPo QPlatformInputContext::setSelectionOnFocusObject(anchorPos, cursorPos); } +/*! + \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); @@ -594,6 +635,12 @@ bool InputContext::selectionControlVisible() const return d->selectionControlVisible; } +ShadowInputContext *InputContext::shadow() const +{ + Q_D(const InputContext); + return const_cast<ShadowInputContext *>(&d->shadow); +} + void InputContext::onInputItemChanged() { Q_D(InputContext); @@ -630,16 +677,30 @@ void InputContext::sendPreedit(const QString &text, const QList<QInputMethodEven if (d->inputContext) { QInputMethodEvent event(text, attributes); - if (replaceFrom != 0 || replaceLength > 0) + 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::reset() @@ -679,6 +740,7 @@ void InputContext::update(Qt::InputMethodQueries queries) 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; @@ -699,6 +761,7 @@ void InputContext::update(Qt::InputMethodQueries queries) d->inputMethodHints = inputMethodHints; d->surroundingText = surroundingText; d->selectedText = selectedText; + d->anchorPosition = anchorPosition; d->cursorPosition = cursorPosition; d->anchorRectangle = anchorRectangle; d->cursorRectangle = cursorRectangle; @@ -725,6 +788,9 @@ void InputContext::update(Qt::InputMethodQueries queries) if (newSelectedText) { emit selectedTextChanged(); } + if (newAnchorPosition) { + emit anchorPositionChanged(); + } if (newCursorPosition) { emit cursorPositionChanged(); } @@ -755,6 +821,12 @@ void InputContext::update(Qt::InputMethodQueries queries) 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) @@ -822,6 +894,28 @@ bool InputContext::filterEvent(const QEvent *event) return false; } +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 @@ -876,6 +970,20 @@ bool InputContext::filterEvent(const QEvent *event) */ /*! + \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. |