From eed30131e168d12ed44e9ed469bef70cd4a80f4e Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Tue, 6 May 2014 18:13:45 +0200 Subject: Android: text cursor position fixes The Android input method protocol specifies that finishComposingText() should not move the cursor. Since Qt likes to move the cursor to the end of the newly committed text, we have to explicitly move the cursor to where the preedit cursor used to be. Fortunately we already keep track of that. Also implement support for the newCursorPosition argument to commitText() since the function needed to be rewritten anyway. (It was calling finishComposingText().) Task-number: QTBUG-38794 Change-Id: Iff2c43bdbd3dda812ccdc71da63f3fa730474eef Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../platforms/android/qandroidinputcontext.cpp | 55 +++++++++++++++++----- 1 file changed, 44 insertions(+), 11 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index e255a49ac7..c2e5f83639 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -591,19 +591,37 @@ jboolean QAndroidInputContext::endBatchEdit() return JNI_TRUE; } -jboolean QAndroidInputContext::commitText(const QString &text, jint /*newCursorPosition*/) +/* + Android docs say: If composing, replace compose text with \a text. + Otherwise insert \a text at current cursor position. + + The cursor should then be moved to newCursorPosition. If > 0, this is + relative to the end of the text - 1; if <= 0, this is relative to the start + of the text. updateSelection() needs to be called. +*/ +jboolean QAndroidInputContext::commitText(const QString &text, jint newCursorPosition) { - QSharedPointer query = focusObjectInputMethodQuery(); - if (query.isNull()) - return JNI_FALSE; + QInputMethodEvent event; + event.setCommitString(text); + sendInputMethodEvent(&event); + clear(); + // Qt has now put the cursor at the end of the text, corresponding to newCursorPosition == 1 + if (newCursorPosition != 1) { + QSharedPointer query = focusObjectInputMethodQuery(); + if (!query.isNull()) { + QList attributes; + const int localPos = query->value(Qt::ImCursorPosition).toInt(); + const int newLocalPos = newCursorPosition > 0 + ? localPos + newCursorPosition - 1 + : localPos - text.length() + newCursorPosition; + //move the cursor + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, + newLocalPos, 0, QVariant())); + } + } - const int cursorPos = getAbsoluteCursorPosition(query); - m_composingText = text; - m_composingTextStart = cursorPos; - m_composingCursor = cursorPos + text.length(); - finishComposingText(); - //### move cursor to newCursorPosition and call updateCursorPosition() + updateCursorPosition(); return JNI_TRUE; } @@ -624,9 +642,24 @@ jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint right return JNI_TRUE; } +// Android docs say the cursor must not move jboolean QAndroidInputContext::finishComposingText() { - QInputMethodEvent event; + QSharedPointer query = focusObjectInputMethodQuery(); + if (query.isNull()) + return JNI_FALSE; + + if (m_composingText.isEmpty()) + return JNI_TRUE; // not composing + + const int blockPos = getBlockPosition(query); + const int localCursorPos = m_composingCursor - blockPos; + + // Moving Qt's cursor to where the preedit cursor used to be + QList attributes; + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, localCursorPos, 0, QVariant())); + + QInputMethodEvent event(QString(), attributes); event.setCommitString(m_composingText); sendInputMethodEvent(&event); clear(); -- cgit v1.2.3