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
52 QOhosOptional<InsertedTextId> lastId() const;
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
84{
85 return m_id;
86}
87
88void JsInputMethodInsertedTextComposer::initOrIncrementId()
89{
90 if (!m_id.hasValue()) {
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.hasValue()) {
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, std::function<void()> continueFunc) {
214 auto startPosition = cursorPosition;
215 auto endPosition = cursorPosition + insertedText.text().length();
216 jsState.eval<QNapi::Promise>(
217 "@ohos.inputMethod.getController().changeSelection(*)", {insertedText.text(), startPosition, endPosition})
218 .onCatch(QtOhos::makeErrorLoggingJsCallback("changeSelection()"))
219 .onFinally(std::move(continueFunc));
220 });
221}
222
223inline QPoint clampToRect(const QPoint &p, const QRect &rect)
224{
225 int x = qBound(rect.left(), p.x(), rect.right());
226 int y = qBound(rect.top(), p.y(), rect.bottom());
227 return QPoint(x, y);
228}
229
230}
231
234 , m_lastCursorRectangle(0, 0, 0, 0)
235 , m_qtImEnabled(false)
241{
242 auto __dbg = make_QCScopedDebug("QOhosInputContext::QOhosInputContext");
243
244 QObject::connect(
245 QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged,
246 this, &QOhosInputContext::onCursorRectangleChanged);
247
248 QGuiApplication::instance()->installEventFilter(this);
249}
250
252
254{
255 if (m_imConnectionState == ImConnectionState::Attached) {
256 setImConnectionState(ImConnectionState::Detached);
257 setImConnectionState(ImConnectionState::Attached);
258 }
259}
260
262{
263 auto __dbg = make_QCScopedDebug("QOhosInputContext::commit");
264
265 auto preeditText = std::exchange(m_pendingPreeditText, {});
266
267 QInputMethodEvent event;
268 event.setCommitString(preeditText);
269 sendFocusObjectInputMethodEvent(&event);
270}
271
272void QOhosInputContext::update(Qt::InputMethodQueries queries)
273{
274 m_qtImEnabled = queryImEnabled();
275 const auto qtInputMethodHintsValue = queryInputMethodHints();
276 const auto qtEnterKeyTypeValue = queryEnterKeyType();
277
278 const bool imStateChanged =
279 m_qtInputMethodHints != qtInputMethodHintsValue
280 || m_qtEnterKeyType != qtEnterKeyTypeValue;
281
282 auto imAlreadyAttached = m_imConnectionState == ImConnectionState::Attached;
283 if (imAlreadyAttached && imStateChanged)
284 updateInputMethodControllerAttributes(qtInputMethodHintsValue, qtEnterKeyTypeValue);
285
286 m_qtInputMethodHints = qtInputMethodHintsValue;
287 m_qtEnterKeyType = qtEnterKeyTypeValue;
288
289 if (inputMethodAccepted() && m_qtImEnabled) {
290 auto updateCausedByWidgetTransform = queries == Qt::ImInputItemClipRectangle;
291 auto updateCausedByQueryAllImParameters = queries == Qt::ImQueryAll;
292
293 if (updateCausedByQueryAllImParameters)
294 return;
295
296 if (!updateCausedByWidgetTransform || !imAlreadyAttached) {
298 }
299 } else {
301 }
302}
303
305{
306 auto __dbg = make_QCScopedDebug("QOhosInputContext::invokeAction");
307}
308
310{
311 auto __dbg = make_QCScopedDebug("QOhosInputContext::keyboardRect");
312 return {};
313}
314
316{
317 auto __dbg = make_QCScopedDebug("QOhosInputContext::isAnimating");
318 return {};
319}
320
322{
323 auto __dbg = make_QCScopedDebug("QOhosInputContext::showInputPanel");
324 setImConnectionState(ImConnectionState::Attached);
325}
326
328{
329 auto __dbg = make_QCScopedDebug("QOhosInputContext::hideInputPanel");
330 setImConnectionState(ImConnectionState::Detached);
331}
332
334{
335 auto __dbg = make_QCScopedDebug("QOhosInputContext::isInputPanelVisible");
336 return m_imConnectionRequestedState == ImConnectionState::Attached;
337}
338
339void QOhosInputContext::setFocusObject(QObject *object)
340{
341 m_focusObject = object;
342}
343
345{
346 return m_focusObject;
347}
348
349void QOhosInputContext::setImConnectionState(ImConnectionState requestedState)
350{
351 if (requestedState != m_imConnectionRequestedState) {
352 setImConnectionStateImpl(requestedState);
353 } else {
354 if (m_imConnectionState == ImConnectionState::Attached && !m_softwareKeyboardVisible)
355 showTextInput();
356 }
357}
358
359void QOhosInputContext::setImConnectionStateImpl(ImConnectionState requestedState)
360{
361 m_imConnectionRequestedState = m_qtImEnabled ? requestedState : ImConnectionState::Detached;
362
363 if (!m_imConnectionRequestActive) {
364 m_imConnectionRequestActive = true;
365
366 dispatchRequestedImStateChange(requestedState);
367 }
368}
369
370void QOhosInputContext::dispatchRequestedImStateChange(ImConnectionState requestedState)
371{
372 auto result = false;
373 if (requestedState == ImConnectionState::Attached)
374 result = attachToInputMethodController();
375 else
376 result = detachFromInputMethodController();
377 handleRequestedImConnectionState(requestedState, result);
378}
379
380bool QOhosInputContext::attachToInputMethodController()
381{
382 class ImCallbacks : public QOhosInputMethodProxy::ClientCallbacks
383 {
384 public:
385 ImCallbacks(QOhosInputContext &inputContext)
386 : m_inputContext(inputContext)
387 {
388 }
389
390 private:
391 void onInsertText(std::string text) override
392 {
393 m_inputContext.sendInsertedTextToQt(std::move(text));
394 }
395
396 void onInsertPreviewText(std::string previewText) override
397 {
398 m_inputContext.sendInsertedPreviewTextToQt(std::move(previewText));
399 }
400
401 void onDeleteForward(int length) override
402 {
403 m_inputContext.sendFocusObjectFunctionalKeyEvent(Qt::Key_Delete, QChar::fromLatin1('\u007F'), length);
404 }
405
406 void onDeleteBackward(int length) override
407 {
408 m_inputContext.sendFocusObjectFunctionalKeyEvent(Qt::Key_Backspace, QChar::fromLatin1('\u0008'), length);
409 }
410
411 void onSendKeyboardStatus(::InputMethod_KeyboardStatus keyboardStatus) override
412 {
413 bool ohosKeyboardShown = keyboardStatus == ::InputMethod_KeyboardStatus::IME_KEYBOARD_STATUS_SHOW;
414 m_inputContext.setSoftwareKeyboardVisibilityStatus(ohosKeyboardShown);
415 }
416
417 void onSendEnterKey(::InputMethod_EnterKeyType) override
418 {
419 m_inputContext.sendFocusObjectFunctionalKeyEvent(Qt::Key_Enter, QChar::fromLatin1('\u000D'));
420 }
421
422 void onMoveCursor(::InputMethod_Direction direction) override
423 {
424 auto qtDirection = tryMapInputMethodDirectionToQt(direction);
425 if (!qtDirection.hasValue()) {
426 qOhosPrintfWarning(
427 "got unsupported InputMethod_Direction value (%d), cursor won't be moved!",
428 static_cast<int>(direction));
429 return;
430 }
431
432 m_inputContext.sendCursorMoveToQt(qtDirection.value());
433 }
434
435 QOhosInputContext &m_inputContext;
436 };
437
438 if (m_imProxy)
439 qOhosPrintfWarning("%s: proxy already exists!", Q_FUNC_INFO);
440
441 m_imProxy = std::make_shared<QOhosInputMethodProxy>(
442 std::make_shared<ImCallbacks>(*this),
443 mapQtToOhosImeRequestReason(
444 m_lastInputTypeToTriggerSoftKeyboard.valueOr(RequestKeyboardReason::OTHER)));
445
446 if (m_imProxy->hasAttachedSuccessfully()) {
447 m_imProxy->notifyConfigurationChange(
448 mapQtToOhosImeEnterKeyType(m_qtEnterKeyType),
449 mapQtInputMethodHintsToOhosImeTextInputType(m_qtInputMethodHints));
450 return true;
451 }
452 return false;
453}
454
455bool QOhosInputContext::detachFromInputMethodController()
456{
457 if (!m_imProxy)
458 qOhosPrintfWarning("%s: proxy doesn't exist!", Q_FUNC_INFO);
459
460 m_imProxy.reset();
461 return true;
462}
463
464void QOhosInputContext::handleRequestedImConnectionState(ImConnectionState requestedState, bool success)
465{
466 m_imConnectionRequestActive = false;
467
468 if (!success) {
469 qOhosWarning(QtForOhos)
470 << "Cannot "
471 << (requestedState == ImConnectionState::Attached ? "attach to" : "detach from")
472 << " IMC!";
473 return;
474 }
475
476 m_imConnectionState = requestedState;
477
478 if (m_imConnectionRequestedState != m_imConnectionState)
479 setImConnectionStateImpl(m_imConnectionRequestedState);
480
481 onCursorRectangleChanged();
482}
483
484void QOhosInputContext::showTextInput()
485{
486 if (m_imProxy == nullptr) {
487 qOhosPrintfError("%s: proxy doesn't exist!", Q_FUNC_INFO);
488 return;
489 }
490
491 m_imProxy->showTextInput(mapQtToOhosImeRequestReason(
492 m_lastInputTypeToTriggerSoftKeyboard.valueOr(RequestKeyboardReason::OTHER)));
493}
494
496{
497 m_softwareKeyboardVisible = visible;
498}
499
500void QOhosInputContext::setLastInputTypeToTriggerSoftKeyboard(RequestKeyboardReason inputType)
501{
502 m_lastInputTypeToTriggerSoftKeyboard = inputType;
503}
504
505void QOhosInputContext::onCursorRectangleChanged()
506{
507 if (m_imConnectionState == ImConnectionState::Detached) {
508 qOhosWarning(QtForOhos) << "Attempting to update cursor position when detached from controller";
509 m_updateCursorRectangleAfterAttaching = true;
510 return;
511 }
512
513 auto *focusedWindow = QGuiApplication::focusWindow();
514 if (focusedWindow == nullptr) {
515 qOhosCritical(QtForOhos)
516 << "Could not retrieve focused window. Updating cursor position isn't possible";
517 return;
518 }
519
520 auto focusedWindowPosition = focusedWindow->position();
521 QRect cursorRectangle = QGuiApplication::inputMethod()->cursorRectangle().toRect();
522 if (!m_updateCursorRectangleAfterAttaching
523 && cursorRectangle == m_lastCursorRectangle
524 && m_lastFocusedWindowPosition == focusedWindowPosition) {
525 return;
526 }
527
528 m_lastCursorRectangle = cursorRectangle;
529 m_lastFocusedWindowPosition = focusedWindowPosition;
530 auto screenSpaceInputItemRectangle =
531 QGuiApplication::inputMethod()->inputItemClipRectangle()
532 .translated(m_lastFocusedWindowPosition)
533 .toRect();
534 auto screenSpaceCursorRectangle = m_lastCursorRectangle.translated(m_lastFocusedWindowPosition);
535 auto inputItemClampedCursorPos = clampToRect(
536 {screenSpaceCursorRectangle.x(), screenSpaceCursorRectangle.y()},
537 screenSpaceInputItemRectangle.isValid()
538 ? screenSpaceInputItemRectangle
539 : focusedWindow->geometry());
540 auto nativeCursorPos = QHighDpiScaling::mapPositionToNative(
541 inputItemClampedCursorPos, focusedWindow->screen()->handle());
542 updateOhosCursor({
543 nativeCursorPos.x(), nativeCursorPos.y(),
544 screenSpaceCursorRectangle.width(), screenSpaceCursorRectangle.height()
545 });
546 m_updateCursorRectangleAfterAttaching = false;
547}
548
549void QOhosInputContext::updateInputMethodControllerAttributes(
550 Qt::InputMethodHints qtInputMethodHints, Qt::EnterKeyType qtEnterKeyType)
551{
552 if (m_imProxy == nullptr) {
553 qOhosPrintfError("%s: proxy doesn't exist!", Q_FUNC_INFO);
554 return;
555 }
556
557 m_imProxy->notifyConfigurationChange(
558 mapQtToOhosImeEnterKeyType(qtEnterKeyType),
559 mapQtInputMethodHintsToOhosImeTextInputType(qtInputMethodHints));
560}
561
562void QOhosInputContext::updateOhosCursor(const QRect &globalCursorRect)
563{
564 if (m_imProxy == nullptr) {
565 qOhosPrintfError("%s: proxy doesn't exist!", Q_FUNC_INFO);
566 return;
567 }
568
569 m_imProxy->notifyCursorUpdate(globalCursorRect);
570}
571
572void QOhosInputContext::handleFocusInEvent(QObject *obj, QFocusEvent *event)
573{
574 if (obj->isWidgetType() && queryImEnabled()) {
575 auto focusReason = event->reason();
576 if (focusReason == Qt::OtherFocusReason || focusReason == Qt::ActiveWindowFocusReason)
577 setLastInputTypeToTriggerSoftKeyboard(RequestKeyboardReason::NONE);
578 }
579}
580
581bool QOhosInputContext::eventFilter(QObject *obj, QEvent *event)
582{
583 if (event->type() == QEvent::FocusIn)
584 handleFocusInEvent(obj, static_cast<QFocusEvent *>(event));
585 return false;
586}
587
588void QOhosInputContext::sendInsertedTextToQt(const std::string &textToInsert)
589{
591
592 auto query = tryQueryFocusObjectInputMethod(Qt::ImEnabled);
593 if (query.isNull())
594 return;
595
596 if (!query->value(Qt::ImEnabled).toBool()) {
597 qOhosDebug(QtForOhos) << "onInsertText(): focus object is not able to handle InputMethod";
598 return;
599 }
600
601 m_pendingPreeditText.clear();
602
603 QInputMethodEvent event;
604 event.setCommitString(QString::fromStdString(insertedText.text()));
605 sendFocusObjectInputMethodEvent(&event);
606
607 auto cursorPosition = tryQueryCursorPosition();
608 if (cursorPosition.hasValue())
609 notifyOhosInputMethodAboutPossibleAutocorrection(insertedText, cursorPosition.value());
610 else
611 qOhosWarning(QtForOhos) << "Couldn't obtain IM cursorPosition";
612}
613
614void QOhosInputContext::sendInsertedPreviewTextToQt(std::string previewText)
615{
616 auto query = tryQueryFocusObjectInputMethod(Qt::ImEnabled);
617 if (query.isNull())
618 return;
619
620 if (!query->value(Qt::ImEnabled).toBool()) {
621 qOhosPrintfDebug("%s: focus object is not able to handle InputMethod", Q_FUNC_INFO);
622 return;
623 }
624
625 const QString previewString = QString::fromStdString(previewText);
626 QList<QInputMethodEvent::Attribute> imEventAttributes;
627 if (!previewString.isEmpty()) {
628 QTextCharFormat format;
629 format.setFontUnderline(true);
630 imEventAttributes.append(
631 QInputMethodEvent::Attribute(
632 QInputMethodEvent::TextFormat, 0, previewString.length(), format));
633 }
634
635 m_pendingPreeditText = previewString;
636
637 QInputMethodEvent preeditStringEvent(previewString, imEventAttributes);
638 sendFocusObjectInputMethodEvent(&preeditStringEvent);
639}
640
641void QOhosInputContext::sendFocusObjectInputMethodEvent(QInputMethodEvent *event)
642{
643 auto *focusObject = focusObjectOrNull();
644 if (focusObject == nullptr) {
645 qOhosWarning(QtForOhos) << "sendFocusObjectInputMethodEvent(): no focus object to send event to!";
646 return;
647 }
648
649 QCoreApplication::sendEvent(focusObject, event);
650}
651
652void QOhosInputContext::sendCursorMoveToQt(QOhosInputContext::Direction direction)
653{
654 switch (direction) {
655 case QOhosInputContext::Direction::CURSOR_UP:
656 sendFocusObjectFunctionalKeyEvent(Qt::Key_Up, QChar(std::int32_t(Qt::Key_Up)));
657 break;
658 case QOhosInputContext::Direction::CURSOR_DOWN:
659 sendFocusObjectFunctionalKeyEvent(Qt::Key_Down, QChar(std::int32_t(Qt::Key_Down)));
660 break;
661 case QOhosInputContext::Direction::CURSOR_LEFT:
662 sendFocusObjectFunctionalKeyEvent(Qt::Key_Left, QChar(std::int32_t(Qt::Key_Left)));
663 break;
664 case QOhosInputContext::Direction::CURSOR_RIGHT:
665 sendFocusObjectFunctionalKeyEvent(Qt::Key_Right, QChar(std::int32_t(Qt::Key_Right)));
666 break;
667 }
668}
669
670void QOhosInputContext::sendFocusObjectFunctionalKeyEvent(Qt::Key key, const QChar &keyChar, int repeatCount)
671{
672 auto *focusObject = focusObjectOrNull();
673 if (focusObject == nullptr) {
674 qOhosWarning(QtForOhos) << "sendFocusObjectFunctionalKeyEvent(): no focus object to send event to!";
675 return;
676 }
677
678 for (int i = 0; i < repeatCount; ++i) {
679 QGuiApplication::postEvent(focusObject, new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier, QString(keyChar)));
680 QGuiApplication::postEvent(focusObject, new QKeyEvent(QEvent::KeyRelease, key, Qt::NoModifier, QString(keyChar)));
681 }
682}
683
684bool QOhosInputContext::queryImEnabled() const
685{
686 auto query = tryQueryFocusObjectInputMethod(Qt::ImEnabled);
687 return !query.isNull() && query->value(Qt::ImEnabled).toBool();
688}
689
690Qt::InputMethodHints QOhosInputContext::queryInputMethodHints() const
691{
692 QOhosOptional<Qt::InputMethodHints> hints;
693 auto query = tryQueryFocusObjectInputMethod(Qt::ImHints);
694 if (!query.isNull()) {
695 auto imHintsInt = tryGetIntPropertyFromQuery(Qt::ImHints, query);
696 if (imHintsInt.hasValue())
697 hints = static_cast<Qt::InputMethodHints>(imHintsInt.value());
698 }
699
700 return hints.valueOr(defaultInputMethodHints);
701}
702
703Qt::EnterKeyType QOhosInputContext::queryEnterKeyType() const
704{
705 QOhosOptional<Qt::EnterKeyType> enterKeyType;
706 auto query = tryQueryFocusObjectInputMethod(Qt::ImEnterKeyType);
707 if (!query.isNull()) {
708 auto imEnterKeyTypeInt = tryGetIntPropertyFromQuery(Qt::ImEnterKeyType, query);
709 if (imEnterKeyTypeInt.hasValue())
710 enterKeyType = static_cast<Qt::EnterKeyType>(imEnterKeyTypeInt.value());
711 }
712
713 return enterKeyType.valueOr(defaultEnterKeyType);
714}
715
716QOhosOptional<int> QOhosInputContext::tryQueryCursorPosition() const
717{
718 auto query = tryQueryFocusObjectInputMethod(Qt::ImCursorPosition);
719 return !query.isNull()
720 ? tryGetIntPropertyFromQuery(Qt::ImCursorPosition, query)
721 : makeEmptyQOhosOptional();
722}
723
724QSharedPointer<QInputMethodQueryEvent> QOhosInputContext::tryQueryFocusObjectInputMethod(Qt::InputMethodQueries queries) const
725{
726 auto *focusObject = focusObjectOrNull();
727 if (focusObject == nullptr) {
728 qOhosWarning(QtForOhos) << "tryQueryFocusObjectInputMethod(): no focus object to query information from!";
729 return {};
730 }
731
732 auto imqEvent = QSharedPointer<QInputMethodQueryEvent>::create(queries);
733 QCoreApplication::sendEvent(focusObject, imqEvent.data());
734 return imqEvent;
735}
736
737QT_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.
std::enable_if_t< qohosplugincore_h_detail::isQOhosOptional< QOhosInvokeResult< Func, T > >, QOhosInvokeResult< Func, T > > andThen(Func &&func) const
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 &, std::function< void()>)> &&task)
QOhosOptional< void > makeEmptyQOhosOptional()