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" << str << 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 << str << 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) << extractedText.text <<
"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" << text;
222 return env->NewString(
reinterpret_cast<
const jchar *>(text.constData()), jsize(text.length()));
232 qCDebug(lcQpaInputMethods) <<
"@@@ GETA" << length << text;
233 return env->NewString(
reinterpret_cast<
const jchar *>(text.constData()), jsize(text.length()));
243 qCDebug(lcQpaInputMethods) <<
"@@@ GETB" << length << text;
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" << str << 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 QRect windowRect = QPlatformInputContext::inputItemRectangle().toRect();
397 QPlatformWindow *window =
qGuiApp->focusWindow()->handle();
398 return QRect(window->mapToGlobal(windowRect.topLeft()), windowRect.size());
403 , m_composingTextStart(-1)
404 , m_composingCursor(-1)
406 , m_batchEditNestingLevel(0)
408 , m_fullScreenMode(
false)
412 if (Q_UNLIKELY(!clazz)) {
413 qCritical() <<
"Native registration unable to find class '"
419 if (Q_UNLIKELY(env->RegisterNatives(clazz, methods,
sizeof(
methods) /
sizeof(
methods[0])) < 0)) {
420 qCritical() <<
"RegisterNatives failed for '"
427 if (Q_UNLIKELY(!clazz)) {
428 qCritical() <<
"Native registration unable to find class '"
436 if (Q_UNLIKELY(!m_classConstructorMethodID)) {
437 qCritical(
"GetMethodID failed");
442 if (Q_UNLIKELY(!m_partialEndOffsetFieldID)) {
443 qCritical(
"Can't find field partialEndOffset");
448 if (Q_UNLIKELY(!m_partialStartOffsetFieldID)) {
449 qCritical(
"Can't find field partialStartOffset");
454 if (Q_UNLIKELY(!m_selectionEndFieldID)) {
455 qCritical(
"Can't find field selectionEnd");
460 if (Q_UNLIKELY(!m_selectionStartFieldID)) {
461 qCritical(
"Can't find field selectionStart");
466 if (Q_UNLIKELY(!m_startOffsetFieldID)) {
467 qCritical(
"Can't find field startOffset");
471 m_textFieldID = env->GetFieldID(m_extractedTextClass,
"text",
"Ljava/lang/String;");
472 if (Q_UNLIKELY(!m_textFieldID)) {
473 qCritical(
"Can't find field text");
476 qRegisterMetaType<QInputMethodEvent *>(
"QInputMethodEvent*");
477 qRegisterMetaType<QInputMethodQueryEvent *>(
"QInputMethodQueryEvent*");
480 QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged,
481 this, &QAndroidInputContext::updateSelectionHandles);
482 QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::anchorRectangleChanged,
483 this, &QAndroidInputContext::updateSelectionHandles);
484 QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::inputItemClipRectangleChanged,
this, [
this]{
485 auto im =
qGuiApp->inputMethod();
486 if (!im->inputItemClipRectangle().contains(im->anchorRectangle()) ||
487 !im->inputItemClipRectangle().contains(im->cursorRectangle())) {
488 m_handleMode = Hidden;
489 updateSelectionHandles();
492 m_hideCursorHandleTimer.setInterval(4000);
493 m_hideCursorHandleTimer.setSingleShot(
true);
494 m_hideCursorHandleTimer.setTimerType(Qt::VeryCoarseTimer);
495 connect(&m_hideCursorHandleTimer, &QTimer::timeout,
this, [
this]{
496 m_handleMode = Hidden;
521 QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
522 return absolutePos.isValid() ? absolutePos.toInt() : query->value(Qt::ImCursorPosition).toInt();
528 QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
529 return absolutePos.isValid() ? absolutePos.toInt() - query->value(Qt::ImCursorPosition).toInt() : 0;
534 focusObjectStopComposing();
536 m_batchEditNestingLevel = 0;
537 m_handleMode = Hidden;
539 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(Qt::ImEnabled);
540 if (!query.isNull() && query->value(Qt::ImEnabled).toBool()) {
546 if (!m_accessibilityFocusInProgress)
556 focusObjectStopComposing();
561 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
562 if (!query.isNull() && m_batchEditNestingLevel == 0) {
563 const int cursorPos = getAbsoluteCursorPosition(query);
564 const int composeLength = m_composingText.length();
567 if (m_composingText.isEmpty() != (m_composingTextStart == -1))
568 qWarning() <<
"Input method out of sync" << m_composingText << m_composingTextStart;
570 int realSelectionStart = cursorPos;
571 int realSelectionEnd = cursorPos;
573 int cpos = query->value(Qt::ImCursorPosition).toInt();
574 int anchor = query->value(Qt::ImAnchorPosition).toInt();
575 if (cpos != anchor) {
576 if (!m_composingText.isEmpty()) {
577 qWarning(
"Selecting text while preediting may give unpredictable results.");
578 focusObjectStopComposing();
580 int blockPos = getBlockPosition(query);
581 realSelectionStart = blockPos + cpos;
582 realSelectionEnd = blockPos + anchor;
585 if (focusObjectIsComposing())
586 realSelectionStart = realSelectionEnd = m_composingCursor;
589 if (realSelectionStart > realSelectionEnd)
590 std::swap(realSelectionStart, realSelectionEnd);
593 m_composingTextStart
, m_composingTextStart + composeLength
);
599 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
602 return query->value(Qt::ImHints).toUInt() & Qt::ImhNoEditMenu;
607 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
610 return query->value(Qt::ImHints).toUInt() & Qt::ImhNoTextHandles;
615 if (m_fullScreenMode) {
619 static bool noHandles = qEnvironmentVariableIntValue(
"QT_QPA_NO_TEXT_HANDLES");
620 if (noHandles || !m_focusObject)
623 if (isImhNoTextHandlesSet()) {
628 auto im =
qGuiApp->inputMethod();
630 QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImEnabled
631 | Qt::ImCurrentSelection | Qt::ImHints | Qt::ImSurroundingText
633 QCoreApplication::sendEvent(m_focusObject, &query);
635 int cpos = query.value(Qt::ImCursorPosition).toInt();
636 int anchor = query.value(Qt::ImAnchorPosition).toInt();
637 const QVariant readOnlyVariant = query.value(Qt::ImReadOnly);
638 bool readOnly = readOnlyVariant.toBool();
639 QPlatformWindow *qPlatformWindow =
qGuiApp->focusWindow()->handle();
641 if (!readOnly && ((m_handleMode & 0xff) == Hidden)) {
646 if ( cpos == anchor && (!readOnlyVariant.isValid() || readOnly)) {
651 if (cpos == anchor || im->anchorRectangle().isNull()) {
652 auto curRect = cursorRectangle();
653 QPoint cursorPointGlobal = QPoint(curRect.x() + (curRect.width() / 2), curRect.y() + curRect.height());
654 QPoint cursorPoint(curRect.center().x(), curRect.bottom());
659 if (cursorPointGlobal != cursorPoint) {
660 x = cursorPointGlobal.x();
661 y = cursorPointGlobal.y();
664 QPoint editMenuPoint(x, y);
665 m_handleMode &= ShowEditPopup;
666 m_handleMode |= ShowCursor;
667 uint32_t buttons = 0;
668 const bool withEditMenu = !isImhNoEditMenuSet();
671 if (!query.value(Qt::ImSurroundingText).toString().isEmpty())
674 QtAndroidInput::updateHandles(m_handleMode, editMenuPoint, buttons, cursorPointGlobal);
675 m_hideCursorHandleTimer.start();
680 m_handleMode = ShowSelection | ShowEditPopup ;
681 auto leftRect = cursorRectangle();
682 auto rightRect = anchorRectangle();
684 std::swap(leftRect, rightRect);
688 QPoint leftPoint(qPlatformWindow->mapToGlobal(leftRect.bottomLeft().toPoint()));
689 QPoint rightPoint(qPlatformWindow->mapToGlobal(rightRect.bottomRight().toPoint()));
692 if (platformIntegration) {
696 int rightSideOfScreen = platformIntegration
->screen()->availableGeometry().right();
699 leftPoint = qPlatformWindow->mapFromGlobal(leftPoint);
703 rightPoint = qPlatformWindow->mapFromGlobal(rightPoint);
705 QPoint editPoint(leftRect.united(rightRect).topLeft().toPoint());
706 uint32_t buttons = 0;
707 const bool withEditMenu = !isImhNoEditMenuSet();
713 QtAndroidInput::updateHandles(m_handleMode, editPoint, buttons, leftPoint, rightPoint,
714 query.value(Qt::ImCurrentSelection).toString().isRightToLeft());
715 m_hideCursorHandleTimer.stop();
720
721
722
723
726 if (m_batchEditNestingLevel != 0) {
727 qWarning() <<
"QAndroidInputContext::handleLocationChanged returned";
733 QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition
734 | Qt::ImAbsolutePosition | Qt::ImCurrentSelection);
735 QCoreApplication::sendEvent(m_focusObject, &query);
736 int cpos = query.value(Qt::ImCursorPosition).toInt();
737 int anchor = query.value(Qt::ImAnchorPosition).toInt();
738 auto leftRect = cursorRectangle();
739 auto rightRect = anchorRectangle();
741 std::swap(leftRect, rightRect);
744 if (handleId == 2 && point.y() > rightRect.center().y()) {
745 point.setY(rightRect.center().y());
746 }
else if (handleId == 3 && point.y() < leftRect.center().y()) {
747 point.setY(leftRect.center().y());
751 auto object = m_focusObject->parent();
754 if (QString::compare(object->metaObject()->className(),
755 "QDialog", Qt::CaseInsensitive) == 0) {
756 dialogMoveX += object->property(
"x").toInt();
758 object = object->parent();
762 QPointF(QHighDpi::fromNativePixels(point, QGuiApplication::focusWindow()));
763 const QPointF fixedPosition = QPointF(position.x() - dialogMoveX, position.y());
764 const QInputMethod *im = QGuiApplication::inputMethod();
765 const QTransform mapToLocal = im->inputItemTransform().inverted();
766 const int handlePos = im->queryFocusObject(Qt::ImCursorPosition, mapToLocal.map(fixedPosition)).toInt(&ok);
772 int newAnchor = anchor;
773 if (newAnchor > newCpos)
774 std::swap(newAnchor, newCpos);
778 newAnchor = handlePos;
779 }
else if (handleId == 2) {
780 newAnchor = handlePos;
781 }
else if (handleId == 3) {
786
787
788
789
790 if ((handleId == 2 || handleId == 3) && newCpos <= newAnchor) {
791 QTextBoundaryFinder finder(QTextBoundaryFinder::Grapheme,
792 query.value(Qt::ImCurrentSelection).toString());
794 const int oldSelectionStartPos = qMin(cpos, anchor);
798 finder.toPreviousBoundary();
799 newAnchor = finder.position() + oldSelectionStartPos;
802 finder.toNextBoundary();
803 newCpos = finder.position() + oldSelectionStartPos;
808 if (!focusObjectIsComposing() && newCpos == cpos && newAnchor == anchor)
812
813
814
815
816 if (focusObjectIsComposing() && handleId == 1) {
817 int absoluteCpos = query.value(Qt::ImAbsolutePosition).toInt(&ok);
820 const int blockPos = absoluteCpos - cpos;
822 if (blockPos + newCpos == m_composingCursor)
826 BatchEditLock batchEditLock(
this);
828 focusObjectStopComposing();
830 QList<QInputMethodEvent::Attribute> attributes;
831 attributes.append({ QInputMethodEvent::Selection, newAnchor, newCpos - newAnchor });
832 if (newCpos != newAnchor)
833 attributes.append({ QInputMethodEvent::Cursor, 0, 0 });
836 QGuiApplication::sendEvent(m_focusObject, &event);
841 if (m_focusObject && screenInputItemRectangle().contains(x, y)) {
843 m_handleMode = ShowCursor;
845 m_hideCursorHandleTimer.stop();
847 if (focusObjectIsComposing()) {
848 const int curBlockPos = getBlockPosition(
849 focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImAbsolutePosition));
850 const int touchPosition = curBlockPos
851 + queryFocusObject(Qt::ImCursorPosition, QPointF(x, y)).toInt();
852 if (touchPosition != m_composingCursor)
853 focusObjectStopComposing();
857 QPlatformWindow *window =
qGuiApp->focusWindow()->handle();
858 const QRectF curRect = cursorRectangle();
859 const QPoint cursorGlobalPoint = window->mapToGlobal(QPoint(curRect.x(), curRect.y()));
860 const QRect windowRect = QPlatformInputContext::inputItemClipRectangle().toRect();
861 const QRect windowGlobalRect = QRect(window->mapToGlobal(windowRect.topLeft()), windowRect.size());
863 if (windowGlobalRect.contains(cursorGlobalPoint.x(), cursorGlobalPoint.y()))
870 static bool noHandles = qEnvironmentVariableIntValue(
"QT_QPA_NO_TEXT_HANDLES");
874 if (m_focusObject && screenInputItemRectangle().contains(x, y)) {
875 BatchEditLock batchEditLock(
this);
877 focusObjectStopComposing();
878 const QPointF touchPoint(x, y);
879 setSelectionOnFocusObject(touchPoint, touchPoint);
881 QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImTextBeforeCursor | Qt::ImTextAfterCursor);
882 QCoreApplication::sendEvent(m_focusObject, &query);
883 int cursor = query.value(Qt::ImCursorPosition).toInt();
885 QString before = query.value(Qt::ImTextBeforeCursor).toString();
886 QString after = query.value(Qt::ImTextAfterCursor).toString();
887 for (
const auto &ch : after) {
888 if (!ch.isLetterOrNumber())
893 for (
auto itch = before.rbegin(); itch != after.rend(); ++itch) {
894 if (!itch->isLetterOrNumber())
898 if (cursor == anchor || cursor < 0 || cursor - anchor > 500) {
899 m_handleMode = ShowCursor | ShowEditPopup;
903 QList<QInputMethodEvent::Attribute> imAttributes;
904 imAttributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 0, QVariant()));
905 imAttributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, anchor, cursor - anchor, QVariant()));
907 QGuiApplication::sendEvent(m_focusObject, &event);
909 m_handleMode = ShowSelection | ShowEditPopup;
918 m_handleMode = Hidden;
925 if (m_handleMode & ShowSelection) {
926 m_handleMode = Hidden;
929 m_hideCursorHandleTimer.start();
935 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(queries);
938#if QT_CONFIG(accessibility)
943 if (queries & Qt::ImSurroundingText) {
944 if (m_batchEditNestingLevel == 0)
945 notifyTextChangedForAccessibility();
946 else if (QAccessible::isActive())
947 m_a11yTextEditPending =
true;
950#warning TODO extract the needed data from query
955#warning TODO Handle at least QInputMethod::ContextMenu action
957 Q_UNUSED(cursorPosition);
965 return QtAndroidInput::softwareKeyboardRect();
975 if (QGuiApplication::applicationState() != Qt::ApplicationActive) {
976 connect(
qGuiApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
this, SLOT(showInputPanelLater(Qt::ApplicationState)));
983 if (m_accessibilityFocusInProgress)
986 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
990 if (!
qGuiApp->focusWindow()->handle())
993 disconnect(m_updateCursorPosConnection);
994 m_updateCursorPosConnection = {};
996 if (
qGuiApp->focusObject()->metaObject()->indexOfSignal(
"cursorPositionChanged(int,int)") >= 0)
997 m_updateCursorPosConnection = connect(
qGuiApp->focusObject(), SIGNAL(cursorPositionChanged(
int,
int)),
this, SLOT(updateCursorPosition()));
998 else if (
qGuiApp->focusObject()->metaObject()->indexOfSignal(
"cursorPositionChanged()") >= 0)
999 m_updateCursorPosConnection = connect(
qGuiApp->focusObject(), SIGNAL(cursorPositionChanged()),
this, SLOT(updateCursorPosition()));
1001 QRect rect = QPlatformInputContext::inputItemRectangle().toRect();
1003 query->value(Qt::ImHints).toUInt()
,
1004 query->value(Qt::ImEnterKeyType).toUInt()
);
1009 if (state != Qt::ApplicationActive)
1011 disconnect(
qGuiApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
this, SLOT(showInputPanelLater(Qt::ApplicationState)));
1017 if (
qGuiApp->thread() == QThread::currentThread())
1020 QMetaObject::invokeMethod(
this,
"safeCall", conType, Q_ARG(std::function<
void()>, func));
1035 return m_composingText.length();
1040 m_composingText.clear();
1041 m_composingTextStart = -1;
1042 m_composingCursor = -1;
1043 m_extractedText.clear();
1049 return m_focusObject;
1054 if (object != m_focusObject) {
1055 focusObjectStopComposing();
1056 m_focusObject = object;
1058#if QT_CONFIG(accessibility)
1066 m_a11yTextEditPending =
false;
1067 m_a11yLastText.clear();
1068 m_a11yBaselineValid =
false;
1069 if (m_focusObject && QAccessible::isActive()) {
1070 QInputMethodQueryEvent query(Qt::ImSurroundingText);
1071 QCoreApplication::sendEvent(m_focusObject, &query);
1072 const QVariant surroundingText = query.value(Qt::ImSurroundingText);
1073 if (surroundingText.isValid()) {
1074 m_a11yLastText = surroundingText.toString();
1075 m_a11yBaselineValid =
true;
1083#if QT_CONFIG(accessibility)
1084void QAndroidInputContext::markTextEditForAccessibility()
1086 if (!QAccessible::isActive() || !m_focusObject)
1088 m_a11yTextEditPending =
true;
1093 if (!m_a11yBaselineValid) {
1094 QInputMethodQueryEvent query(Qt::ImSurroundingText);
1095 QCoreApplication::sendEvent(m_focusObject, &query);
1096 m_a11yLastText = query.value(Qt::ImSurroundingText).toString();
1097 m_a11yBaselineValid =
true;
1101void QAndroidInputContext::notifyTextChangedForAccessibility()
1103 if (!QAccessible::isActive() || !m_focusObject)
1106 QInputMethodQueryEvent query(Qt::ImSurroundingText);
1107 QCoreApplication::sendEvent(m_focusObject, &query);
1108 const QString after = query.value(Qt::ImSurroundingText).toString();
1109 if (!m_a11yBaselineValid) {
1112 m_a11yLastText = after;
1113 m_a11yBaselineValid =
true;
1116 const QString before = m_a11yLastText;
1117 if (after == before)
1119 m_a11yLastText = after;
1124 const int minLen = qMin(before.size(), after.size());
1126 while (prefix < minLen && before.at(prefix) == after.at(prefix))
1130 if (prefix > 0 && before.at(prefix - 1).isHighSurrogate())
1133 while (suffix < minLen - prefix
1134 && before.at(before.size() - 1 - suffix) == after.at(after.size() - 1 - suffix))
1136 if (suffix > 0 && before.at(before.size() - suffix).isLowSurrogate())
1138 const int removedCount =
int(before.size()) - prefix - suffix;
1139 const int addedCount =
int(after.size()) - prefix - suffix;
1144 if (QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(m_focusObject))
1145 focusUid = QAccessible::uniqueId(iface);
1147 QtAndroid::notifyTextChanged(focusUid, after, before, prefix, addedCount, removedCount);
1153 ++m_batchEditNestingLevel;
1159 if (--m_batchEditNestingLevel == 0) {
1160 focusObjectStartComposing();
1162#if QT_CONFIG(accessibility)
1170 if (m_a11yTextEditPending) {
1171 m_a11yTextEditPending =
false;
1172 notifyTextChangedForAccessibility();
1180
1181
1182
1185 BatchEditLock batchEditLock(
this);
1186 return setComposingText(text, newCursorPosition) && finishComposingText();
1191 BatchEditLock batchEditLock(
this);
1192#if QT_CONFIG(accessibility)
1193 markTextEditForAccessibility();
1196 focusObjectStopComposing();
1198 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1202 if (leftLength < 0) {
1203 rightLength += -leftLength;
1207 const int initialBlockPos = getBlockPosition(query);
1208 const int initialCursorPos = getAbsoluteCursorPosition(query);
1209 const int initialAnchorPos = initialBlockPos + query->value(Qt::ImAnchorPosition).toInt();
1212
1213
1214
1215
1216
1217
1218
1219
1221 m_composingText.isEmpty()
1222 ? qMin(initialCursorPos, initialAnchorPos)
1223 : qMin(qMin(initialCursorPos, initialAnchorPos), m_composingTextStart);
1225 const int rightBegin =
1226 m_composingText.isEmpty()
1227 ? qMax(initialCursorPos, initialAnchorPos)
1228 : qMax(qMax(initialCursorPos, initialAnchorPos),
1229 m_composingTextStart + m_composingText.length());
1231 int textBeforeCursorLen;
1232 int textAfterCursorLen;
1234 QVariant textBeforeCursor = query->value(Qt::ImTextBeforeCursor);
1235 QVariant textAfterCursor = query->value(Qt::ImTextAfterCursor);
1236 if (textBeforeCursor.isValid() && textAfterCursor.isValid()) {
1237 textBeforeCursorLen = textBeforeCursor.toString().length();
1238 textAfterCursorLen = textAfterCursor.toString().length();
1240 textBeforeCursorLen = initialCursorPos - initialBlockPos;
1241 textAfterCursorLen =
1242 query->value(Qt::ImSurroundingText).toString().length() - textBeforeCursorLen;
1245 leftLength = qMin(qMax(0, textBeforeCursorLen - (initialCursorPos - leftEnd)), leftLength);
1246 rightLength = qMin(qMax(0, textAfterCursorLen - (rightBegin - initialCursorPos)), rightLength);
1248 if (leftLength == 0 && rightLength == 0)
1251 if (leftEnd == rightBegin) {
1254 event.setCommitString({}, -leftLength, leftLength + rightLength);
1255 QGuiApplication::sendEvent(m_focusObject, &event);
1257 if (initialCursorPos != initialAnchorPos) {
1259 { QInputMethodEvent::Selection, initialCursorPos - initialBlockPos, 0 }
1262 QGuiApplication::sendEvent(m_focusObject, &event);
1265 int currentCursorPos = initialCursorPos;
1267 if (rightLength > 0) {
1269 event.setCommitString({}, rightBegin - currentCursorPos, rightLength);
1270 QGuiApplication::sendEvent(m_focusObject, &event);
1272 currentCursorPos = rightBegin;
1275 if (leftLength > 0) {
1276 const int leftBegin = leftEnd - leftLength;
1279 event.setCommitString({}, leftBegin - currentCursorPos, leftLength);
1280 QGuiApplication::sendEvent(m_focusObject, &event);
1282 currentCursorPos = leftBegin;
1284 if (!m_composingText.isEmpty())
1285 m_composingTextStart -= leftLength;
1289 if (currentCursorPos != initialCursorPos - leftLength
1290 || initialCursorPos != initialAnchorPos) {
1292 const int currentBlockPos = getBlockPosition(
1293 focusObjectInputMethodQuery(Qt::ImAbsolutePosition | Qt::ImCursorPosition));
1296 { QInputMethodEvent::Selection, initialCursorPos - leftLength - currentBlockPos,
1297 initialAnchorPos - initialCursorPos },
1298 { QInputMethodEvent::Cursor, 0, 0 }
1301 QGuiApplication::sendEvent(m_focusObject, &event);
1311 BatchEditLock batchEditLock(
this);
1313 if (!focusObjectStopComposing())
1321
1322
1323
1324
1327 if (!finishComposingText())
1329 if (!setSelection(start, end))
1332 return commitText(text, newCursorPosition);
1337 m_fullScreenMode = enabled;
1338 BatchEditLock batchEditLock(
this);
1339 if (!focusObjectStopComposing())
1343 m_handleMode = Hidden;
1351 return m_fullScreenMode;
1356 return m_composingCursor != -1;
1361 if (focusObjectIsComposing() || m_composingText.isEmpty())
1365 if (m_composingText.contains(u'\n'))
1368 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1372 if (query->value(Qt::ImCursorPosition).toInt() != query->value(Qt::ImAnchorPosition).toInt())
1375 const int absoluteCursorPos = getAbsoluteCursorPosition(query);
1376 if (absoluteCursorPos < m_composingTextStart
1377 || absoluteCursorPos > m_composingTextStart + m_composingText.length())
1380 m_composingCursor = absoluteCursorPos;
1382 QTextCharFormat underlined;
1383 underlined.setFontUnderline(
true);
1386 { QInputMethodEvent::Cursor, absoluteCursorPos - m_composingTextStart, 1 },
1387 { QInputMethodEvent::TextFormat, 0,
int(m_composingText.length()), underlined }
1390 event.setCommitString({}, m_composingTextStart - absoluteCursorPos, m_composingText.length());
1392 QGuiApplication::sendEvent(m_focusObject, &event);
1397 if (!focusObjectIsComposing())
1400 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1404 const int blockPos = getBlockPosition(query);
1405 const int localCursorPos = m_composingCursor - blockPos;
1407 m_composingCursor = -1;
1411 QList<QInputMethodEvent::Attribute> attributes;
1413 event.setCommitString(m_composingText);
1414 sendInputMethodEvent(&event);
1418 QList<QInputMethodEvent::Attribute> attributes;
1420 QInputMethodEvent::Attribute(QInputMethodEvent::Selection, localCursorPos, 0));
1422 sendInputMethodEvent(&event);
1431 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1435 const uint qtInputMethodHints = query->value(Qt::ImHints).toUInt();
1436 const int localPos = query->value(Qt::ImCursorPosition).toInt();
1438 bool atWordBoundary =
1440 && (!focusObjectIsComposing() || m_composingCursor == m_composingTextStart);
1442 if (!atWordBoundary) {
1443 QString surroundingText = query->value(Qt::ImSurroundingText).toString();
1444 surroundingText.truncate(localPos);
1445 if (focusObjectIsComposing())
1446 surroundingText += QStringView{m_composingText}.left(m_composingCursor - m_composingTextStart);
1448 QTextBoundaryFinder finder(QTextBoundaryFinder::Sentence, surroundingText + u'A');
1449 finder.setPosition(surroundingText.length());
1450 if (finder.isAtBoundary())
1451 atWordBoundary = finder.isAtBoundary();
1453 if (atWordBoundary && !(qtInputMethodHints & Qt::ImhLowercaseOnly) && !(qtInputMethodHints & Qt::ImhNoAutoUppercase))
1454 res |= CAP_MODE_SENTENCES;
1456 if (qtInputMethodHints & Qt::ImhUppercaseOnly)
1457 res |= CAP_MODE_CHARACTERS;
1470 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(
1471 Qt::ImCursorPosition | Qt::ImAbsolutePosition | Qt::ImAnchorPosition);
1473 return m_extractedText;
1475 const int cursorPos = getAbsoluteCursorPosition(query);
1476 const int blockPos = getBlockPosition(query);
1483 QVariant textBeforeCursor = QInputMethod::queryFocusObject(Qt::ImTextBeforeCursor, INT_MAX);
1484 QVariant textAfterCursor = QInputMethod::queryFocusObject(Qt::ImTextAfterCursor, INT_MAX);
1485 if (textBeforeCursor.isValid() && textAfterCursor.isValid()) {
1486 if (focusObjectIsComposing()) {
1487 m_extractedText.text =
1488 textBeforeCursor.toString() + m_composingText + textAfterCursor.toString();
1490 m_extractedText.text = textBeforeCursor.toString() + textAfterCursor.toString();
1493 m_extractedText.startOffset = qMax(0, cursorPos - textBeforeCursor.toString().length());
1495 m_extractedText.text = focusObjectInputMethodQuery(Qt::ImSurroundingText)
1496 ->value(Qt::ImSurroundingText).toString();
1498 if (focusObjectIsComposing())
1499 m_extractedText.text.insert(cursorPos - blockPos, m_composingText);
1501 m_extractedText.startOffset = blockPos;
1504 if (focusObjectIsComposing()) {
1505 m_extractedText.selectionStart = m_composingCursor - m_extractedText.startOffset;
1506 m_extractedText.selectionEnd = m_extractedText.selectionStart;
1508 m_extractedText.selectionStart = cursorPos - m_extractedText.startOffset;
1509 m_extractedText.selectionEnd =
1510 blockPos + query->value(Qt::ImAnchorPosition).toInt() - m_extractedText.startOffset;
1513 if (m_extractedText.selectionStart > m_extractedText.selectionEnd)
1514 std::swap(m_extractedText.selectionStart, m_extractedText.selectionEnd);
1517 return m_extractedText;
1522 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1526 return query->value(Qt::ImCurrentSelection).toString();
1536 QVariant reportedTextAfter = QInputMethod::queryFocusObject(Qt::ImTextAfterCursor, length);
1537 if (reportedTextAfter.isValid()) {
1538 text = reportedTextAfter.toString();
1541 QSharedPointer<QInputMethodQueryEvent> query =
1542 focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImSurroundingText);
1544 const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
1545 text = query->value(Qt::ImSurroundingText).toString().mid(cursorPos);
1549 if (focusObjectIsComposing()) {
1551 const int cursorPosInsidePreedit = m_composingCursor - m_composingTextStart;
1552 text = QStringView{m_composingText}.mid(cursorPosInsidePreedit) + text;
1555 QSharedPointer<QInputMethodQueryEvent> query =
1556 focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImAnchorPosition);
1558 const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
1559 const int anchorPos = query->value(Qt::ImAnchorPosition).toInt();
1560 if (anchorPos > cursorPos)
1561 text.remove(0, anchorPos - cursorPos);
1565 text.truncate(length);
1576 QVariant reportedTextBefore = QInputMethod::queryFocusObject(Qt::ImTextBeforeCursor, length);
1577 if (reportedTextBefore.isValid()) {
1578 text = reportedTextBefore.toString();
1581 QSharedPointer<QInputMethodQueryEvent> query =
1582 focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImSurroundingText);
1584 const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
1585 text = query->value(Qt::ImSurroundingText).toString().left(cursorPos);
1589 if (focusObjectIsComposing()) {
1591 const int cursorPosInsidePreedit = m_composingCursor - m_composingTextStart;
1592 text += QStringView{m_composingText}.left(cursorPosInsidePreedit);
1595 QSharedPointer<QInputMethodQueryEvent> query =
1596 focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImAnchorPosition);
1598 const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
1599 const int anchorPos = query->value(Qt::ImAnchorPosition).toInt();
1600 if (anchorPos < cursorPos)
1601 text.chop(cursorPos - anchorPos);
1605 if (text.length() > length)
1606 text = text.right(length);
1611
1612
1613
1614
1615
1616
1617
1618
1622 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1626 BatchEditLock batchEditLock(
this);
1627#if QT_CONFIG(accessibility)
1628 markTextEditForAccessibility();
1631 const int absoluteCursorPos = getAbsoluteCursorPosition(query);
1632 int absoluteAnchorPos = getBlockPosition(query) + query->value(Qt::ImAnchorPosition).toInt();
1634 auto setCursorPosition = [=]() {
1635 const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
1636 QInputMethodEvent event({}, { { QInputMethodEvent::Selection, cursorPos, 0 } });
1637 QGuiApplication::sendEvent(m_focusObject, &event);
1642 if (!m_composingText.isEmpty() && absoluteCursorPos != absoluteAnchorPos) {
1643 setCursorPosition();
1644 absoluteAnchorPos = absoluteCursorPos;
1649 if (absoluteCursorPos == 0 && text.length() == 1 && getTextAfterCursor(1,1).length() >= 0) {
1650 setCursorPosition();
1656 const int effectiveAbsoluteCursorPos = qMin(absoluteCursorPos, absoluteAnchorPos);
1657 if (m_composingTextStart == -1)
1658 m_composingTextStart = effectiveAbsoluteCursorPos;
1660 const int oldComposingTextLen = m_composingText.length();
1661 m_composingText = text;
1663 const int newAbsoluteCursorPos =
1664 newCursorPosition <= 0
1665 ? m_composingTextStart + newCursorPosition
1666 : m_composingTextStart + m_composingText.length() + newCursorPosition - 1;
1668 const bool focusObjectWasComposing = focusObjectIsComposing();
1671 if (!m_composingText.isEmpty() && !m_composingText.contains(u'\n')
1672 && newAbsoluteCursorPos >= m_composingTextStart
1673 && newAbsoluteCursorPos <= m_composingTextStart + m_composingText.length())
1674 m_composingCursor = newAbsoluteCursorPos;
1676 m_composingCursor = -1;
1678 if (focusObjectIsComposing()) {
1679 QTextCharFormat underlined;
1680 underlined.setFontUnderline(
true);
1683 { QInputMethodEvent::TextFormat, 0,
int(m_composingText.length()), underlined },
1684 { QInputMethodEvent::Cursor, m_composingCursor - m_composingTextStart, 1 }
1687 if (oldComposingTextLen > 0 && !focusObjectWasComposing) {
1688 event.setCommitString({}, m_composingTextStart - effectiveAbsoluteCursorPos,
1689 oldComposingTextLen);
1691 if (m_composingText.isEmpty())
1694 QGuiApplication::sendEvent(m_focusObject, &event);
1698 if (focusObjectWasComposing) {
1699 event.setCommitString(m_composingText);
1701 event.setCommitString(m_composingText,
1702 m_composingTextStart - effectiveAbsoluteCursorPos,
1703 oldComposingTextLen);
1705 if (m_composingText.isEmpty())
1708 QGuiApplication::sendEvent(m_focusObject, &event);
1711 if (!focusObjectIsComposing() && newCursorPosition != 1) {
1715 const int newBlockPos = getBlockPosition(
1716 focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImAbsolutePosition));
1719 { QInputMethodEvent::Selection, newAbsoluteCursorPos - newBlockPos, 0 }
1722 QGuiApplication::sendEvent(m_focusObject, &event);
1736 BatchEditLock batchEditLock(
this);
1743 finishComposingText();
1745 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1754 QString text = query->value(Qt::ImSurroundingText).toString();
1755 int textOffset = getBlockPosition(query);
1757 if (start < textOffset || end > textOffset + text.length()) {
1758 const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
1760 if (end - textOffset > text.length()) {
1761 const QString after = query->value(Qt::ImTextAfterCursor).toString();
1762 const int additionalSuffixLen = after.length() - (text.length() - cursorPos);
1764 if (additionalSuffixLen > 0)
1765 text += QStringView{after}.right(additionalSuffixLen);
1768 if (start < textOffset) {
1769 QString before = query->value(Qt::ImTextBeforeCursor).toString();
1770 before.chop(cursorPos);
1772 if (!before.isEmpty()) {
1773 text = before + text;
1774 textOffset -= before.length();
1778 if (start < textOffset || end - textOffset > text.length()) {
1779 qCDebug(lcQpaInputMethods) <<
"Warning: setComposingRegion: failed to retrieve text from composing region";
1785 m_composingText = text.mid(start - textOffset, end - start);
1786 m_composingTextStart = start;
1793 QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
1797 BatchEditLock batchEditLock(
this);
1799 int blockPosition = getBlockPosition(query);
1800 int localCursorPos = start - blockPosition;
1802 if (focusObjectIsComposing() && start == end && start >= m_composingTextStart
1803 && start <= m_composingTextStart + m_composingText.length()) {
1806 int localOldPos = query->value(Qt::ImCursorPosition).toInt();
1807 int pos = localCursorPos - localOldPos;
1808 QList<QInputMethodEvent::Attribute> attributes;
1809 attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, pos, 1));
1814 QTextCharFormat underlined;
1815 underlined.setFontUnderline(
true);
1816 attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,0, m_composingText.length(),
1817 QVariant(underlined)));
1818 m_composingCursor = start;
1821 QGuiApplication::sendEvent(m_focusObject, &event);
1824 focusObjectStopComposing();
1825 QList<QInputMethodEvent::Attribute> attributes;
1826 attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection,
1830 QGuiApplication::sendEvent(m_focusObject, &event);
1837 BatchEditLock batchEditLock(
this);
1839 focusObjectStopComposing();
1840 m_handleMode = ShowCursor;
1841 sendShortcut(QKeySequence::SelectAll);
1847 BatchEditLock batchEditLock(
this);
1851 finishComposingText();
1853 m_handleMode = ShowCursor;
1854 sendShortcut(QKeySequence::Cut);
1860 BatchEditLock batchEditLock(
this);
1862 focusObjectStopComposing();
1863 m_handleMode = ShowCursor;
1864 sendShortcut(QKeySequence::Copy);
1876 BatchEditLock batchEditLock(
this);
1879 finishComposingText();
1881 m_handleMode = ShowCursor;
1882 sendShortcut(QKeySequence::Paste);
1888 for (
int i = 0; i < sequence.count(); ++i) {
1889 const QKeyCombination keys = sequence[i];
1890 Qt::Key key = Qt::Key(keys.toCombined() & ~Qt::KeyboardModifierMask);
1891 Qt::KeyboardModifiers mod = Qt::KeyboardModifiers(keys.toCombined() & Qt::KeyboardModifierMask);
1893 QKeyEvent pressEvent(QEvent::KeyPress, key, mod);
1894 QKeyEvent releaseEvent(QEvent::KeyRelease, key, mod);
1896 QGuiApplication::sendEvent(m_focusObject, &pressEvent);
1897 QGuiApplication::sendEvent(m_focusObject, &releaseEvent);
1901QSharedPointer<QInputMethodQueryEvent>
QAndroidInputContext::focusObjectInputMethodQuery(Qt::InputMethodQueries queries) {
1905 QObject *focusObject =
qGuiApp->focusObject();
1909 QInputMethodQueryEvent *ret =
new QInputMethodQueryEvent(queries);
1910 QCoreApplication::sendEvent(focusObject, ret);
1911 return QSharedPointer<QInputMethodQueryEvent>(ret);
1919 QObject *focusObject =
qGuiApp->focusObject();
1923 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 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)