Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qohosinputcontext.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include <QtCore/private/qnapi_p.h>
6#include <qohosjsenv_p.h>
7#include <QtCore/private/qohoslogger_p.h>
8#include <QtCore/qnamespace.h>
9#include <QtGui/private/qhighdpiscaling_p.h>
10#include "qohosjsmain.h"
13#include <QRect>
14#include <QInputDevice>
15#include <QGuiApplication>
16#include <QTextCharFormat>
17#include <algorithm>
18#include <qohosjsutils.h>
19#include <inputmethod/inputmethod_controller_capi.h>
21
22namespace {
23
25const Qt::EnterKeyType defaultEnterKeyType = Qt::EnterKeyDefault;
26
27using InsertedTextId = QtOhos::TypedId<std::uint64_t, struct InsertedTextIdTag>;
28
30{
31public:
32 QOhosInsertedText(const std::string &text, const InsertedTextId &id);
33
34 InsertedTextId id() const;
35 std::string text() const;
36
37private:
38 InsertedTextId m_id;
39 std::string m_text;
40};
41
43{
44public:
46
51
54
55private:
56 JsInputMethodInsertedTextComposer() = default;
57 void initOrIncrementId();
58
59 QOhosOptional<InsertedTextId> m_id;
60};
61
62QOhosInsertedText::QOhosInsertedText(const std::string &text, const InsertedTextId &id)
63 : m_id(id)
64 , m_text(text)
65{}
66
67InsertedTextId QOhosInsertedText::id() const
68{
69 return m_id;
70}
71
72std::string QOhosInsertedText::text() const
73{
74 return m_text;
75}
76
82
87
88void JsInputMethodInsertedTextComposer::initOrIncrementId()
89{
90 if (!m_id.has_value()) {
91 m_id = InsertedTextId(0);
92 } else {
93 auto oldValue = m_id.value().value();
94 m_id = InsertedTextId(++oldValue);
95 }
96}
97
99{
100 initOrIncrementId();
101 return QOhosInsertedText(text, m_id.value());
102}
103
105{
106 using TextInputType = ::InputMethod_TextInputType;
107 if (hints & Qt::ImhMultiLine) {
108 return TextInputType::IME_TEXT_INPUT_TYPE_MULTILINE;
109 } else if (hints & Qt::ImhDigitsOnly) {
110 return (hints & Qt::ImhHiddenText)
111 ? TextInputType::IME_TEXT_INPUT_TYPE_NUMBER_PASSWORD
112 : TextInputType::IME_TEXT_INPUT_TYPE_NUMBER;
113 } else if (hints & Qt::ImhDialableCharactersOnly) {
114 return TextInputType::IME_TEXT_INPUT_TYPE_PHONE;
115 } else if (hints & (Qt::ImhDate | Qt::ImhTime)) {
116 return TextInputType::IME_TEXT_INPUT_TYPE_DATETIME;
117 } else if (hints & Qt::ImhEmailCharactersOnly) {
118 return TextInputType::IME_TEXT_INPUT_TYPE_EMAIL_ADDRESS;
119 } else if (hints & Qt::ImhUrlCharactersOnly) {
120 return TextInputType::IME_TEXT_INPUT_TYPE_URL;
121 } else if (hints & Qt::ImhHiddenText) {
122 return TextInputType::IME_TEXT_INPUT_TYPE_VISIBLE_PASSWORD;
123 } else {
124 return TextInputType::IME_TEXT_INPUT_TYPE_TEXT;
125 }
126}
127
129{
130 switch (direction) {
131 case ::InputMethod_Direction::IME_DIRECTION_NONE:
133 case ::InputMethod_Direction::IME_DIRECTION_UP:
134 return makeQOhosOptional(QOhosInputContext::Direction::CURSOR_UP);
135 case ::InputMethod_Direction::IME_DIRECTION_DOWN:
136 return makeQOhosOptional(QOhosInputContext::Direction::CURSOR_DOWN);
137 case ::InputMethod_Direction::IME_DIRECTION_LEFT:
138 return makeQOhosOptional(QOhosInputContext::Direction::CURSOR_LEFT);
139 case ::InputMethod_Direction::IME_DIRECTION_RIGHT:
140 return makeQOhosOptional(QOhosInputContext::Direction::CURSOR_RIGHT);
141 }
143}
144
145::InputMethod_EnterKeyType mapQtToOhosImeEnterKeyType(Qt::EnterKeyType qtEnterKeyType)
146{
147 switch (qtEnterKeyType) {
148 case Qt::EnterKeyType::EnterKeyReturn:
149 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_NEWLINE;
150 case Qt::EnterKeyType::EnterKeyDone:
151 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_DONE;
152 case Qt::EnterKeyType::EnterKeyGo:
153 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_GO;
154 case Qt::EnterKeyType::EnterKeySend:
155 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_SEND;
156 case Qt::EnterKeyType::EnterKeySearch:
157 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_SEARCH;
158 case Qt::EnterKeyType::EnterKeyNext:
159 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_NEXT;
160 case Qt::EnterKeyType::EnterKeyPrevious:
161 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_PREVIOUS;
162 case Qt::EnterKeyType::EnterKeyDefault:
163 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_NONE;
164 }
165 qOhosPrintfError(
166 "%s: Cannot map Qt::EnterKeyType to OHOS value. Returning ::InputMethod_EnterKeyType::IME_ENTER_KEY_UNSPECIFIED",
167 Q_FUNC_INFO);
168 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_UNSPECIFIED;
169}
170
172 QOhosInputContext::RequestKeyboardReason qtRequestKeyboardReason)
173{
174 switch (qtRequestKeyboardReason) {
175 case QOhosInputContext::RequestKeyboardReason::NONE:
176 return ::InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_NONE;
177 case QOhosInputContext::RequestKeyboardReason::MOUSE:
178 return ::InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_MOUSE;
179 case QOhosInputContext::RequestKeyboardReason::TOUCH:
180 return ::InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_TOUCH;
181 case QOhosInputContext::RequestKeyboardReason::OTHER:
182 return ::InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_OTHER;
183 }
184 qOhosPrintfError(
185 "%s: Cannot map QOhosInputContext::RequestKeyboardReason to OHOS value. Returning ::InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_NONE",
186 Q_FUNC_INFO);
187 return ::InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_NONE;
188}
189
190QOhosOptional<int> tryGetIntPropertyFromQuery(Qt::InputMethodQuery property, QSharedPointer<QInputMethodQueryEvent> query)
191{
192 bool converted;
193 const auto value = query->value(property).toInt(&converted);
194 return converted ? makeQOhosOptional(value) : makeEmptyQOhosOptional();
195}
196
197void notifyOhosInputMethodAboutPossibleAutocorrection(const QOhosInsertedText &insertedText, int cursorPosition)
198{
199 auto lastInsertedTextId = JsInputMethodInsertedTextComposer::instance().lastId();
200 if (!lastInsertedTextId.has_value()) {
201 qOhosPrintfError("%s: JsInputMethodInsertedTextComposer has no last inserted text ID", Q_FUNC_INFO);
202 return;
203 }
204
205 auto currentInsertedTextId = insertedText.id();
206 if (currentInsertedTextId != lastInsertedTextId.value()) {
207 qOhosPrintfWarning(
208 "%s: inserted text and one currently processed differ from each other, system won't be notified with changeSelection()", Q_FUNC_INFO);
209 return;
210 }
211
213 [&](QtOhos::JsState &jsState, QOhosTaskPromise<> taskPromise) {
214 auto startPosition = cursorPosition;
215 auto endPosition = cursorPosition + insertedText.text().length();
216 jsState.evalToPromiseOrRejectOnThrow(
217 "@ohos.inputMethod.getController().changeSelection(*)", {insertedText.text(), startPosition, endPosition})
218 .onCatch(QtOhos::makeErrorLoggingJsCallback("changeSelection()"))
219 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
220 },
221 Q_FUNC_INFO);
222}
223
224inline QPoint clampToRect(const QPoint &p, const QRect &rect)
225{
226 int x = qBound(rect.left(), p.x(), rect.right());
227 int y = qBound(rect.top(), p.y(), rect.bottom());
228 return QPoint(x, y);
229}
230
231}
232
235 , m_lastCursorRectangle(0, 0, 0, 0)
236 , m_qtImEnabled(false)
242{
243 auto __dbg = make_QCScopedDebug("QOhosInputContext::QOhosInputContext");
244
245 QObject::connect(
246 QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged,
247 this, &QOhosInputContext::onCursorRectangleChanged);
248
249 QGuiApplication::instance()->installEventFilter(this);
250}
251
253
255{
256 if (m_imConnectionState == ImConnectionState::Attached) {
257 setImConnectionState(ImConnectionState::Detached);
258 setImConnectionState(ImConnectionState::Attached);
259 }
260}
261
263{
264 auto __dbg = make_QCScopedDebug("QOhosInputContext::commit");
265
266 auto preeditText = std::exchange(m_pendingPreeditText, {});
267
268 QInputMethodEvent event;
269 event.setCommitString(preeditText);
270 sendFocusObjectInputMethodEvent(&event);
271}
272
273void QOhosInputContext::update(Qt::InputMethodQueries queries)
274{
275 if (!focusObjectOrNull()) {
277 return;
278 }
279
280 m_qtImEnabled = queryImEnabled();
281 const auto qtInputMethodHintsValue = queryInputMethodHints();
282 const auto qtEnterKeyTypeValue = queryEnterKeyType();
283
284 const bool imStateChanged =
285 m_qtInputMethodHints != qtInputMethodHintsValue
286 || m_qtEnterKeyType != qtEnterKeyTypeValue;
287
288 auto imAlreadyAttached = m_imConnectionState == ImConnectionState::Attached;
289 if (imAlreadyAttached && imStateChanged)
290 updateInputMethodControllerAttributes(qtInputMethodHintsValue, qtEnterKeyTypeValue);
291
292 m_qtInputMethodHints = qtInputMethodHintsValue;
293 m_qtEnterKeyType = qtEnterKeyTypeValue;
294
295 if (inputMethodAccepted() && m_qtImEnabled) {
296 auto updateCausedByWidgetTransform = queries == Qt::ImInputItemClipRectangle;
297 auto updateCausedByQueryAllImParameters = queries == Qt::ImQueryAll;
298
299 if (updateCausedByQueryAllImParameters)
300 return;
301
302 if (!updateCausedByWidgetTransform || !imAlreadyAttached) {
304 }
305 } else {
307 }
308}
309
311{
312 auto __dbg = make_QCScopedDebug("QOhosInputContext::invokeAction");
313}
314
316{
317 auto __dbg = make_QCScopedDebug("QOhosInputContext::keyboardRect");
318 return {};
319}
320
322{
323 auto __dbg = make_QCScopedDebug("QOhosInputContext::isAnimating");
324 return {};
325}
326
328{
329 auto __dbg = make_QCScopedDebug("QOhosInputContext::showInputPanel");
330 setImConnectionState(ImConnectionState::Attached);
331}
332
334{
335 auto __dbg = make_QCScopedDebug("QOhosInputContext::hideInputPanel");
336 setImConnectionState(ImConnectionState::Detached);
337}
338
340{
341 auto __dbg = make_QCScopedDebug("QOhosInputContext::isInputPanelVisible");
342 return m_imConnectionRequestedState == ImConnectionState::Attached;
343}
344
345void QOhosInputContext::setFocusObject(QObject *object)
346{
347 m_focusObject = object;
348}
349
351{
352 return m_focusObject;
353}
354
355void QOhosInputContext::setImConnectionState(ImConnectionState requestedState)
356{
357 if (requestedState != m_imConnectionRequestedState) {
358 setImConnectionStateImpl(requestedState);
359 } else {
360 if (m_imConnectionState == ImConnectionState::Attached && !m_softwareKeyboardVisible)
361 showTextInput();
362 }
363}
364
365void QOhosInputContext::setImConnectionStateImpl(ImConnectionState requestedState)
366{
367 m_imConnectionRequestedState = m_qtImEnabled ? requestedState : ImConnectionState::Detached;
368
369 if (!m_imConnectionRequestActive) {
370 m_imConnectionRequestActive = true;
371
372 dispatchRequestedImStateChange(requestedState);
373 }
374}
375
376void QOhosInputContext::dispatchRequestedImStateChange(ImConnectionState requestedState)
377{
378 auto result = false;
379 if (requestedState == ImConnectionState::Attached)
380 result = attachToInputMethodController();
381 else
382 result = detachFromInputMethodController();
383 handleRequestedImConnectionState(requestedState, result);
384}
385
386bool QOhosInputContext::attachToInputMethodController()
387{
388 class ImCallbacks : public QOhosInputMethodProxy::ClientCallbacks
389 {
390 public:
391 ImCallbacks(QOhosInputContext &inputContext)
392 : m_inputContext(inputContext)
393 {
394 }
395
396 private:
397 void onInsertText(std::string text) override
398 {
399 m_inputContext.sendInsertedTextToQt(std::move(text));
400 }
401
402 void onInsertPreviewText(std::string previewText) override
403 {
404 m_inputContext.sendInsertedPreviewTextToQt(std::move(previewText));
405 }
406
407 void onFinishPreviewText() override
408 {
409 m_inputContext.commit();
410 }
411
412 void onDeleteForward(int length) override
413 {
414 m_inputContext.sendFocusObjectFunctionalKeyEvent(Qt::Key_Delete, QChar::fromLatin1('\u007F'), length);
415 }
416
417 void onDeleteBackward(int length) override
418 {
419 m_inputContext.sendFocusObjectFunctionalKeyEvent(Qt::Key_Backspace, QChar::fromLatin1('\u0008'), length);
420 }
421
422 void onSendKeyboardStatus(::InputMethod_KeyboardStatus keyboardStatus) override
423 {
424 bool ohosKeyboardShown = keyboardStatus == ::InputMethod_KeyboardStatus::IME_KEYBOARD_STATUS_SHOW;
425 m_inputContext.setSoftwareKeyboardVisibilityStatus(ohosKeyboardShown);
426 }
427
428 void onSendEnterKey(::InputMethod_EnterKeyType) override
429 {
430 m_inputContext.sendFocusObjectFunctionalKeyEvent(Qt::Key_Enter, QChar::fromLatin1('\u000D'));
431 }
432
433 void onMoveCursor(::InputMethod_Direction direction) override
434 {
435 auto qtDirection = tryMapInputMethodDirectionToQt(direction);
436 if (!qtDirection.has_value()) {
437 qOhosPrintfWarning(
438 "got unsupported InputMethod_Direction value (%d), cursor won't be moved!",
439 static_cast<int>(direction));
440 return;
441 }
442
443 m_inputContext.sendCursorMoveToQt(qtDirection.value());
444 }
445
446 QOhosInputContext &m_inputContext;
447 };
448
449 if (m_imProxy)
450 qOhosPrintfWarning("%s: proxy already exists!", Q_FUNC_INFO);
451
452 m_imProxy = std::make_shared<QOhosInputMethodProxy>(
453 std::make_shared<ImCallbacks>(*this),
454 mapQtToOhosImeRequestReason(
455 m_lastInputTypeToTriggerSoftKeyboard.value_or(RequestKeyboardReason::OTHER)));
456
457 if (m_imProxy->hasAttachedSuccessfully()) {
458 m_imProxy->notifyConfigurationChange(
459 mapQtToOhosImeEnterKeyType(m_qtEnterKeyType),
460 mapQtInputMethodHintsToOhosImeTextInputType(m_qtInputMethodHints));
461 return true;
462 }
463 return false;
464}
465
466bool QOhosInputContext::detachFromInputMethodController()
467{
468 if (!m_imProxy)
469 qOhosPrintfWarning("%s: proxy doesn't exist!", Q_FUNC_INFO);
470
471 m_imProxy.reset();
472 return true;
473}
474
475void QOhosInputContext::handleRequestedImConnectionState(ImConnectionState requestedState, bool success)
476{
477 m_imConnectionRequestActive = false;
478
479 if (!success) {
480 qOhosWarning(QtForOhos)
481 << "Cannot "
482 << (requestedState == ImConnectionState::Attached ? "attach to" : "detach from")
483 << " IMC!";
484 return;
485 }
486
487 m_imConnectionState = requestedState;
488
489 if (m_imConnectionRequestedState != m_imConnectionState)
490 setImConnectionStateImpl(m_imConnectionRequestedState);
491
492 onCursorRectangleChanged();
493}
494
495void QOhosInputContext::showTextInput()
496{
497 if (m_imProxy == nullptr) {
498 qOhosPrintfError("%s: proxy doesn't exist!", Q_FUNC_INFO);
499 return;
500 }
501
502 m_imProxy->showTextInput(mapQtToOhosImeRequestReason(
503 m_lastInputTypeToTriggerSoftKeyboard.value_or(RequestKeyboardReason::OTHER)));
504}
505
507{
508 m_softwareKeyboardVisible = visible;
509}
510
511void QOhosInputContext::setLastInputTypeToTriggerSoftKeyboard(RequestKeyboardReason inputType)
512{
513 m_lastInputTypeToTriggerSoftKeyboard = inputType;
514}
515
516void QOhosInputContext::onCursorRectangleChanged()
517{
518 if (m_imConnectionState == ImConnectionState::Detached) {
519 qOhosDebug(QtForOhos) << "Cursor rectangle changed while detached; deferring update until attach";
520 m_updateCursorRectangleAfterAttaching = true;
521 return;
522 }
523
524 auto *focusedWindow = QGuiApplication::focusWindow();
525 if (focusedWindow == nullptr) {
526 qOhosCritical(QtForOhos)
527 << "Could not retrieve focused window. Updating cursor position isn't possible";
528 return;
529 }
530
531 auto focusedWindowPosition = focusedWindow->position();
532 QRect cursorRectangle = QGuiApplication::inputMethod()->cursorRectangle().toRect();
533 if (!m_updateCursorRectangleAfterAttaching
534 && cursorRectangle == m_lastCursorRectangle
535 && m_lastFocusedWindowPosition == focusedWindowPosition) {
536 return;
537 }
538
539 m_lastCursorRectangle = cursorRectangle;
540 m_lastFocusedWindowPosition = focusedWindowPosition;
541 auto globalInputItemRectangle =
542 QGuiApplication::inputMethod()->inputItemClipRectangle()
543 .translated(m_lastFocusedWindowPosition)
544 .toRect();
545 auto globalCursorRectangle = m_lastCursorRectangle.translated(m_lastFocusedWindowPosition);
546 auto inputItemClampedCursorPos = clampToRect(
547 {globalCursorRectangle.x(), globalCursorRectangle.y()},
548 globalInputItemRectangle.isValid()
549 ? globalInputItemRectangle
550 : focusedWindow->geometry());
551 auto nativeCursorPos = QHighDpiScaling::mapPositionToNative(
552 inputItemClampedCursorPos, focusedWindow->screen()->handle());
553 auto screenBasedCursorPos = nativeCursorPos - focusedWindow->screen()->handle()->geometry().topLeft();
554 updateOhosCursor({
555 screenBasedCursorPos.x(), screenBasedCursorPos.y(),
556 globalCursorRectangle.width(), globalCursorRectangle.height()
557 });
558 m_updateCursorRectangleAfterAttaching = false;
559}
560
561void QOhosInputContext::updateInputMethodControllerAttributes(
562 Qt::InputMethodHints qtInputMethodHints, Qt::EnterKeyType qtEnterKeyType)
563{
564 if (m_imProxy == nullptr) {
565 qOhosPrintfError("%s: proxy doesn't exist!", Q_FUNC_INFO);
566 return;
567 }
568
569 m_imProxy->notifyConfigurationChange(
570 mapQtToOhosImeEnterKeyType(qtEnterKeyType),
571 mapQtInputMethodHintsToOhosImeTextInputType(qtInputMethodHints));
572}
573
574void QOhosInputContext::updateOhosCursor(const QRect &globalCursorRect)
575{
576 if (m_imProxy == nullptr) {
577 qOhosPrintfError("%s: proxy doesn't exist!", Q_FUNC_INFO);
578 return;
579 }
580
581 m_imProxy->notifyCursorUpdate(globalCursorRect);
582}
583
584void QOhosInputContext::handleFocusInEvent(QObject *obj, QFocusEvent *event)
585{
586 if (obj->isWidgetType() && queryImEnabled()) {
587 auto focusReason = event->reason();
588 if (focusReason == Qt::OtherFocusReason || focusReason == Qt::ActiveWindowFocusReason)
589 setLastInputTypeToTriggerSoftKeyboard(RequestKeyboardReason::NONE);
590 }
591}
592
593bool QOhosInputContext::eventFilter(QObject *obj, QEvent *event)
594{
595 if (event->type() == QEvent::FocusIn)
596 handleFocusInEvent(obj, static_cast<QFocusEvent *>(event));
597 return false;
598}
599
600void QOhosInputContext::sendInsertedTextToQt(const std::string &textToInsert)
601{
603
604 auto query = tryQueryFocusObjectInputMethod(Qt::ImEnabled);
605 if (query.isNull())
606 return;
607
608 if (!query->value(Qt::ImEnabled).toBool()) {
609 qOhosDebug(QtForOhos) << "onInsertText(): focus object is not able to handle InputMethod";
610 return;
611 }
612
613 m_pendingPreeditText.clear();
614
615 QInputMethodEvent event;
616 event.setCommitString(QString::fromStdString(insertedText.text()));
617 sendFocusObjectInputMethodEvent(&event);
618
619 auto cursorPosition = tryQueryCursorPosition();
620 if (cursorPosition.has_value())
621 notifyOhosInputMethodAboutPossibleAutocorrection(insertedText, cursorPosition.value());
622 else
623 qOhosWarning(QtForOhos) << "Couldn't obtain IM cursorPosition";
624}
625
626void QOhosInputContext::sendInsertedPreviewTextToQt(std::string previewText)
627{
628 auto query = tryQueryFocusObjectInputMethod(Qt::ImEnabled);
629 if (query.isNull())
630 return;
631
632 if (!query->value(Qt::ImEnabled).toBool()) {
633 qOhosPrintfDebug("%s: focus object is not able to handle InputMethod", Q_FUNC_INFO);
634 return;
635 }
636
637 const QString previewString = QString::fromStdString(previewText);
638 QList<QInputMethodEvent::Attribute> imEventAttributes;
639 if (!previewString.isEmpty()) {
640 QTextCharFormat format;
641 format.setFontUnderline(true);
642 imEventAttributes.append(
643 QInputMethodEvent::Attribute(
644 QInputMethodEvent::TextFormat, 0, previewString.length(), format));
645 }
646
647 m_pendingPreeditText = previewString;
648
649 QInputMethodEvent preeditStringEvent(previewString, imEventAttributes);
650 sendFocusObjectInputMethodEvent(&preeditStringEvent);
651}
652
653void QOhosInputContext::sendFocusObjectInputMethodEvent(QInputMethodEvent *event)
654{
655 auto *focusObject = focusObjectOrNull();
656 if (focusObject == nullptr) {
657 qOhosWarning(QtForOhos) << "sendFocusObjectInputMethodEvent(): no focus object to send event to!";
658 return;
659 }
660
661 QCoreApplication::sendEvent(focusObject, event);
662}
663
664void QOhosInputContext::sendCursorMoveToQt(QOhosInputContext::Direction direction)
665{
666 switch (direction) {
667 case QOhosInputContext::Direction::CURSOR_UP:
668 sendFocusObjectFunctionalKeyEvent(Qt::Key_Up, QChar(std::int32_t(Qt::Key_Up)));
669 break;
670 case QOhosInputContext::Direction::CURSOR_DOWN:
671 sendFocusObjectFunctionalKeyEvent(Qt::Key_Down, QChar(std::int32_t(Qt::Key_Down)));
672 break;
673 case QOhosInputContext::Direction::CURSOR_LEFT:
674 sendFocusObjectFunctionalKeyEvent(Qt::Key_Left, QChar(std::int32_t(Qt::Key_Left)));
675 break;
676 case QOhosInputContext::Direction::CURSOR_RIGHT:
677 sendFocusObjectFunctionalKeyEvent(Qt::Key_Right, QChar(std::int32_t(Qt::Key_Right)));
678 break;
679 }
680}
681
682void QOhosInputContext::sendFocusObjectFunctionalKeyEvent(Qt::Key key, const QChar &keyChar, int repeatCount)
683{
684 auto *focusObject = focusObjectOrNull();
685 if (focusObject == nullptr) {
686 qOhosWarning(QtForOhos) << "sendFocusObjectFunctionalKeyEvent(): no focus object to send event to!";
687 return;
688 }
689
690 for (int i = 0; i < repeatCount; ++i) {
691 QGuiApplication::postEvent(focusObject, new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier, QString(keyChar)));
692 QGuiApplication::postEvent(focusObject, new QKeyEvent(QEvent::KeyRelease, key, Qt::NoModifier, QString(keyChar)));
693 }
694}
695
696bool QOhosInputContext::queryImEnabled() const
697{
698 auto query = tryQueryFocusObjectInputMethod(Qt::ImEnabled);
699 return !query.isNull() && query->value(Qt::ImEnabled).toBool();
700}
701
702Qt::InputMethodHints QOhosInputContext::queryInputMethodHints() const
703{
704 QOhosOptional<Qt::InputMethodHints> hints;
705 auto query = tryQueryFocusObjectInputMethod(Qt::ImHints);
706 if (!query.isNull()) {
707 auto imHintsInt = tryGetIntPropertyFromQuery(Qt::ImHints, query);
708 if (imHintsInt.has_value())
709 hints = static_cast<Qt::InputMethodHints>(imHintsInt.value());
710 }
711
712 return hints.value_or(defaultInputMethodHints);
713}
714
715Qt::EnterKeyType QOhosInputContext::queryEnterKeyType() const
716{
717 QOhosOptional<Qt::EnterKeyType> enterKeyType;
718 auto query = tryQueryFocusObjectInputMethod(Qt::ImEnterKeyType);
719 if (!query.isNull()) {
720 auto imEnterKeyTypeInt = tryGetIntPropertyFromQuery(Qt::ImEnterKeyType, query);
721 if (imEnterKeyTypeInt.has_value())
722 enterKeyType = static_cast<Qt::EnterKeyType>(imEnterKeyTypeInt.value());
723 }
724
725 return enterKeyType.value_or(defaultEnterKeyType);
726}
727
728QOhosOptional<int> QOhosInputContext::tryQueryCursorPosition() const
729{
730 auto query = tryQueryFocusObjectInputMethod(Qt::ImCursorPosition);
731 return !query.isNull()
732 ? tryGetIntPropertyFromQuery(Qt::ImCursorPosition, query)
733 : makeEmptyQOhosOptional();
734}
735
736QSharedPointer<QInputMethodQueryEvent> QOhosInputContext::tryQueryFocusObjectInputMethod(Qt::InputMethodQueries queries) const
737{
738 auto *focusObject = focusObjectOrNull();
739 if (focusObject == nullptr) {
740 qOhosWarning(QtForOhos) << "tryQueryFocusObjectInputMethod(): no focus object to query information from!";
741 return {};
742 }
743
744 auto imqEvent = QSharedPointer<QInputMethodQueryEvent>::create(queries);
745 QCoreApplication::sendEvent(focusObject, imqEvent.data());
746 return imqEvent;
747}
748
749QT_END_NAMESPACE
void update(Qt::InputMethodQueries queries) override
Notification on editor updates.
QRectF keyboardRect() const override
This function can be reimplemented to return virtual keyboard rectangle in currently active window co...
void setSoftwareKeyboardVisibilityStatus(bool visible)
void showInputPanel() override
Request to show input panel.
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 setLastInputTypeToTriggerSoftKeyboard(RequestKeyboardReason inputType)
void reset() override
Method to be called when input method needs to be reset.
void hideInputPanel() override
Request to hide input panel.
bool eventFilter(QObject *obj, QEvent *event) override
Filters events if this object has been installed as an event filter for the watched object.
bool isInputPanelVisible() const override
Returns input panel visibility status.
QObject * focusObjectOrNull() const
void setFocusObject(QObject *object) override
This virtual method gets called to notify updated focus to object.
bool isAnimating() const override
This function can be reimplemented to return true whenever input method is animating shown or hidden.
QtOhos::enums::ohos::inputMethod::Direction Direction
JsInputMethodInsertedTextComposer & operator=(const JsInputMethodInsertedTextComposer &)=delete
JsInputMethodInsertedTextComposer(JsInputMethodInsertedTextComposer &&)=delete
static JsInputMethodInsertedTextComposer & instance()
JsInputMethodInsertedTextComposer & operator=(JsInputMethodInsertedTextComposer &&)=delete
QOhosOptional< InsertedTextId > lastId() const
JsInputMethodInsertedTextComposer(const JsInputMethodInsertedTextComposer &)=delete
QOhosInsertedText makeInsertedText(const std::string &text)
QOhosInsertedText(const std::string &text, const InsertedTextId &id)
Combined button and popup list for selecting options.
QOhosOptional< QOhosInputContext::Direction > tryMapInputMethodDirectionToQt(::InputMethod_Direction direction)
::InputMethod_TextInputType mapQtInputMethodHintsToOhosImeTextInputType(Qt::InputMethodHints hints)
::InputMethod_EnterKeyType mapQtToOhosImeEnterKeyType(Qt::EnterKeyType qtEnterKeyType)
const Qt::EnterKeyType defaultEnterKeyType
void notifyOhosInputMethodAboutPossibleAutocorrection(const QOhosInsertedText &insertedText, int cursorPosition)
const Qt::InputMethodHints defaultInputMethodHints
QPoint clampToRect(const QPoint &p, const QRect &rect)
::InputMethod_RequestKeyboardReason mapQtToOhosImeRequestReason(QOhosInputContext::RequestKeyboardReason qtRequestKeyboardReason)
QOhosOptional< int > tryGetIntPropertyFromQuery(Qt::InputMethodQuery property, QSharedPointer< QInputMethodQueryEvent > query)
void invokeInJsThreadAndWaitForContinue(std::function< void(JsState &, QOhosTaskPromise<>)> &&task, std::string callerContextName={})
std::nullopt_t makeEmptyQOhosOptional()