7#include <android/log.h>
14#include "private/qhighdpiscaling_p.h"
16#include <QTextBoundaryFinder>
17#include <QTextCharFormat>
18#include <QtCore/QJniEnvironment>
19#include <QtCore/QJniObject>
21#include <qguiapplication.h>
22#include <qinputmethod.h>
23#include <qsharedpointer.h>
24#if QT_CONFIG(accessibility)
25#include <qaccessible.h>
29#include <qpa/qplatformwindow.h>
33using namespace Qt::StringLiterals;
44 m_context->beginBatchEdit();
49 m_context->endBatchEdit();
52 BatchEditLock(
const BatchEditLock &) =
delete;
53 BatchEditLock &operator=(
const BatchEditLock &) =
delete;
77 QtAndroidPrivate::AndroidDeadlockProtector protector(
78 u"QAndroidInputContext::runOnQtThread()"_s);
79 if (!protector.acquire())
81 QMetaObject::invokeMethod(m_androidInputContext,
"safeCall", Qt::BlockingQueuedConnection, Q_ARG(std::function<
void()>, func));
93 if (!focusObject->property(
"inputMethodHints").isValid())
101 if (!hasValidFocusObject())
104 qCDebug(lcQpaInputMethods) <<
"@@@ BEGINBATCH";
105 jboolean res = JNI_FALSE;
112 if (!hasValidFocusObject())
115 qCDebug(lcQpaInputMethods) <<
"@@@ ENDBATCH";
117 jboolean res = JNI_FALSE;
125 if (!hasValidFocusObject())
129 const jchar *jstr = env->GetStringChars(text, &isCopy);
130 QString str(
reinterpret_cast<
const QChar *>(jstr), env->GetStringLength(text));
131 env->ReleaseStringChars(text, jstr);
133 qCDebug(lcQpaInputMethods) <<
"@@@ COMMIT len:" << str.size() << newCursorPosition;
134 jboolean res = JNI_FALSE;
141 if (!hasValidFocusObject())
144 qCDebug(lcQpaInputMethods) <<
"@@@ DELETE" << leftLength << rightLength;
145 jboolean res = JNI_FALSE;
152 if (!hasValidFocusObject())
155 qCDebug(lcQpaInputMethods) <<
"@@@ FINISH";
156 jboolean res = JNI_FALSE;
163 if (!hasValidFocusObject())
167 const jchar *jstr = env->GetStringChars(text, &isCopy);
168 QString str(
reinterpret_cast<
const QChar *>(jstr), env->GetStringLength(text));
169 env->ReleaseStringChars(text, jstr);
171 qCDebug(lcQpaInputMethods) <<
"@@@ REPLACE" << start << end <<
"len:" << str.size() << newCursorPosition;
172 jboolean res = JNI_FALSE;
193 QAndroidInputContext::ExtractedText extractedText;
194 runOnQtThread([&]{extractedText =
m_androidInputContext->getExtractedText(hintMaxChars, hintMaxLines, flags);});
196 qCDebug(lcQpaInputMethods) <<
"@@@ GETEX" << hintMaxChars << hintMaxLines << QString::fromLatin1(
"0x") + QString::number(flags,16) <<
"textLen:" << extractedText.text.size() <<
"partOff:" << extractedText.partialStartOffset << extractedText.partialEndOffset <<
"sel:" << extractedText.selectionStart << extractedText.selectionEnd <<
"offset:" << extractedText.startOffset;
198 jobject object = env->NewObject(m_extractedTextClass, m_classConstructorMethodID);
199 env->SetIntField(object, m_partialStartOffsetFieldID, extractedText.partialStartOffset);
200 env->SetIntField(object, m_partialEndOffsetFieldID, extractedText.partialEndOffset);
201 env->SetIntField(object, m_selectionStartFieldID, extractedText.selectionStart);
202 env->SetIntField(object, m_selectionEndFieldID, extractedText.selectionEnd);
203 env->SetIntField(object, m_startOffsetFieldID, extractedText.startOffset);
204 env->SetObjectField(object,
206 env->NewString(
reinterpret_cast<
const jchar *>(extractedText.text.constData()),
207 jsize(extractedText.text.length())));
219 qCDebug(lcQpaInputMethods) <<
"@@@ GETSEL len:" << text.size();
222 return env->NewString(
reinterpret_cast<
const jchar *>(text.constData()), jsize(text.length()));
232 qCDebug(lcQpaInputMethods) <<
"@@@ GETA" << length <<
"len:" << text.size();
233 return env->NewString(
reinterpret_cast<
const jchar *>(text.constData()), jsize(text.length()));
243 qCDebug(lcQpaInputMethods) <<
"@@@ GETB" << length <<
"len:" << text.size();
244 return env->NewString(
reinterpret_cast<
const jchar *>(text.constData()), jsize(text.length()));
249 if (!hasValidFocusObject())
253 const jchar *jstr = env->GetStringChars(text, &isCopy);
254 QString str(
reinterpret_cast<
const QChar *>(jstr), env->GetStringLength(text));
255 env->ReleaseStringChars(text, jstr);
257 qCDebug(lcQpaInputMethods) <<
"@@@ SET len:" << str.size() << newCursorPosition;
258 jboolean res = JNI_FALSE;
265 if (!hasValidFocusObject())
268 qCDebug(lcQpaInputMethods) <<
"@@@ SETR" << start << end;
269 jboolean res = JNI_FALSE;
277 if (!hasValidFocusObject())
280 qCDebug(lcQpaInputMethods) <<
"@@@ SETSEL" << start << end;
281 jboolean res = JNI_FALSE;
289 if (!hasValidFocusObject())
292 qCDebug(lcQpaInputMethods) <<
"@@@ SELALL";
293 jboolean res = JNI_FALSE;
300 if (!hasValidFocusObject())
303 qCDebug(lcQpaInputMethods) <<
"@@@";
304 jboolean res = JNI_FALSE;
311 if (!hasValidFocusObject())
314 qCDebug(lcQpaInputMethods) <<
"@@@";
315 jboolean res = JNI_FALSE;
322 if (!hasValidFocusObject())
325 qCDebug(lcQpaInputMethods) <<
"@@@";
326 jboolean res = JNI_FALSE;
333 if (!hasValidFocusObject())
336 qCDebug(lcQpaInputMethods) <<
"@@@ PASTE";
337 jboolean res = JNI_FALSE;
344 if (!hasValidFocusObject())
347 qCDebug(lcQpaInputMethods) <<
"@@@ UPDATECURSORPOS";
370 {
"beginBatchEdit",
"()Z", (
void *)beginBatchEdit},
371 {
"endBatchEdit",
"()Z", (
void *)endBatchEdit},
372 {
"commitText",
"(Ljava/lang/String;I)Z", (
void *)commitText},
373 {
"deleteSurroundingText",
"(II)Z", (
void *)deleteSurroundingText},
374 {
"finishComposingText",
"()Z", (
void *)finishComposingText},
375 {
"getCursorCapsMode",
"(I)I", (
void *)getCursorCapsMode},
376 {
"getExtractedText",
"(III)Lorg/qtproject/qt/android/QtExtractedText;", (
void *)getExtractedText},
377 {
"getSelectedText",
"(I)Ljava/lang/String;", (
void *)getSelectedText},
378 {
"getTextAfterCursor",
"(II)Ljava/lang/String;", (
void *)getTextAfterCursor},
379 {
"getTextBeforeCursor",
"(II)Ljava/lang/String;", (
void *)getTextBeforeCursor},
380 {
"replaceText",
"(IILjava/lang/String;I)Z", (
void *)replaceText},
381 {
"setComposingText",
"(Ljava/lang/String;I)Z", (
void *)setComposingText},
382 {
"setComposingRegion",
"(II)Z", (
void *)setComposingRegion},
383 {
"setSelection",
"(II)Z", (
void *)setSelection},
384 {
"selectAll",
"()Z", (
void *)selectAll},
385 {
"cut",
"()Z", (
void *)cut},
386 {
"copy",
"()Z", (
void *)copy},
387 {
"copyURL",
"()Z", (
void *)copyURL},
388 {
"paste",
"()Z", (
void *)paste},
389 {
"updateCursorPosition",
"()Z", (
void *)updateCursorPosition},
390 {
"reportFullscreenMode",
"(Z)V", (
void *)reportFullscreenMode},
391 {
"fullscreenMode",
"()Z", (
void *)fullscreenMode}
396 QWindow *window =
qGuiApp->focusWindow();
397 return window ? window->handle() :
nullptr;
405 const QRect windowRect = QPlatformInputContext::inputItemRectangle().toRect();
406 return QRect(window->mapToGlobal(windowRect.topLeft()), windowRect.size());
411 , m_composingTextStart(-1)
412 , m_composingCursor(-1)
414 , m_batchEditNestingLevel(0)
416 , m_fullScreenMode(
false)
420 if (Q_UNLIKELY(!clazz)) {
421 qCritical() <<
"Native registration unable to find class '"
427 if (Q_UNLIKELY(env->RegisterNatives(clazz, methods,
sizeof(
methods) /
sizeof(
methods[0])) < 0)) {
428 qCritical() <<
"RegisterNatives failed for '"
435 if (Q_UNLIKELY(!clazz)) {
436 qCritical() <<
"Native registration unable to find class '"
444 if (Q_UNLIKELY(!m_classConstructorMethodID)) {
445 qCritical(
"GetMethodID failed");
450 if (Q_UNLIKELY(!m_partialEndOffsetFieldID)) {
451 qCritical(
"Can't find field partialEndOffset");
456 if (Q_UNLIKELY(!m_partialStartOffsetFieldID)) {
457 qCritical(
"Can't find field partialStartOffset");
462 if (Q_UNLIKELY(!m_selectionEndFieldID)) {
463 qCritical(
"Can't find field selectionEnd");
468 if (Q_UNLIKELY(!m_selectionStartFieldID)) {
469 qCritical(
"Can't find field selectionStart");
474 if (Q_UNLIKELY(!m_startOffsetFieldID)) {
475 qCritical(
"Can't find field startOffset");
479 m_textFieldID = env->GetFieldID(m_extractedTextClass,
"text",
"Ljava/lang/String;");
480 if (Q_UNLIKELY(!m_textFieldID)) {
481 qCritical(
"Can't find field text");
484 qRegisterMetaType<QInputMethodEvent *>(
"QInputMethodEvent*");
485 qRegisterMetaType<QInputMethodQueryEvent *>(
"QInputMethodQueryEvent*");
488 QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged,
489 this, &QAndroidInputContext::updateSelectionHandles);
490 QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::anchorRectangleChanged,
491 this, &QAndroidInputContext::updateSelectionHandles);
492 QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::inputItemClipRectangleChanged,
this, [
this]{
493 auto im =
qGuiApp->inputMethod();
494 if (!im->inputItemClipRectangle().contains(im->anchorRectangle()) ||
495 !im->inputItemClipRectangle().contains(im->cursorRectangle())) {
496 m_handleMode = Hidden;
497 updateSelectionHandles();
500 m_hideCursorHandleTimer.setInterval(4000);
501 m_hideCursorHandleTimer.setSingleShot(
true);
502 m_hideCursorHandleTimer.setTimerType(Qt::VeryCoarseTimer);
503 connect(&m_hideCursorHandleTimer, &QTimer::timeout,
this, [
this]{
504 m_handleMode = Hidden;
529 QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
530 return absolutePos.isValid() ? absolutePos.toInt() : query->value(Qt::ImCursorPosition).toInt();
536 QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
537 return absolutePos.isValid() ? absolutePos.toInt() - query->value(Qt::ImCursorPosition).toInt() : 0;
542 focusObjectStopComposing();
544 m_batchEditNestingLevel = 0;
545 m_handleMode = Hidden;
547 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(Qt::ImEnabled);
548 if (!query.isNull() && query->value(Qt::ImEnabled).toBool()) {
554 if (!m_accessibilityFocusInProgress)
564 focusObjectStopComposing();
569 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
570 if (!query.isNull() && m_batchEditNestingLevel == 0) {
571 const int cursorPos = getAbsoluteCursorPosition(query);
572 const int composeLength = m_composingText.length();
575 if (m_composingText.isEmpty() != (m_composingTextStart == -1))
576 qWarning() <<
"Input method out of sync" << m_composingText << m_composingTextStart;
578 int realSelectionStart = cursorPos;
579 int realSelectionEnd = cursorPos;
581 int cpos = query->value(Qt::ImCursorPosition).toInt();
582 int anchor = query->value(Qt::ImAnchorPosition).toInt();
583 if (cpos != anchor) {
584 if (!m_composingText.isEmpty()) {
585 qWarning(
"Selecting text while preediting may give unpredictable results.");
586 focusObjectStopComposing();
588 int blockPos = getBlockPosition(query);
589 realSelectionStart = blockPos + cpos;
590 realSelectionEnd = blockPos + anchor;
593 if (focusObjectIsComposing())
594 realSelectionStart = realSelectionEnd = m_composingCursor;
597 if (realSelectionStart > realSelectionEnd)
598 std::swap(realSelectionStart, realSelectionEnd);
601 m_composingTextStart
, m_composingTextStart + composeLength
);
607 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
610 return query->value(Qt::ImHints).toUInt() & Qt::ImhNoEditMenu;
615 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
618 return query->value(Qt::ImHints).toUInt() & Qt::ImhNoTextHandles;
623 if (m_fullScreenMode) {
627 static bool noHandles = qEnvironmentVariableIntValue(
"QT_QPA_NO_TEXT_HANDLES");
628 if (noHandles || !m_focusObject)
632 if (!qPlatformWindow)
635 if (isImhNoTextHandlesSet()) {
640 auto im =
qGuiApp->inputMethod();
642 QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImEnabled
643 | Qt::ImCurrentSelection | Qt::ImHints | Qt::ImSurroundingText
645 QCoreApplication::sendEvent(m_focusObject, &query);
647 int cpos = query.value(Qt::ImCursorPosition).toInt();
648 int anchor = query.value(Qt::ImAnchorPosition).toInt();
649 const QVariant readOnlyVariant = query.value(Qt::ImReadOnly);
650 bool readOnly = readOnlyVariant.toBool();
652 if (!readOnly && ((m_handleMode & 0xff) == Hidden)) {
657 if ( cpos == anchor && (!readOnlyVariant.isValid() || readOnly)) {
662 if (cpos == anchor || im->anchorRectangle().isNull()) {
663 auto curRect = cursorRectangle();
664 QPoint cursorPointGlobal = QPoint(curRect.x() + (curRect.width() / 2), curRect.y() + curRect.height());
665 QPoint cursorPoint(curRect.center().x(), curRect.bottom());
670 if (cursorPointGlobal != cursorPoint) {
671 x = cursorPointGlobal.x();
672 y = cursorPointGlobal.y();
675 QPoint editMenuPoint(x, y);
676 m_handleMode &= ShowEditPopup;
677 m_handleMode |= ShowCursor;
678 uint32_t buttons = 0;
679 const bool withEditMenu = !isImhNoEditMenuSet();
682 if (!query.value(Qt::ImSurroundingText).toString().isEmpty())
685 QtAndroidInput::updateHandles(m_handleMode, editMenuPoint, buttons, cursorPointGlobal);
686 m_hideCursorHandleTimer.start();
691 m_handleMode = ShowSelection | ShowEditPopup ;
692 auto leftRect = cursorRectangle();
693 auto rightRect = anchorRectangle();
695 std::swap(leftRect, rightRect);
699 QPoint leftPoint(qPlatformWindow->mapToGlobal(leftRect.bottomLeft().toPoint()));
700 QPoint rightPoint(qPlatformWindow->mapToGlobal(rightRect.bottomRight().toPoint()));
703 if (platformIntegration) {
707 int rightSideOfScreen = platformIntegration
->screen()->availableGeometry().right();
710 leftPoint = qPlatformWindow->mapFromGlobal(leftPoint);
714 rightPoint = qPlatformWindow->mapFromGlobal(rightPoint);
716 QPoint editPoint(leftRect.united(rightRect).topLeft().toPoint());
717 uint32_t buttons = 0;
718 const bool withEditMenu = !isImhNoEditMenuSet();
724 QtAndroidInput::updateHandles(m_handleMode, editPoint, buttons, leftPoint, rightPoint,
725 query.value(Qt::ImCurrentSelection).toString().isRightToLeft());
726 m_hideCursorHandleTimer.stop();
731
732
733
734
737 if (m_batchEditNestingLevel != 0) {
738 qWarning() <<
"QAndroidInputContext::handleLocationChanged returned";
744 QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition
745 | Qt::ImAbsolutePosition | Qt::ImCurrentSelection);
746 QCoreApplication::sendEvent(m_focusObject, &query);
747 int cpos = query.value(Qt::ImCursorPosition).toInt();
748 int anchor = query.value(Qt::ImAnchorPosition).toInt();
749 auto leftRect = cursorRectangle();
750 auto rightRect = anchorRectangle();
752 std::swap(leftRect, rightRect);
755 if (handleId == 2 && point.y() > rightRect.center().y()) {
756 point.setY(rightRect.center().y());
757 }
else if (handleId == 3 && point.y() < leftRect.center().y()) {
758 point.setY(leftRect.center().y());
762 auto object = m_focusObject->parent();
765 if (QString::compare(object->metaObject()->className(),
766 "QDialog", Qt::CaseInsensitive) == 0) {
767 dialogMoveX += object->property(
"x").toInt();
769 object = object->parent();
773 QPointF(QHighDpi::fromNativePixels(point, QGuiApplication::focusWindow()));
774 const QPointF fixedPosition = QPointF(position.x() - dialogMoveX, position.y());
775 const QInputMethod *im = QGuiApplication::inputMethod();
776 const QTransform mapToLocal = im->inputItemTransform().inverted();
777 const int handlePos = im->queryFocusObject(Qt::ImCursorPosition, mapToLocal.map(fixedPosition)).toInt(&ok);
783 int newAnchor = anchor;
784 if (newAnchor > newCpos)
785 std::swap(newAnchor, newCpos);
789 newAnchor = handlePos;
790 }
else if (handleId == 2) {
791 newAnchor = handlePos;
792 }
else if (handleId == 3) {
797
798
799
800
801 if ((handleId == 2 || handleId == 3) && newCpos <= newAnchor) {
802 QTextBoundaryFinder finder(QTextBoundaryFinder::Grapheme,
803 query.value(Qt::ImCurrentSelection).toString());
805 const int oldSelectionStartPos = qMin(cpos, anchor);
809 finder.toPreviousBoundary();
810 newAnchor = finder.position() + oldSelectionStartPos;
813 finder.toNextBoundary();
814 newCpos = finder.position() + oldSelectionStartPos;
819 if (!focusObjectIsComposing() && newCpos == cpos && newAnchor == anchor)
823
824
825
826
827 if (focusObjectIsComposing() && handleId == 1) {
828 int absoluteCpos = query.value(Qt::ImAbsolutePosition).toInt(&ok);
831 const int blockPos = absoluteCpos - cpos;
833 if (blockPos + newCpos == m_composingCursor)
837 BatchEditLock batchEditLock(
this);
839 focusObjectStopComposing();
841 QList<QInputMethodEvent::Attribute> attributes;
842 attributes.append({ QInputMethodEvent::Selection, newAnchor, newCpos - newAnchor });
843 if (newCpos != newAnchor)
844 attributes.append({ QInputMethodEvent::Cursor, 0, 0 });
847 QGuiApplication::sendEvent(m_focusObject, &event);
853 if (window && m_focusObject && screenInputItemRectangle().contains(x, y)) {
855 m_handleMode = ShowCursor;
857 m_hideCursorHandleTimer.stop();
859 if (focusObjectIsComposing()) {
860 const int curBlockPos = getBlockPosition(
861 focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImAbsolutePosition));
862 const int touchPosition = curBlockPos
863 + queryFocusObject(Qt::ImCursorPosition, QPointF(x, y)).toInt();
864 if (touchPosition != m_composingCursor)
865 focusObjectStopComposing();
869 const QRectF curRect = cursorRectangle();
870 const QPoint cursorGlobalPoint = window->mapToGlobal(QPoint(curRect.x(), curRect.y()));
871 const QRect windowRect = QPlatformInputContext::inputItemClipRectangle().toRect();
872 const QRect windowGlobalRect = QRect(window->mapToGlobal(windowRect.topLeft()), windowRect.size());
874 if (windowGlobalRect.contains(cursorGlobalPoint.x(), cursorGlobalPoint.y()))
881 static bool noHandles = qEnvironmentVariableIntValue(
"QT_QPA_NO_TEXT_HANDLES");
885 if (m_focusObject && screenInputItemRectangle().contains(x, y)) {
886 BatchEditLock batchEditLock(
this);
888 focusObjectStopComposing();
889 const QPointF touchPoint(x, y);
890 setSelectionOnFocusObject(touchPoint, touchPoint);
892 QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImTextBeforeCursor | Qt::ImTextAfterCursor);
893 QCoreApplication::sendEvent(m_focusObject, &query);
894 int cursor = query.value(Qt::ImCursorPosition).toInt();
896 QString before = query.value(Qt::ImTextBeforeCursor).toString();
897 QString after = query.value(Qt::ImTextAfterCursor).toString();
898 for (
const auto &ch : after) {
899 if (!ch.isLetterOrNumber())
904 for (
auto itch = before.rbegin(); itch != before.rend(); ++itch) {
905 if (!itch->isLetterOrNumber())
909 if (cursor == anchor || cursor < 0 || cursor - anchor > 500) {
910 m_handleMode = ShowCursor | ShowEditPopup;
914 QList<QInputMethodEvent::Attribute> imAttributes;
915 imAttributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 0, QVariant()));
916 imAttributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, anchor, cursor - anchor, QVariant()));
918 QGuiApplication::sendEvent(m_focusObject, &event);
920 m_handleMode = ShowSelection | ShowEditPopup;
929 m_handleMode = Hidden;
936 if (m_handleMode & ShowSelection) {
937 m_handleMode = Hidden;
940 m_hideCursorHandleTimer.start();
946 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(queries);
949#if QT_CONFIG(accessibility)
954 if (queries & Qt::ImSurroundingText) {
955 if (m_batchEditNestingLevel == 0)
956 notifyTextChangedForAccessibility();
957 else if (QAccessible::isActive())
958 m_a11yTextEditPending =
true;
961#warning TODO extract the needed data from query
966#warning TODO Handle at least QInputMethod::ContextMenu action
968 Q_UNUSED(cursorPosition);
976 return QtAndroidInput::softwareKeyboardRect();
986 if (QGuiApplication::applicationState() != Qt::ApplicationActive) {
987 connect(
qGuiApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
this, SLOT(showInputPanelLater(Qt::ApplicationState)));
994 if (m_accessibilityFocusInProgress)
997 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1004 disconnect(m_updateCursorPosConnection);
1005 m_updateCursorPosConnection = {};
1007 if (
qGuiApp->focusObject()->metaObject()->indexOfSignal(
"cursorPositionChanged(int,int)") >= 0)
1008 m_updateCursorPosConnection = connect(
qGuiApp->focusObject(), SIGNAL(cursorPositionChanged(
int,
int)),
this, SLOT(updateCursorPosition()));
1009 else if (
qGuiApp->focusObject()->metaObject()->indexOfSignal(
"cursorPositionChanged()") >= 0)
1010 m_updateCursorPosConnection = connect(
qGuiApp->focusObject(), SIGNAL(cursorPositionChanged()),
this, SLOT(updateCursorPosition()));
1012 QRect rect = QPlatformInputContext::inputItemRectangle().toRect();
1014 query->value(Qt::ImHints).toUInt()
,
1015 query->value(Qt::ImEnterKeyType).toUInt()
);
1020 if (state != Qt::ApplicationActive)
1022 disconnect(
qGuiApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
this, SLOT(showInputPanelLater(Qt::ApplicationState)));
1028 if (
qGuiApp->thread() == QThread::currentThread())
1031 QMetaObject::invokeMethod(
this,
"safeCall", conType, Q_ARG(std::function<
void()>, func));
1046 return m_composingText.length();
1051 m_composingText.clear();
1052 m_composingTextStart = -1;
1053 m_composingCursor = -1;
1054 m_extractedText.clear();
1060 return m_focusObject;
1065 if (object != m_focusObject) {
1066 focusObjectStopComposing();
1067 m_focusObject = object;
1069#if QT_CONFIG(accessibility)
1077 m_a11yTextEditPending =
false;
1078 m_a11yLastText.clear();
1079 m_a11yBaselineValid =
false;
1080 if (m_focusObject && QAccessible::isActive()) {
1081 QInputMethodQueryEvent query(Qt::ImSurroundingText);
1082 QCoreApplication::sendEvent(m_focusObject, &query);
1083 const QVariant surroundingText = query.value(Qt::ImSurroundingText);
1084 if (surroundingText.isValid()) {
1085 m_a11yLastText = surroundingText.toString();
1086 m_a11yBaselineValid =
true;
1094#if QT_CONFIG(accessibility)
1095void QAndroidInputContext::markTextEditForAccessibility()
1097 if (!QAccessible::isActive() || !m_focusObject)
1099 m_a11yTextEditPending =
true;
1104 if (!m_a11yBaselineValid) {
1105 QInputMethodQueryEvent query(Qt::ImSurroundingText);
1106 QCoreApplication::sendEvent(m_focusObject, &query);
1107 m_a11yLastText = query.value(Qt::ImSurroundingText).toString();
1108 m_a11yBaselineValid =
true;
1112void QAndroidInputContext::notifyTextChangedForAccessibility()
1114 if (!QAccessible::isActive() || !m_focusObject)
1117 QInputMethodQueryEvent query(Qt::ImSurroundingText);
1118 QCoreApplication::sendEvent(m_focusObject, &query);
1119 const QString after = query.value(Qt::ImSurroundingText).toString();
1120 if (!m_a11yBaselineValid) {
1123 m_a11yLastText = after;
1124 m_a11yBaselineValid =
true;
1127 const QString before = m_a11yLastText;
1128 if (after == before)
1130 m_a11yLastText = after;
1135 const int minLen = qMin(before.size(), after.size());
1137 while (prefix < minLen && before.at(prefix) == after.at(prefix))
1141 if (prefix > 0 && before.at(prefix - 1).isHighSurrogate())
1144 while (suffix < minLen - prefix
1145 && before.at(before.size() - 1 - suffix) == after.at(after.size() - 1 - suffix))
1147 if (suffix > 0 && before.at(before.size() - suffix).isLowSurrogate())
1149 const int removedCount =
int(before.size()) - prefix - suffix;
1150 const int addedCount =
int(after.size()) - prefix - suffix;
1155 if (QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(m_focusObject))
1156 focusUid = QAccessible::uniqueId(iface);
1158 QtAndroid::notifyTextChanged(focusUid, after, before, prefix, addedCount, removedCount);
1164 ++m_batchEditNestingLevel;
1170 if (--m_batchEditNestingLevel == 0) {
1171 focusObjectStartComposing();
1173#if QT_CONFIG(accessibility)
1181 if (m_a11yTextEditPending) {
1182 m_a11yTextEditPending =
false;
1183 notifyTextChangedForAccessibility();
1191
1192
1193
1196 BatchEditLock batchEditLock(
this);
1197 return setComposingText(text, newCursorPosition) && finishComposingText();
1202 BatchEditLock batchEditLock(
this);
1203#if QT_CONFIG(accessibility)
1204 markTextEditForAccessibility();
1207 focusObjectStopComposing();
1209 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1213 if (leftLength < 0) {
1214 rightLength += -leftLength;
1218 const int initialBlockPos = getBlockPosition(query);
1219 const int initialCursorPos = getAbsoluteCursorPosition(query);
1220 const int initialAnchorPos = initialBlockPos + query->value(Qt::ImAnchorPosition).toInt();
1223
1224
1225
1226
1227
1228
1229
1230
1232 m_composingText.isEmpty()
1233 ? qMin(initialCursorPos, initialAnchorPos)
1234 : qMin(qMin(initialCursorPos, initialAnchorPos), m_composingTextStart);
1236 const int rightBegin =
1237 m_composingText.isEmpty()
1238 ? qMax(initialCursorPos, initialAnchorPos)
1239 : qMax(qMax(initialCursorPos, initialAnchorPos),
1240 m_composingTextStart + m_composingText.length());
1242 int textBeforeCursorLen;
1243 int textAfterCursorLen;
1245 QVariant textBeforeCursor = query->value(Qt::ImTextBeforeCursor);
1246 QVariant textAfterCursor = query->value(Qt::ImTextAfterCursor);
1247 if (textBeforeCursor.isValid() && textAfterCursor.isValid()) {
1248 textBeforeCursorLen = textBeforeCursor.toString().length();
1249 textAfterCursorLen = textAfterCursor.toString().length();
1251 textBeforeCursorLen = initialCursorPos - initialBlockPos;
1252 textAfterCursorLen =
1253 query->value(Qt::ImSurroundingText).toString().length() - textBeforeCursorLen;
1256 leftLength = qMin(qMax(0, textBeforeCursorLen - (initialCursorPos - leftEnd)), leftLength);
1257 rightLength = qMin(qMax(0, textAfterCursorLen - (rightBegin - initialCursorPos)), rightLength);
1259 if (leftLength == 0 && rightLength == 0)
1262 if (leftEnd == rightBegin) {
1265 event.setCommitString({}, -leftLength, leftLength + rightLength);
1266 QGuiApplication::sendEvent(m_focusObject, &event);
1268 if (initialCursorPos != initialAnchorPos) {
1270 { QInputMethodEvent::Selection, initialCursorPos - initialBlockPos, 0 }
1273 QGuiApplication::sendEvent(m_focusObject, &event);
1276 int currentCursorPos = initialCursorPos;
1278 if (rightLength > 0) {
1280 event.setCommitString({}, rightBegin - currentCursorPos, rightLength);
1281 QGuiApplication::sendEvent(m_focusObject, &event);
1283 currentCursorPos = rightBegin;
1286 if (leftLength > 0) {
1287 const int leftBegin = leftEnd - leftLength;
1290 event.setCommitString({}, leftBegin - currentCursorPos, leftLength);
1291 QGuiApplication::sendEvent(m_focusObject, &event);
1293 currentCursorPos = leftBegin;
1295 if (!m_composingText.isEmpty())
1296 m_composingTextStart -= leftLength;
1300 if (currentCursorPos != initialCursorPos - leftLength
1301 || initialCursorPos != initialAnchorPos) {
1303 const int currentBlockPos = getBlockPosition(
1304 focusObjectInputMethodQuery(Qt::ImAbsolutePosition | Qt::ImCursorPosition));
1307 { QInputMethodEvent::Selection, initialCursorPos - leftLength - currentBlockPos,
1308 initialAnchorPos - initialCursorPos },
1309 { QInputMethodEvent::Cursor, 0, 0 }
1312 QGuiApplication::sendEvent(m_focusObject, &event);
1322 BatchEditLock batchEditLock(
this);
1324 if (!focusObjectStopComposing())
1332
1333
1334
1335
1338 if (!finishComposingText())
1340 if (!setSelection(start, end))
1343 return commitText(text, newCursorPosition);
1348 m_fullScreenMode = enabled;
1349 BatchEditLock batchEditLock(
this);
1350 if (!focusObjectStopComposing())
1354 m_handleMode = Hidden;
1362 return m_fullScreenMode;
1367 return m_composingCursor != -1;
1372 if (focusObjectIsComposing() || m_composingText.isEmpty())
1376 if (m_composingText.contains(u'\n'))
1379 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1383 if (query->value(Qt::ImCursorPosition).toInt() != query->value(Qt::ImAnchorPosition).toInt())
1386 const int absoluteCursorPos = getAbsoluteCursorPosition(query);
1387 if (absoluteCursorPos < m_composingTextStart
1388 || absoluteCursorPos > m_composingTextStart + m_composingText.length())
1391 m_composingCursor = absoluteCursorPos;
1393 QTextCharFormat underlined;
1394 underlined.setFontUnderline(
true);
1397 { QInputMethodEvent::Cursor, absoluteCursorPos - m_composingTextStart, 1 },
1398 { QInputMethodEvent::TextFormat, 0,
int(m_composingText.length()), underlined }
1401 event.setCommitString({}, m_composingTextStart - absoluteCursorPos, m_composingText.length());
1403 QGuiApplication::sendEvent(m_focusObject, &event);
1408 if (!focusObjectIsComposing())
1411 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1415 const int blockPos = getBlockPosition(query);
1416 const int localCursorPos = m_composingCursor - blockPos;
1418 m_composingCursor = -1;
1422 QList<QInputMethodEvent::Attribute> attributes;
1424 event.setCommitString(m_composingText);
1425 sendInputMethodEvent(&event);
1429 QList<QInputMethodEvent::Attribute> attributes;
1431 QInputMethodEvent::Attribute(QInputMethodEvent::Selection, localCursorPos, 0));
1433 sendInputMethodEvent(&event);
1442 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1446 const uint qtInputMethodHints = query->value(Qt::ImHints).toUInt();
1447 const int localPos = query->value(Qt::ImCursorPosition).toInt();
1449 bool atWordBoundary =
1451 && (!focusObjectIsComposing() || m_composingCursor == m_composingTextStart);
1453 if (!atWordBoundary) {
1454 QString surroundingText = query->value(Qt::ImSurroundingText).toString();
1455 surroundingText.truncate(localPos);
1456 if (focusObjectIsComposing())
1457 surroundingText += QStringView{m_composingText}.left(m_composingCursor - m_composingTextStart);
1459 QTextBoundaryFinder finder(QTextBoundaryFinder::Sentence, surroundingText + u'A');
1460 finder.setPosition(surroundingText.length());
1461 if (finder.isAtBoundary())
1462 atWordBoundary = finder.isAtBoundary();
1464 if (atWordBoundary && !(qtInputMethodHints & Qt::ImhLowercaseOnly) && !(qtInputMethodHints & Qt::ImhNoAutoUppercase))
1465 res |= CAP_MODE_SENTENCES;
1467 if (qtInputMethodHints & Qt::ImhUppercaseOnly)
1468 res |= CAP_MODE_CHARACTERS;
1481 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(
1482 Qt::ImCursorPosition | Qt::ImAbsolutePosition | Qt::ImAnchorPosition);
1484 return m_extractedText;
1486 const int cursorPos = getAbsoluteCursorPosition(query);
1487 const int blockPos = getBlockPosition(query);
1494 QVariant textBeforeCursor = QInputMethod::queryFocusObject(Qt::ImTextBeforeCursor, INT_MAX);
1495 QVariant textAfterCursor = QInputMethod::queryFocusObject(Qt::ImTextAfterCursor, INT_MAX);
1496 if (textBeforeCursor.isValid() && textAfterCursor.isValid()) {
1497 if (focusObjectIsComposing()) {
1498 m_extractedText.text =
1499 textBeforeCursor.toString() + m_composingText + textAfterCursor.toString();
1501 m_extractedText.text = textBeforeCursor.toString() + textAfterCursor.toString();
1504 m_extractedText.startOffset = qMax(0, cursorPos - textBeforeCursor.toString().length());
1506 m_extractedText.text = focusObjectInputMethodQuery(Qt::ImSurroundingText)
1507 ->value(Qt::ImSurroundingText).toString();
1509 if (focusObjectIsComposing())
1510 m_extractedText.text.insert(cursorPos - blockPos, m_composingText);
1512 m_extractedText.startOffset = blockPos;
1515 if (focusObjectIsComposing()) {
1516 m_extractedText.selectionStart = m_composingCursor - m_extractedText.startOffset;
1517 m_extractedText.selectionEnd = m_extractedText.selectionStart;
1519 m_extractedText.selectionStart = cursorPos - m_extractedText.startOffset;
1520 m_extractedText.selectionEnd =
1521 blockPos + query->value(Qt::ImAnchorPosition).toInt() - m_extractedText.startOffset;
1524 if (m_extractedText.selectionStart > m_extractedText.selectionEnd)
1525 std::swap(m_extractedText.selectionStart, m_extractedText.selectionEnd);
1528 return m_extractedText;
1533 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1537 return query->value(Qt::ImCurrentSelection).toString();
1547 QVariant reportedTextAfter = QInputMethod::queryFocusObject(Qt::ImTextAfterCursor, length);
1548 if (reportedTextAfter.isValid()) {
1549 text = reportedTextAfter.toString();
1552 QSharedPointer<QInputMethodQueryEvent> query =
1553 focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImSurroundingText);
1555 const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
1556 text = query->value(Qt::ImSurroundingText).toString().mid(cursorPos);
1560 if (focusObjectIsComposing()) {
1562 const int cursorPosInsidePreedit = m_composingCursor - m_composingTextStart;
1563 text = QStringView{m_composingText}.mid(cursorPosInsidePreedit) + text;
1566 QSharedPointer<QInputMethodQueryEvent> query =
1567 focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImAnchorPosition);
1569 const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
1570 const int anchorPos = query->value(Qt::ImAnchorPosition).toInt();
1571 if (anchorPos > cursorPos)
1572 text.remove(0, anchorPos - cursorPos);
1576 text.truncate(length);
1587 QVariant reportedTextBefore = QInputMethod::queryFocusObject(Qt::ImTextBeforeCursor, length);
1588 if (reportedTextBefore.isValid()) {
1589 text = reportedTextBefore.toString();
1592 QSharedPointer<QInputMethodQueryEvent> query =
1593 focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImSurroundingText);
1595 const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
1596 text = query->value(Qt::ImSurroundingText).toString().left(cursorPos);
1600 if (focusObjectIsComposing()) {
1602 const int cursorPosInsidePreedit = m_composingCursor - m_composingTextStart;
1603 text += QStringView{m_composingText}.left(cursorPosInsidePreedit);
1606 QSharedPointer<QInputMethodQueryEvent> query =
1607 focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImAnchorPosition);
1609 const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
1610 const int anchorPos = query->value(Qt::ImAnchorPosition).toInt();
1611 if (anchorPos < cursorPos)
1612 text.chop(cursorPos - anchorPos);
1616 if (text.length() > length)
1617 text = text.right(length);
1622
1623
1624
1625
1626
1627
1628
1629
1633 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1637 BatchEditLock batchEditLock(
this);
1638#if QT_CONFIG(accessibility)
1639 markTextEditForAccessibility();
1642 const int absoluteCursorPos = getAbsoluteCursorPosition(query);
1643 int absoluteAnchorPos = getBlockPosition(query) + query->value(Qt::ImAnchorPosition).toInt();
1645 auto setCursorPosition = [=]() {
1646 const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
1647 QInputMethodEvent event({}, { { QInputMethodEvent::Selection, cursorPos, 0 } });
1648 QGuiApplication::sendEvent(m_focusObject, &event);
1653 if (!m_composingText.isEmpty() && absoluteCursorPos != absoluteAnchorPos) {
1654 setCursorPosition();
1655 absoluteAnchorPos = absoluteCursorPos;
1660 if (absoluteCursorPos == 0 && text.length() == 1 && getTextAfterCursor(1,1).length() >= 0) {
1661 setCursorPosition();
1667 const int effectiveAbsoluteCursorPos = qMin(absoluteCursorPos, absoluteAnchorPos);
1668 if (m_composingTextStart == -1)
1669 m_composingTextStart = effectiveAbsoluteCursorPos;
1671 const int oldComposingTextLen = m_composingText.length();
1672 m_composingText = text;
1674 const int newAbsoluteCursorPos =
1675 newCursorPosition <= 0
1676 ? m_composingTextStart + newCursorPosition
1677 : m_composingTextStart + m_composingText.length() + newCursorPosition - 1;
1679 const bool focusObjectWasComposing = focusObjectIsComposing();
1682 if (!m_composingText.isEmpty() && !m_composingText.contains(u'\n')
1683 && newAbsoluteCursorPos >= m_composingTextStart
1684 && newAbsoluteCursorPos <= m_composingTextStart + m_composingText.length())
1685 m_composingCursor = newAbsoluteCursorPos;
1687 m_composingCursor = -1;
1689 if (focusObjectIsComposing()) {
1690 QTextCharFormat underlined;
1691 underlined.setFontUnderline(
true);
1694 { QInputMethodEvent::TextFormat, 0,
int(m_composingText.length()), underlined },
1695 { QInputMethodEvent::Cursor, m_composingCursor - m_composingTextStart, 1 }
1698 if (oldComposingTextLen > 0 && !focusObjectWasComposing) {
1699 event.setCommitString({}, m_composingTextStart - effectiveAbsoluteCursorPos,
1700 oldComposingTextLen);
1702 if (m_composingText.isEmpty())
1705 QGuiApplication::sendEvent(m_focusObject, &event);
1709 if (focusObjectWasComposing) {
1710 event.setCommitString(m_composingText);
1712 event.setCommitString(m_composingText,
1713 m_composingTextStart - effectiveAbsoluteCursorPos,
1714 oldComposingTextLen);
1716 if (m_composingText.isEmpty())
1719 QGuiApplication::sendEvent(m_focusObject, &event);
1722 if (!focusObjectIsComposing() && newCursorPosition != 1) {
1726 const int newBlockPos = getBlockPosition(
1727 focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImAbsolutePosition));
1730 { QInputMethodEvent::Selection, newAbsoluteCursorPos - newBlockPos, 0 }
1733 QGuiApplication::sendEvent(m_focusObject, &event);
1747 BatchEditLock batchEditLock(
this);
1754 finishComposingText();
1756 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1765 QString text = query->value(Qt::ImSurroundingText).toString();
1766 int textOffset = getBlockPosition(query);
1768 if (start < textOffset || end > textOffset + text.length()) {
1769 const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
1771 if (end - textOffset > text.length()) {
1772 const QString after = query->value(Qt::ImTextAfterCursor).toString();
1773 const int additionalSuffixLen = after.length() - (text.length() - cursorPos);
1775 if (additionalSuffixLen > 0)
1776 text += QStringView{after}.right(additionalSuffixLen);
1779 if (start < textOffset) {
1780 QString before = query->value(Qt::ImTextBeforeCursor).toString();
1781 before.chop(cursorPos);
1783 if (!before.isEmpty()) {
1784 text = before + text;
1785 textOffset -= before.length();
1789 if (start < textOffset || end - textOffset > text.length()) {
1790 qCDebug(lcQpaInputMethods) <<
"Warning: setComposingRegion: failed to retrieve text from composing region";
1796 m_composingText = text.mid(start - textOffset, end - start);
1797 m_composingTextStart = start;
1804 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1808 BatchEditLock batchEditLock(
this);
1810 int blockPosition = getBlockPosition(query);
1811 int localCursorPos = start - blockPosition;
1813 if (focusObjectIsComposing() && start == end && start >= m_composingTextStart
1814 && start <= m_composingTextStart + m_composingText.length()) {
1817 int localOldPos = query->value(Qt::ImCursorPosition).toInt();
1818 int pos = localCursorPos - localOldPos;
1819 QList<QInputMethodEvent::Attribute> attributes;
1820 attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, pos, 1));
1825 QTextCharFormat underlined;
1826 underlined.setFontUnderline(
true);
1827 attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,0, m_composingText.length(),
1828 QVariant(underlined)));
1829 m_composingCursor = start;
1832 QGuiApplication::sendEvent(m_focusObject, &event);
1835 focusObjectStopComposing();
1836 QList<QInputMethodEvent::Attribute> attributes;
1837 attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection,
1841 QGuiApplication::sendEvent(m_focusObject, &event);
1848 BatchEditLock batchEditLock(
this);
1850 focusObjectStopComposing();
1851 m_handleMode = ShowCursor;
1852 sendShortcut(QKeySequence::SelectAll);
1858 BatchEditLock batchEditLock(
this);
1862 finishComposingText();
1864 m_handleMode = ShowCursor;
1865 sendShortcut(QKeySequence::Cut);
1871 BatchEditLock batchEditLock(
this);
1873 focusObjectStopComposing();
1874 m_handleMode = ShowCursor;
1875 sendShortcut(QKeySequence::Copy);
1887 BatchEditLock batchEditLock(
this);
1890 finishComposingText();
1892 m_handleMode = ShowCursor;
1893 sendShortcut(QKeySequence::Paste);
1899 for (
int i = 0; i < sequence.count(); ++i) {
1900 const QKeyCombination keys = sequence[i];
1901 Qt::Key key = Qt::Key(keys.toCombined() & ~Qt::KeyboardModifierMask);
1902 Qt::KeyboardModifiers mod = Qt::KeyboardModifiers(keys.toCombined() & Qt::KeyboardModifierMask);
1904 QKeyEvent pressEvent(QEvent::KeyPress, key, mod);
1905 QKeyEvent releaseEvent(QEvent::KeyRelease, key, mod);
1907 QGuiApplication::sendEvent(m_focusObject, &pressEvent);
1908 QGuiApplication::sendEvent(m_focusObject, &releaseEvent);
1912QSharedPointer<QInputMethodQueryEvent>
QAndroidInputContext::focusObjectInputMethodQuery(Qt::InputMethodQueries queries) {
1916 QObject *focusObject =
qGuiApp->focusObject();
1920 QInputMethodQueryEvent *ret =
new QInputMethodQueryEvent(queries);
1921 QCoreApplication::sendEvent(focusObject, ret);
1922 return QSharedPointer<QInputMethodQueryEvent>(ret);
1930 QObject *focusObject =
qGuiApp->focusObject();
1934 QCoreApplication::sendEvent(focusObject, event);
jboolean beginBatchEdit()
jboolean setSelection(jint start, jint end)
void touchDown(int x, int y)
void longPress(int x, int y)
jboolean finishComposingText()
jint getCursorCapsMode(jint reqModes)
QString getSelectedText(jint flags)
bool isAnimating() const override
This function can be reimplemented to return true whenever input method is animating shown or hidden.
void hideSelectionHandles()
QString getTextAfterCursor(jint length, jint flags)
void reportFullscreenMode(jboolean enabled)
QRectF keyboardRect() const override
This function can be reimplemented to return virtual keyboard rectangle in currently active window co...
void reset() override
Method to be called when input method needs to be reset.
jboolean setComposingText(const QString &text, jint newCursorPosition)
void hideInputPanel() override
Request to hide input panel.
jboolean commitText(const QString &text, jint newCursorPosition)
jboolean setComposingRegion(jint start, jint end)
static QAndroidInputContext * androidInputContext()
void updateSelectionHandles()
void update(Qt::InputMethodQueries queries) override
Notification on editor updates.
QString getTextBeforeCursor(jint length, jint flags)
void sendShortcut(const QKeySequence &)
void invokeAction(QInputMethod::Action action, int cursorPosition) override
Called when the word currently being composed in the input item is tapped by the user.
void updateCursorPosition()
jboolean deleteSurroundingText(jint leftLength, jint rightLength)
jboolean replaceText(jint start, jint end, const QString text, jint newCursorPosition)
void handleLocationChanged(int handleId, int x, int y)
void showInputPanel() override
Request to show input panel.
const ExtractedText & getExtractedText(jint hintMaxChars, jint hintMaxLines, jint flags)
bool isInputPanelVisible() const override
Returns input panel visibility status.
jboolean fullscreenMode()
\inmodule QtCore\reentrant
Combined button and popup list for selecting options.
QAndroidPlatformIntegration * androidPlatformIntegration()
static jfieldID m_startOffsetFieldID
static int getBlockPosition(const QSharedPointer< QInputMethodQueryEvent > &query)
static jboolean cut(JNIEnv *, jobject)
static jint getCursorCapsMode(JNIEnv *, jobject, jint reqModes)
static jfieldID m_partialEndOffsetFieldID
static jfieldID m_textFieldID
static char const *const QtExtractedTextClassName
static bool hasValidFocusObject()
static jboolean fullscreenMode(JNIEnv *, jobject)
static QRect screenInputItemRectangle()
static jboolean finishComposingText(JNIEnv *, jobject)
static jobject getExtractedText(JNIEnv *env, jobject, int hintMaxChars, int hintMaxLines, jint flags)
static jfieldID m_selectionStartFieldID
static JNINativeMethod methods[]
static QAndroidInputContext * m_androidInputContext
static jboolean copy(JNIEnv *, jobject)
static jstring getTextBeforeCursor(JNIEnv *env, jobject, jint length, jint flags)
static jfieldID m_selectionEndFieldID
static QPlatformWindow * focusWindowHandle()
static jboolean copyURL(JNIEnv *, jobject)
static char const *const QtNativeInputConnectionClassName
static int m_selectHandleWidth
static void runOnQtThread(const std::function< void()> &func)
static jboolean commitText(JNIEnv *env, jobject, jstring text, jint newCursorPosition)
static jboolean paste(JNIEnv *, jobject)
static jboolean replaceText(JNIEnv *env, jobject, jint start, jint end, jstring text, jint newCursorPosition)
static jboolean beginBatchEdit(JNIEnv *, jobject)
static jmethodID m_classConstructorMethodID
static jstring getSelectedText(JNIEnv *env, jobject, jint flags)
static jboolean setComposingRegion(JNIEnv *, jobject, jint start, jint end)
static jboolean deleteSurroundingText(JNIEnv *, jobject, jint leftLength, jint rightLength)
static jboolean setComposingText(JNIEnv *env, jobject, jstring text, jint newCursorPosition)
static jboolean updateCursorPosition(JNIEnv *, jobject)
static jstring getTextAfterCursor(JNIEnv *env, jobject, jint length, jint flags)
static int getAbsoluteCursorPosition(const QSharedPointer< QInputMethodQueryEvent > &query)
static void reportFullscreenMode(JNIEnv *, jobject, jboolean enabled)
static jclass m_extractedTextClass
static jboolean endBatchEdit(JNIEnv *, jobject)
static jfieldID m_partialStartOffsetFieldID
static jboolean setSelection(JNIEnv *, jobject, jint start, jint end)
static jboolean selectAll(JNIEnv *, jobject)