diff options
author | Jan Arne Petersen <jan.petersen@kdab.com> | 2016-04-06 20:44:44 +0200 |
---|---|---|
committer | Jan Arne Petersen <jan.petersen@kdab.com> | 2016-04-18 14:38:03 +0000 |
commit | f4b7f65cb1a37c999dc152c50f04b1fe2829752e (patch) | |
tree | 353a8c614f15fc6e36f7bcc5b303edbb9130fdd0 /src/compositor/extensions/qwaylandtextinput.cpp | |
parent | 99ce12ed9ed00846387e7b3ab3d0ba8a1d7c94e3 (diff) |
Set state to expected state inside compositor
Some input methods like qtvirtualkeyboard expect to receive all updates
to surrounding text, cursor position, etc before processing of the
QInputMethodEvent is done. Else they assume the updates are happended because
of some external input and reset all internal state regarding the input.
Since we send the text events first to the client before we get status updates
back from the client, the status of the virtual keyboard gets
constantly reset.
To work around this issue, we already update the state in the compositor
while processing QInputMethodEvents to the state we expect to get sent
later from the clients. As long as there is no difference between the
state we expect the client will have and the precalculated state there
will be no status updates sent to the qtvirtualkeyboard outside of processing
QInputMethodEvents.
Change-Id: Ife1b541510d754657fc18281a8d765ea97935fcc
Reviewed-by: Giulio Camuffo <giulio.camuffo@kdab.com>
Diffstat (limited to 'src/compositor/extensions/qwaylandtextinput.cpp')
-rw-r--r-- | src/compositor/extensions/qwaylandtextinput.cpp | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/src/compositor/extensions/qwaylandtextinput.cpp b/src/compositor/extensions/qwaylandtextinput.cpp index 31166ddb2..2d317dcb0 100644 --- a/src/compositor/extensions/qwaylandtextinput.cpp +++ b/src/compositor/extensions/qwaylandtextinput.cpp @@ -134,10 +134,26 @@ QWaylandTextInputPrivate::QWaylandTextInputPrivate(QWaylandCompositor *composito void QWaylandTextInputPrivate::sendInputMethodEvent(QInputMethodEvent *event) { + Q_Q(QWaylandTextInput); + if (!focusResource || !focusResource->handle) return; + QWaylandTextInputClientState afterCommit; + + afterCommit.surroundingText = currentState->surroundingText; + afterCommit.cursorPosition = qMin(currentState->cursorPosition, currentState->anchorPosition); + + // Remove selection + afterCommit.surroundingText.remove(afterCommit.cursorPosition, qAbs(currentState->cursorPosition - currentState->anchorPosition)); + if (event->replacementLength() > 0 || event->replacementStart() != 0) { + // Remove replacement + afterCommit.cursorPosition = qBound(0, afterCommit.cursorPosition + event->replacementStart(), afterCommit.surroundingText.length()); + afterCommit.surroundingText.remove(afterCommit.cursorPosition, + qMin(event->replacementLength(), + afterCommit.surroundingText.length() - afterCommit.cursorPosition)); + if (event->replacementStart() <= 0 && (event->replacementLength() >= -event->replacementStart())) { const int selectionStart = qMin(currentState->cursorPosition, currentState->anchorPosition); const int selectionEnd = qMax(currentState->cursorPosition, currentState->anchorPosition); @@ -149,20 +165,21 @@ void QWaylandTextInputPrivate::sendInputMethodEvent(QInputMethodEvent *event) qWarning() << "Not yet supported case of replacement. Start:" << event->replacementStart() << "length:" << event->replacementLength(); } } + + // Insert commit string + afterCommit.surroundingText.insert(afterCommit.cursorPosition, event->commitString()); + afterCommit.cursorPosition += event->commitString().length(); + afterCommit.anchorPosition = afterCommit.cursorPosition; + foreach (const QInputMethodEvent::Attribute &attribute, event->attributes()) { if (attribute.type == QInputMethodEvent::Selection) { - const int cursorAfterCommit = qMin(currentState->cursorPosition, currentState->anchorPosition) + event->replacementStart() + event->commitString().length(); - QString textAfterCommit = currentState->surroundingText; - textAfterCommit.remove(qMin(currentState->cursorPosition, currentState->anchorPosition), - qAbs(currentState->cursorPosition - currentState->anchorPosition)); - textAfterCommit.replace(qMin(currentState->cursorPosition, currentState->anchorPosition) + event->replacementStart(), - event->replacementLength(), event->commitString()); - - int cursor = textAfterCommit.midRef(qMin(attribute.start, cursorAfterCommit), qAbs(attribute.start - cursorAfterCommit)).toUtf8().size(); - int anchor = textAfterCommit.midRef(qMin(attribute.length, cursorAfterCommit), qAbs(attribute.length - cursorAfterCommit)).toUtf8().size(); + afterCommit.cursorPosition = attribute.start; + afterCommit.anchorPosition = attribute.length; + int cursor = afterCommit.surroundingText.midRef(qMin(attribute.start, afterCommit.cursorPosition), qAbs(attribute.start - afterCommit.cursorPosition)).toUtf8().size(); + int anchor = afterCommit.surroundingText.midRef(qMin(attribute.length, afterCommit.cursorPosition), qAbs(attribute.length - afterCommit.cursorPosition)).toUtf8().size(); send_cursor_position(focusResource->handle, - attribute.start < cursorAfterCommit ? -cursor : cursor, - attribute.start < cursorAfterCommit ? -anchor : anchor); + attribute.start < afterCommit.cursorPosition ? -cursor : cursor, + attribute.length < afterCommit.cursorPosition ? -anchor : anchor); } } send_commit_string(focusResource->handle, event->commitString()); @@ -178,6 +195,17 @@ void QWaylandTextInputPrivate::sendInputMethodEvent(QInputMethodEvent *event) } } send_preedit_string(focusResource->handle, event->preeditString(), event->preeditString()); + + Qt::InputMethodQueries queries = currentState->updatedQueries(afterCommit); + currentState->surroundingText = afterCommit.surroundingText; + currentState->cursorPosition = afterCommit.cursorPosition; + currentState->anchorPosition = afterCommit.anchorPosition; + + if (queries) { + qCDebug(qLcCompositorInputMethods) << "QInputMethod::update() after QInputMethodEvent" << queries; + + emit q->updateInputMethod(queries); + } } void QWaylandTextInputPrivate::sendKeyEvent(QKeyEvent *event) |