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 <QtCore/qrect.h>
14#include <QtGui/qinputdevice.h>
15#include <QtGui/qguiapplication.h>
16#include <QtGui/qtextformat.h>
17#include <algorithm>
18#include <qohosjsutils.h>
19#include <inputmethod/inputmethod_controller_capi.h>
20
22
23namespace {
24
26const Qt::EnterKeyType defaultEnterKeyType = Qt::EnterKeyDefault;
27
29{
30 using TextInputType = ::InputMethod_TextInputType;
31 if (hints & Qt::ImhMultiLine) {
32 return TextInputType::IME_TEXT_INPUT_TYPE_MULTILINE;
33 } else if (hints & Qt::ImhDigitsOnly) {
34 return (hints & Qt::ImhHiddenText)
35 ? TextInputType::IME_TEXT_INPUT_TYPE_NUMBER_PASSWORD
36 : TextInputType::IME_TEXT_INPUT_TYPE_NUMBER;
37 } else if (hints & Qt::ImhDialableCharactersOnly) {
38 return TextInputType::IME_TEXT_INPUT_TYPE_PHONE;
39 } else if (hints & (Qt::ImhDate | Qt::ImhTime)) {
40 return TextInputType::IME_TEXT_INPUT_TYPE_DATETIME;
41 } else if (hints & Qt::ImhEmailCharactersOnly) {
42 return TextInputType::IME_TEXT_INPUT_TYPE_EMAIL_ADDRESS;
43 } else if (hints & Qt::ImhUrlCharactersOnly) {
44 return TextInputType::IME_TEXT_INPUT_TYPE_URL;
45 } else if (hints & Qt::ImhHiddenText) {
46 return TextInputType::IME_TEXT_INPUT_TYPE_VISIBLE_PASSWORD;
47 } else {
48 return TextInputType::IME_TEXT_INPUT_TYPE_TEXT;
49 }
50}
51
53{
54 switch (direction) {
55 case ::InputMethod_Direction::IME_DIRECTION_NONE:
56 return {};
57 case ::InputMethod_Direction::IME_DIRECTION_UP:
58 return QOhosInputContext::Direction::CURSOR_UP;
59 case ::InputMethod_Direction::IME_DIRECTION_DOWN:
60 return QOhosInputContext::Direction::CURSOR_DOWN;
61 case ::InputMethod_Direction::IME_DIRECTION_LEFT:
62 return QOhosInputContext::Direction::CURSOR_LEFT;
63 case ::InputMethod_Direction::IME_DIRECTION_RIGHT:
64 return QOhosInputContext::Direction::CURSOR_RIGHT;
65 }
66 return {};
67}
68
69::InputMethod_EnterKeyType mapQtToOhosImeEnterKeyType(Qt::EnterKeyType qtEnterKeyType)
70{
71 switch (qtEnterKeyType) {
72 case Qt::EnterKeyType::EnterKeyReturn:
73 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_NEWLINE;
74 case Qt::EnterKeyType::EnterKeyDone:
75 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_DONE;
76 case Qt::EnterKeyType::EnterKeyGo:
77 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_GO;
78 case Qt::EnterKeyType::EnterKeySend:
79 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_SEND;
80 case Qt::EnterKeyType::EnterKeySearch:
81 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_SEARCH;
82 case Qt::EnterKeyType::EnterKeyNext:
83 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_NEXT;
84 case Qt::EnterKeyType::EnterKeyPrevious:
85 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_PREVIOUS;
86 case Qt::EnterKeyType::EnterKeyDefault:
87 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_NONE;
88 }
89 qOhosPrintfError(
90 "%s: Cannot map Qt::EnterKeyType to OHOS value. Returning ::InputMethod_EnterKeyType::IME_ENTER_KEY_UNSPECIFIED",
91 Q_FUNC_INFO);
92 return ::InputMethod_EnterKeyType::IME_ENTER_KEY_UNSPECIFIED;
93}
94
96 QOhosInputContext::RequestKeyboardReason qtRequestKeyboardReason)
97{
98 switch (qtRequestKeyboardReason) {
99 case QOhosInputContext::RequestKeyboardReason::NONE:
100 return ::InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_NONE;
101 case QOhosInputContext::RequestKeyboardReason::MOUSE:
102 return ::InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_MOUSE;
103 case QOhosInputContext::RequestKeyboardReason::TOUCH:
104 return ::InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_TOUCH;
105 case QOhosInputContext::RequestKeyboardReason::OTHER:
106 return ::InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_OTHER;
107 }
108 qOhosPrintfError(
109 "%s: Cannot map QOhosInputContext::RequestKeyboardReason to OHOS value. Returning ::InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_NONE",
110 Q_FUNC_INFO);
111 return ::InputMethod_RequestKeyboardReason::IME_REQUEST_REASON_NONE;
112}
113
114std::optional<int> tryGetIntPropertyFromQuery(Qt::InputMethodQuery property, QSharedPointer<QInputMethodQueryEvent> query)
115{
116 bool converted;
117 const auto value = query->value(property).toInt(&converted);
118 return converted ? std::optional(value) : std::nullopt;
119}
120
121inline QPoint clampToRect(const QPoint &p, const QRect &rect)
122{
123 int x = qBound(rect.left(), p.x(), rect.right());
124 int y = qBound(rect.top(), p.y(), rect.bottom());
125 return QPoint(x, y);
126}
127
129{
130 auto *focusObject = QGuiApplication::focusObject();
131 if (!focusObject)
132 return {};
133
134 QInputMethodQueryEvent directEvent(Qt::ImTextBeforeCursor | Qt::ImTextAfterCursor);
135 QCoreApplication::sendEvent(focusObject, &directEvent);
136
137 const auto textBeforeCursorResult = directEvent.value(Qt::ImTextBeforeCursor);
138 const auto textAfterCursorResult = directEvent.value(Qt::ImTextAfterCursor);
139 if (textBeforeCursorResult.canConvert<QString>() && textAfterCursorResult.canConvert<QString>())
140 return {textBeforeCursorResult.toString(), textAfterCursorResult.toString()};
141
142 QInputMethodQueryEvent fallbackEvent(Qt::ImSurroundingText | Qt::ImCursorPosition);
143 QCoreApplication::sendEvent(focusObject, &fallbackEvent);
144
145 const auto surroundingTextResult = fallbackEvent.value(Qt::ImSurroundingText);
146 const auto cursorPositionResult = fallbackEvent.value(Qt::ImCursorPosition);
147
148 if (!surroundingTextResult.canConvert<QString>() || !cursorPositionResult.canConvert<int>())
149 return {};
150
151 const auto cursorPos = cursorPositionResult.toInt();
152 if (cursorPos < 0)
153 return {};
154
155 const QString text = surroundingTextResult.toString();
156 return {text.left(cursorPos), text.mid(cursorPos)};
157}
158
159}
160
163 , m_lastCursorRectangle(0, 0, 0, 0)
164 , m_qtImEnabled(false)
170{
171 auto __dbg = make_QCScopedDebug("QOhosInputContext::QOhosInputContext");
172
173 QObject::connect(
174 QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged,
175 this, &QOhosInputContext::onCursorRectangleChanged);
176
177 QGuiApplication::instance()->installEventFilter(this);
178}
179
181
183{
184 if (m_imConnectionState == ImConnectionState::Attached) {
185 setImConnectionState(ImConnectionState::Detached);
186 setImConnectionState(ImConnectionState::Attached);
187 }
188}
189
191{
192 auto __dbg = make_QCScopedDebug("QOhosInputContext::commit");
193
194 auto preeditText = std::exchange(m_pendingPreeditText, {});
195
196 QInputMethodEvent event;
197 event.setCommitString(preeditText);
198 sendFocusObjectInputMethodEvent(&event);
199}
200
201void QOhosInputContext::update(Qt::InputMethodQueries queries)
202{
203 if (!focusObjectOrNull()) {
205 return;
206 }
207
208 m_qtImEnabled = queryImEnabled();
209 const auto qtInputMethodHintsValue = queryInputMethodHints();
210 const auto qtEnterKeyTypeValue = queryEnterKeyType();
211
212 const bool imStateChanged =
213 m_qtInputMethodHints != qtInputMethodHintsValue
214 || m_qtEnterKeyType != qtEnterKeyTypeValue;
215
216 auto imAlreadyAttached = m_imConnectionState == ImConnectionState::Attached;
217 if (imAlreadyAttached && imStateChanged)
218 updateInputMethodControllerAttributes(qtInputMethodHintsValue, qtEnterKeyTypeValue);
219
220 m_qtInputMethodHints = qtInputMethodHintsValue;
221 m_qtEnterKeyType = qtEnterKeyTypeValue;
222
223 if (inputMethodAccepted() && m_qtImEnabled) {
224 if (imAlreadyAttached) {
225 pushTextAroundCursorToProxy();
226 updateSelection();
227 }
228
229 auto updateCausedByWidgetTransform = queries == Qt::ImInputItemClipRectangle;
230 auto updateCausedByQueryAllImParameters = queries == Qt::ImQueryAll;
231
232 if (updateCausedByQueryAllImParameters)
233 return;
234
235 if (!updateCausedByWidgetTransform || !imAlreadyAttached) {
237 }
238 } else {
240 }
241}
242
244{
245 auto __dbg = make_QCScopedDebug("QOhosInputContext::invokeAction");
246}
247
249{
250 auto __dbg = make_QCScopedDebug("QOhosInputContext::keyboardRect");
251 return {};
252}
253
255{
256 auto __dbg = make_QCScopedDebug("QOhosInputContext::isAnimating");
257 return {};
258}
259
261{
262 auto __dbg = make_QCScopedDebug("QOhosInputContext::showInputPanel");
263 setImConnectionState(ImConnectionState::Attached);
264}
265
267{
268 auto __dbg = make_QCScopedDebug("QOhosInputContext::hideInputPanel");
269 setImConnectionState(ImConnectionState::Detached);
270}
271
273{
274 auto __dbg = make_QCScopedDebug("QOhosInputContext::isInputPanelVisible");
275 return m_imConnectionRequestedState == ImConnectionState::Attached;
276}
277
278void QOhosInputContext::setFocusObject(QObject *object)
279{
280 if (object == m_focusObject)
281 return;
282
283 const bool wasAttached = m_imConnectionState == ImConnectionState::Attached;
284
285 if (!m_pendingPreeditText.isEmpty())
286 commit();
287
288 m_focusObject = object;
289
290 if (wasAttached && object != nullptr) {
291 m_qtImEnabled = queryImEnabled();
292 if (m_qtImEnabled)
293 reset();
294 }
295}
296
298{
299 return m_focusObject;
300}
301
302void QOhosInputContext::setImConnectionState(ImConnectionState requestedState)
303{
304 if (requestedState != m_imConnectionRequestedState) {
305 setImConnectionStateImpl(requestedState);
306 } else {
307 if (m_imConnectionState == ImConnectionState::Attached && !m_softwareKeyboardVisible)
308 showTextInput();
309 }
310}
311
312void QOhosInputContext::setImConnectionStateImpl(ImConnectionState requestedState)
313{
314 m_imConnectionRequestedState = m_qtImEnabled ? requestedState : ImConnectionState::Detached;
315
316 if (!m_imConnectionRequestActive) {
317 m_imConnectionRequestActive = true;
318
319 dispatchRequestedImStateChange(requestedState);
320 }
321}
322
323void QOhosInputContext::dispatchRequestedImStateChange(ImConnectionState requestedState)
324{
325 auto result = false;
326 if (requestedState == ImConnectionState::Attached)
327 result = attachToInputMethodController();
328 else
329 result = detachFromInputMethodController();
330 handleRequestedImConnectionState(requestedState, result);
331}
332
333bool QOhosInputContext::attachToInputMethodController()
334{
335 class ImCallbacks : public QOhosInputMethodProxy::ClientCallbacks
336 {
337 public:
338 ImCallbacks(QOhosInputContext &inputContext)
339 : m_inputContext(inputContext)
340 {
341 }
342
343 private:
344 void onInsertText(std::string text) override
345 {
346 m_inputContext.sendInsertedTextToQt(std::move(text));
347 }
348
349 void onInsertPreviewText(std::string previewText) override
350 {
351 m_inputContext.sendInsertedPreviewTextToQt(std::move(previewText));
352 }
353
354 void onFinishPreviewText() override
355 {
356 m_inputContext.commit();
357 }
358
359 void onDeleteForward(int length) override
360 {
361 m_inputContext.sendFocusObjectFunctionalKeyEvent(Qt::Key_Delete, QStringLiteral("\u007F"), length);
362 }
363
364 void onDeleteBackward(int length) override
365 {
366 m_inputContext.sendFocusObjectFunctionalKeyEvent(Qt::Key_Backspace, QStringLiteral("\u0008"), length);
367 }
368
369 void onSendKeyboardStatus(::InputMethod_KeyboardStatus keyboardStatus) override
370 {
371 bool ohosKeyboardShown = keyboardStatus == ::InputMethod_KeyboardStatus::IME_KEYBOARD_STATUS_SHOW;
372 m_inputContext.setSoftwareKeyboardVisibilityStatus(ohosKeyboardShown);
373 }
374
375 void onSendEnterKey(::InputMethod_EnterKeyType) override
376 {
377 m_inputContext.sendFocusObjectFunctionalKeyEvent(Qt::Key_Enter, QStringLiteral("\u000D"));
378 }
379
380 void onMoveCursor(::InputMethod_Direction direction) override
381 {
382 auto qtDirection = tryMapInputMethodDirectionToQt(direction);
383 if (!qtDirection.has_value()) {
384 qOhosPrintfWarning(
385 "got unsupported InputMethod_Direction value (%d), cursor won't be moved!",
386 static_cast<int>(direction));
387 return;
388 }
389
390 m_inputContext.sendCursorMoveToQt(qtDirection.value());
391 }
392
393 QOhosInputContext &m_inputContext;
394 };
395
396 if (m_imProxy)
397 qOhosPrintfWarning("%s: proxy already exists!", Q_FUNC_INFO);
398
399 m_imProxy = std::make_shared<QOhosInputMethodProxy>(
400 std::make_shared<ImCallbacks>(*this),
401 mapQtToOhosImeRequestReason(
402 m_lastInputTypeToTriggerSoftKeyboard.value_or(RequestKeyboardReason::OTHER)));
403
404 if (m_imProxy->hasAttachedSuccessfully()) {
405 pushTextAroundCursorToProxy();
406 m_imProxy->notifyConfigurationChange(
407 mapQtToOhosImeEnterKeyType(m_qtEnterKeyType),
408 mapQtInputMethodHintsToOhosImeTextInputType(m_qtInputMethodHints));
409 return true;
410 }
411 return false;
412}
413
414bool QOhosInputContext::detachFromInputMethodController()
415{
416 if (!m_imProxy)
417 qOhosPrintfWarning("%s: proxy doesn't exist!", Q_FUNC_INFO);
418
419 m_imProxy.reset();
420 return true;
421}
422
423void QOhosInputContext::handleRequestedImConnectionState(ImConnectionState requestedState, bool success)
424{
425 m_imConnectionRequestActive = false;
426
427 if (!success) {
428 qOhosWarning(QtForOhos)
429 << "Cannot "
430 << (requestedState == ImConnectionState::Attached ? "attach to" : "detach from")
431 << " IMC!";
432 return;
433 }
434
435 m_imConnectionState = requestedState;
436
437 if (m_imConnectionRequestedState != m_imConnectionState)
438 setImConnectionStateImpl(m_imConnectionRequestedState);
439
440 onCursorRectangleChanged();
441}
442
443void QOhosInputContext::showTextInput()
444{
445 if (m_imProxy == nullptr) {
446 qOhosPrintfError("%s: proxy doesn't exist!", Q_FUNC_INFO);
447 return;
448 }
449
450 m_imProxy->showTextInput(mapQtToOhosImeRequestReason(
451 m_lastInputTypeToTriggerSoftKeyboard.value_or(RequestKeyboardReason::OTHER)));
452}
453
455{
456 m_softwareKeyboardVisible = visible;
457}
458
459void QOhosInputContext::setLastInputTypeToTriggerSoftKeyboard(RequestKeyboardReason inputType)
460{
461 m_lastInputTypeToTriggerSoftKeyboard = inputType;
462}
463
464void QOhosInputContext::onCursorRectangleChanged()
465{
466 if (m_imConnectionState == ImConnectionState::Detached) {
467 qOhosDebug(QtForOhos) << "Cursor rectangle changed while detached; deferring update until attach";
468 m_updateCursorRectangleAfterAttaching = true;
469 return;
470 }
471
472 auto *focusedWindow = QGuiApplication::focusWindow();
473 if (focusedWindow == nullptr) {
474 qOhosCritical(QtForOhos)
475 << "Could not retrieve focused window. Updating cursor position isn't possible";
476 return;
477 }
478
479 auto focusedWindowPosition = focusedWindow->mapToGlobal(QPoint(0, 0));
480 QRect cursorRectangle = QGuiApplication::inputMethod()->cursorRectangle().toRect();
481 if (!m_updateCursorRectangleAfterAttaching
482 && cursorRectangle == m_lastCursorRectangle
483 && m_lastFocusedWindowPosition == focusedWindowPosition) {
484 return;
485 }
486
487 m_lastCursorRectangle = cursorRectangle;
488 m_lastFocusedWindowPosition = focusedWindowPosition;
489 auto globalInputItemRectangle =
490 QGuiApplication::inputMethod()->inputItemClipRectangle()
491 .translated(m_lastFocusedWindowPosition)
492 .toRect();
493 auto globalCursorRectangle = m_lastCursorRectangle.translated(m_lastFocusedWindowPosition);
494 auto inputItemClampedCursorPos = clampToRect(
495 {globalCursorRectangle.x(), globalCursorRectangle.y()},
496 globalInputItemRectangle.isValid()
497 ? globalInputItemRectangle
498 : QRect(focusedWindowPosition, focusedWindow->size()));
499 auto nativeCursorPos = QHighDpiScaling::mapPositionToNative(
500 inputItemClampedCursorPos, focusedWindow->screen()->handle());
501 auto screenBasedCursorPos = nativeCursorPos - focusedWindow->screen()->handle()->geometry().topLeft();
502 updateOhosCursor({
503 screenBasedCursorPos.x(), screenBasedCursorPos.y(),
504 globalCursorRectangle.width(), globalCursorRectangle.height()
505 });
506 m_updateCursorRectangleAfterAttaching = false;
507}
508
509void QOhosInputContext::updateInputMethodControllerAttributes(
510 Qt::InputMethodHints qtInputMethodHints, Qt::EnterKeyType qtEnterKeyType)
511{
512 if (m_imProxy == nullptr) {
513 qOhosPrintfError("%s: proxy doesn't exist!", Q_FUNC_INFO);
514 return;
515 }
516
517 m_imProxy->notifyConfigurationChange(
518 mapQtToOhosImeEnterKeyType(qtEnterKeyType),
519 mapQtInputMethodHintsToOhosImeTextInputType(qtInputMethodHints));
520}
521
522void QOhosInputContext::updateOhosCursor(const QRect &globalCursorRect)
523{
524 if (m_imProxy == nullptr) {
525 qOhosPrintfError("%s: proxy doesn't exist!", Q_FUNC_INFO);
526 return;
527 }
528
529 m_imProxy->notifyCursorUpdate(globalCursorRect);
530}
531
532void QOhosInputContext::pushTextAroundCursorToProxy()
533{
534 if (m_imProxy == nullptr) {
535 qOhosPrintfError("%s: proxy doesn't exist!", Q_FUNC_INFO);
536 return;
537 }
538
539 const auto textAroundCursor = queryQtImTextAroundCursorOrEmpty();
540 m_imProxy->setTextAroundCursor(
541 textAroundCursor.first.toStdU16String(),
542 textAroundCursor.second.toStdU16String(),
543 tryQueryCursorPosition().value_or(0));
544}
545
546void QOhosInputContext::updateSelection()
547{
548 if (m_imProxy == nullptr) {
549 qOhosPrintfError("%s: proxy doesn't exist!", Q_FUNC_INFO);
550 return;
551 }
552
553 auto query = tryQueryFocusObjectInputMethod(
554 Qt::ImSurroundingText | Qt::ImCursorPosition | Qt::ImAnchorPosition);
555 if (query.isNull())
556 return;
557
558 const auto surroundingText = query->value(Qt::ImSurroundingText);
559 const auto cursorPosition = query->value(Qt::ImCursorPosition);
560 const auto anchorPosition = query->value(Qt::ImAnchorPosition);
561
562 if (!surroundingText.canConvert<QString>() || !cursorPosition.canConvert<int>()
563 || !anchorPosition.canConvert<int>())
564 return;
565
566 const int cursor = cursorPosition.toInt();
567 const int anchor = anchorPosition.toInt();
568
569 m_imProxy->notifySelectionChange(
570 surroundingText.toString().toStdU16String(), std::min(anchor, cursor), std::max(anchor, cursor));
571}
572
573void QOhosInputContext::handleFocusInEvent(QObject *obj, QFocusEvent *event)
574{
575 if (obj->isWidgetType() && queryImEnabled()) {
576 auto focusReason = event->reason();
577 if (focusReason == Qt::OtherFocusReason || focusReason == Qt::ActiveWindowFocusReason)
578 setLastInputTypeToTriggerSoftKeyboard(RequestKeyboardReason::NONE);
579 }
580}
581
582bool QOhosInputContext::eventFilter(QObject *obj, QEvent *event)
583{
584 if (event->type() == QEvent::FocusIn)
585 handleFocusInEvent(obj, static_cast<QFocusEvent *>(event));
586 return false;
587}
588
589void QOhosInputContext::sendInsertedTextToQt(const std::string &textToInsert)
590{
591 auto query = tryQueryFocusObjectInputMethod(Qt::ImEnabled);
592 if (query.isNull())
593 return;
594
595 if (!query->value(Qt::ImEnabled).toBool()) {
596 qOhosDebug(QtForOhos) << "onInsertText(): focus object is not able to handle InputMethod";
597 return;
598 }
599
600 m_pendingPreeditText.clear();
601
602 QInputMethodEvent event;
603 event.setCommitString(QString::fromStdString(textToInsert));
604 sendFocusObjectInputMethodEvent(&event);
605}
606
607void QOhosInputContext::sendInsertedPreviewTextToQt(std::string previewText)
608{
609 auto query = tryQueryFocusObjectInputMethod(Qt::ImEnabled);
610 if (query.isNull())
611 return;
612
613 if (!query->value(Qt::ImEnabled).toBool()) {
614 qOhosPrintfDebug("%s: focus object is not able to handle InputMethod", Q_FUNC_INFO);
615 return;
616 }
617
618 const QString previewString = QString::fromStdString(previewText);
619 QList<QInputMethodEvent::Attribute> imEventAttributes;
620 if (!previewString.isEmpty()) {
621 QTextCharFormat format;
622 format.setFontUnderline(true);
623 imEventAttributes.append(
624 QInputMethodEvent::Attribute(
625 QInputMethodEvent::TextFormat, 0, previewString.length(), format));
626 }
627
628 m_pendingPreeditText = previewString;
629
630 QInputMethodEvent preeditStringEvent(previewString, imEventAttributes);
631 sendFocusObjectInputMethodEvent(&preeditStringEvent);
632}
633
634void QOhosInputContext::sendFocusObjectInputMethodEvent(QInputMethodEvent *event)
635{
636 auto *focusObject = focusObjectOrNull();
637 if (focusObject == nullptr) {
638 qOhosWarning(QtForOhos) << "sendFocusObjectInputMethodEvent(): no focus object to send event to!";
639 return;
640 }
641
642 QCoreApplication::sendEvent(focusObject, event);
643}
644
645void QOhosInputContext::sendCursorMoveToQt(QOhosInputContext::Direction direction)
646{
647 switch (direction) {
648 case QOhosInputContext::Direction::CURSOR_UP:
649 sendFocusObjectFunctionalKeyEvent(Qt::Key_Up);
650 break;
651 case QOhosInputContext::Direction::CURSOR_DOWN:
652 sendFocusObjectFunctionalKeyEvent(Qt::Key_Down);
653 break;
654 case QOhosInputContext::Direction::CURSOR_LEFT:
655 sendFocusObjectFunctionalKeyEvent(Qt::Key_Left);
656 break;
657 case QOhosInputContext::Direction::CURSOR_RIGHT:
658 sendFocusObjectFunctionalKeyEvent(Qt::Key_Right);
659 break;
660 }
661}
662
663void QOhosInputContext::sendFocusObjectFunctionalKeyEvent(Qt::Key key, const QString &keyText, int repeatCount)
664{
665 auto *focusObject = focusObjectOrNull();
666 if (focusObject == nullptr) {
667 qOhosWarning(QtForOhos) << "sendFocusObjectFunctionalKeyEvent(): no focus object to send event to!";
668 return;
669 }
670
671 for (int i = 0; i < repeatCount; ++i) {
672 QGuiApplication::postEvent(focusObject, new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier, keyText));
673 QGuiApplication::postEvent(focusObject, new QKeyEvent(QEvent::KeyRelease, key, Qt::NoModifier, keyText));
674 }
675}
676
677bool QOhosInputContext::queryImEnabled() const
678{
679 auto query = tryQueryFocusObjectInputMethod(Qt::ImEnabled);
680 return !query.isNull() && query->value(Qt::ImEnabled).toBool();
681}
682
683Qt::InputMethodHints QOhosInputContext::queryInputMethodHints() const
684{
685 std::optional<Qt::InputMethodHints> hints;
686 auto query = tryQueryFocusObjectInputMethod(Qt::ImHints);
687 if (!query.isNull()) {
688 auto imHintsInt = tryGetIntPropertyFromQuery(Qt::ImHints, query);
689 if (imHintsInt.has_value())
690 hints = static_cast<Qt::InputMethodHints>(imHintsInt.value());
691 }
692
693 return hints.value_or(defaultInputMethodHints);
694}
695
696Qt::EnterKeyType QOhosInputContext::queryEnterKeyType() const
697{
698 std::optional<Qt::EnterKeyType> enterKeyType;
699 auto query = tryQueryFocusObjectInputMethod(Qt::ImEnterKeyType);
700 if (!query.isNull()) {
701 auto imEnterKeyTypeInt = tryGetIntPropertyFromQuery(Qt::ImEnterKeyType, query);
702 if (imEnterKeyTypeInt.has_value())
703 enterKeyType = static_cast<Qt::EnterKeyType>(imEnterKeyTypeInt.value());
704 }
705
706 return enterKeyType.value_or(defaultEnterKeyType);
707}
708
709std::optional<int> QOhosInputContext::tryQueryCursorPosition() const
710{
711 auto query = tryQueryFocusObjectInputMethod(Qt::ImCursorPosition);
712 return !query.isNull()
713 ? tryGetIntPropertyFromQuery(Qt::ImCursorPosition, query)
714 : std::nullopt;
715}
716
717QSharedPointer<QInputMethodQueryEvent> QOhosInputContext::tryQueryFocusObjectInputMethod(Qt::InputMethodQueries queries) const
718{
719 auto *focusObject = focusObjectOrNull();
720 if (focusObject == nullptr) {
721 qOhosWarning(QtForOhos) << "tryQueryFocusObjectInputMethod(): no focus object to query information from!";
722 return {};
723 }
724
725 auto imqEvent = QSharedPointer<QInputMethodQueryEvent>::create(queries);
726 QCoreApplication::sendEvent(focusObject, imqEvent.data());
727 return imqEvent;
728}
729
730QT_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.
Combined button and popup list for selecting options.
::InputMethod_TextInputType mapQtInputMethodHintsToOhosImeTextInputType(Qt::InputMethodHints hints)
::InputMethod_EnterKeyType mapQtToOhosImeEnterKeyType(Qt::EnterKeyType qtEnterKeyType)
std::optional< int > tryGetIntPropertyFromQuery(Qt::InputMethodQuery property, QSharedPointer< QInputMethodQueryEvent > query)
const Qt::EnterKeyType defaultEnterKeyType
std::optional< QOhosInputContext::Direction > tryMapInputMethodDirectionToQt(::InputMethod_Direction direction)
const Qt::InputMethodHints defaultInputMethodHints
QPoint clampToRect(const QPoint &p, const QRect &rect)
::InputMethod_RequestKeyboardReason mapQtToOhosImeRequestReason(QOhosInputContext::RequestKeyboardReason qtRequestKeyboardReason)
std::pair< QString, QString > queryQtImTextAroundCursorOrEmpty()