Revision control
++ // Copyright (C) 2021 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include "xt9awinputmethod_p.h"
++ #include "xt9awinputmethodprivate_p.h"
++ #include <QtVirtualKeyboard/qvirtualkeyboardinputcontext.h>
++ #include <QtVirtualKeyboard/qvirtualkeyboardobserver.h>
++ #include <QLoggingCategory>
++
++ QT_BEGIN_NAMESPACE
++ namespace QtVirtualKeyboard {
++
++ /*!
++ \class QtVirtualKeyboard::Xt9AwInputMethod
++ \internal
++ */
++
++ Xt9AwInputMethod::Xt9AwInputMethod(Xt9AwInputMethodPrivate &dd, QObject *parent) :
++ Xt9InputMethod(dd, parent)
++ {
++ }
++
++ Xt9AwInputMethod::Xt9AwInputMethod(QObject *parent) :
++ Xt9InputMethod(*new Xt9AwInputMethodPrivate(this), parent)
++ {
++ }
++
++ QList<QVirtualKeyboardInputEngine::InputMode> Xt9AwInputMethod::inputModes(const QString &locale)
++ {
++ QList<QVirtualKeyboardInputEngine::InputMode> result;
++ bool supportsLatinInputMode = true;
++ switch (QLocale(locale).script()) {
++ case QLocale::GreekScript:
++ result.append(QVirtualKeyboardInputEngine::InputMode::Greek);
++ break;
++ case QLocale::CyrillicScript:
++ if (locale == QLatin1String("uk_UA") || locale == QLatin1String("ru_RU") || locale == QLatin1String("bg_BG")) {
++ result.append(QVirtualKeyboardInputEngine::InputMode::Cyrillic);
++ supportsLatinInputMode = false;
++ }
++ break;
++ case QLocale::ArabicScript:
++ result.append(QVirtualKeyboardInputEngine::InputMode::Arabic);
++ break;
++ case QLocale::HebrewScript:
++ result.append(QVirtualKeyboardInputEngine::InputMode::Hebrew);
++ break;
++ default:
++ break;
++ }
++ if (supportsLatinInputMode)
++ result.append(QVirtualKeyboardInputEngine::InputMode::Latin);
++ result.append(QVirtualKeyboardInputEngine::InputMode::Numeric);
++ return result;
++ }
++
++ bool Xt9AwInputMethod::setInputMode(const QString &locale, QVirtualKeyboardInputEngine::InputMode inputMode)
++ {
++ Q_D(Xt9AwInputMethod);
++
++ return d->init(QLocale(locale), inputMode);
++ }
++
++ bool Xt9AwInputMethod::setTextCase(QVirtualKeyboardInputEngine::TextCase textCase)
++ {
++ Q_UNUSED(textCase)
++ return true;
++ }
++
++ bool Xt9AwInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::KeyboardModifiers modifiers)
++ {
++ Q_UNUSED(modifiers)
++ Q_D(Xt9AwInputMethod);
++
++ QVirtualKeyboardInputContext *ic = inputContext();
++ const Qt::InputMethodHints inputMethodHints = ic->inputMethodHints();
++ if (inputMethodHints.testFlag(Qt::ImhHiddenText) || inputMethodHints.testFlag(Qt::ImhNoPredictiveText)) {
++ const Qt::KeyboardModifiers mods = (key == Qt::Key_Return) ? Qt::NoModifier : modifiers;
++ inputContext()->sendKeyClick(key, text, mods);
++ return true;
++ }
++
++ switch (key) {
++ case Qt::Key_Backspace: {
++ const int cursorPosition = ic->cursorPosition();
++ if (cursorPosition > 0 && !d->xt9Ime()->hasActiveInput() &&
++ reselect(cursorPosition, QVirtualKeyboardInputEngine::ReselectFlag::WordBeforeCursor))
++ return true;
++ return d->processBackspace();
++ }
++
++ case Qt::Key_Enter:
++ case Qt::Key_Return:
++ case Qt::Key_Tab:
++ case Qt::Key_Space: {
++ Xt9DeferredSelectionListUpdate deferredSelectionListUpdate(d);
++ if (d->xt9Ime()->hasActiveInput() && !d->selectionList.isEmpty() && d->defaultListIndex >= 0) {
++ if (key == Qt::Key_Space)
++ d->selectionList.replace(d->defaultListIndex, d->selectionList.at(d->defaultListIndex) + QLatin1String(" "));
++ d->selectionListSelectItem(d->defaultListIndex);
++ if (key == Qt::Key_Space) {
++ d->setAutoSpaceAllowed(false);
++ return true;
++ }
++ return false;
++ }
++
++ update();
++ if (key == Qt::Key_Space) {
++ ic->commit(QLatin1String(" "));
++ d->buildSelectionList();
++ return true;
++ }
++ break;
++ }
++
++ case Qt::Key_Shift:
++ break;
++
++ default:
++ if (text.length() > 0) {
++ const bool autoSpaceAllowed = d->xt9Ime()->hasActiveInput() || d->autoSpaceAllowed;
++ if (text.length() == 1) {
++ if (!d->processKeyBySymbol(text.at(0))) {
++ ic->sendKeyClick(key, text, modifiers);
++ d->setAutoSpaceAllowed(autoSpaceAllowed);
++ }
++ return true;
++ } else {
++ update();
++ d->setAutoSpaceAllowed(true);
++ if (autoSpaceAllowed && d->isAutoSpaceAllowed())
++ ic->commit(QLatin1String(" "));
++ ic->commit(text);
++ d->setAutoSpaceAllowed(autoSpaceAllowed);
++ d->buildSelectionList();
++ return true;
++ }
++ }
++ break;
++ }
++
++ return false;
++ }
++
++ QList<QVirtualKeyboardSelectionListModel::Type> Xt9AwInputMethod::selectionLists()
++ {
++ return QList<QVirtualKeyboardSelectionListModel::Type>() << QVirtualKeyboardSelectionListModel::Type::WordCandidateList;
++ }
++
++ int Xt9AwInputMethod::selectionListItemCount(QVirtualKeyboardSelectionListModel::Type type)
++ {
++ Q_UNUSED(type)
++ Q_D(Xt9AwInputMethod);
++ return d->selectionList.size();
++ }
++
++ QVariant Xt9AwInputMethod::selectionListData(QVirtualKeyboardSelectionListModel::Type type, int index, QVirtualKeyboardSelectionListModel::Role role)
++ {
++ Q_UNUSED(type)
++ QVariant result;
++ Q_D(Xt9AwInputMethod);
++ switch (role) {
++ case QVirtualKeyboardSelectionListModel::Role::Display:
++ result = QVariant(d->selectionList.at(index));
++ break;
++ case QVirtualKeyboardSelectionListModel::Role::WordCompletionLength:
++ result.setValue(0);
++ break;
++ case QVirtualKeyboardSelectionListModel::Role::Dictionary:
++ {
++ ET9AWWordInfo *wordInfo = nullptr;
++ XT9_API(ET9AWSelLstGetWord, &d->xt9Ime()->sLingInfo, &wordInfo, static_cast<ET9U8>(index));
++ if (wordInfo) {
++ QVirtualKeyboardSelectionListModel::DictionaryType dictionaryType = wordInfo->bWordSource == ET9AWORDSOURCE_CUSTOM ?
++ QVirtualKeyboardSelectionListModel::DictionaryType::User :
++ QVirtualKeyboardSelectionListModel::DictionaryType::Default;
++ result = QVariant(static_cast<int>(dictionaryType));
++ }
++ break;
++ }
++ case QVirtualKeyboardSelectionListModel::Role::CanRemoveSuggestion:
++ {
++ ET9AWWordInfo *wordInfo = nullptr;
++ XT9_API(ET9AWSelLstGetWord, &d->xt9Ime()->sLingInfo, &wordInfo, static_cast<ET9U8>(index));
++ result = QVariant(wordInfo && wordInfo->bIsDeletable != 0);
++ break;
++ }
++ }
++ return result;
++ }
++
++ void Xt9AwInputMethod::selectionListItemSelected(QVirtualKeyboardSelectionListModel::Type type, int index)
++ {
++ Q_UNUSED(type)
++ Q_D(Xt9AwInputMethod);
++
++ d->selectionListSelectItem(index);
++ }
++
++ bool Xt9AwInputMethod::selectionListRemoveItem(QVirtualKeyboardSelectionListModel::Type type, int index)
++ {
++ Q_D(Xt9AwInputMethod);
++ Q_UNUSED(type)
++
++ if (index <= 0 || index >= d->selectionList.size())
++ return false;
++
++ QString word = d->selectionList.at(index);
++ d->removeFromDictionary(word);
++ d->buildSelectionList();
++
++ return true;
++ }
++
++ bool Xt9AwInputMethod::reselect(int cursorPosition, const QVirtualKeyboardInputEngine::ReselectFlags &reselectFlags)
++ {
++ Q_D(Xt9AwInputMethod);
++
++ QVirtualKeyboardInputContext *ic = inputContext();
++ if (!ic)
++ return false;
++
++ QString word;
++ const QString surroundingText = ic->surroundingText();
++ int replaceFrom = 0;
++
++ if (reselectFlags.testFlag(QVirtualKeyboardInputEngine::ReselectFlag::WordBeforeCursor)) {
++ for (int i = cursorPosition - 1; i >= 0; --i) {
++ QChar c = surroundingText.at(i);
++ if (!d->isValidInputChar(c))
++ break;
++ word.insert(0, c);
++ --replaceFrom;
++ }
++
++ while (replaceFrom < 0 && d->isJoiner(word.at(0))) {
++ word.remove(0, 1);
++ ++replaceFrom;
++ }
++ }
++
++ if (reselectFlags.testFlag(QVirtualKeyboardInputEngine::ReselectFlag::WordAtCursor) && replaceFrom == 0)
++ return false;
++
++ if (reselectFlags.testFlag(QVirtualKeyboardInputEngine::ReselectFlag::WordAfterCursor)) {
++ for (int i = cursorPosition; i < surroundingText.length(); ++i) {
++ QChar c = surroundingText.at(i);
++ if (!d->isValidInputChar(c))
++ break;
++ word.append(c);
++ }
++
++ while (replaceFrom > -word.length()) {
++ int lastPos = word.length() - 1;
++ if (!d->isJoiner(word.at(lastPos)))
++ break;
++ word.remove(lastPos, 1);
++ }
++ }
++
++ if (word.isEmpty())
++ return false;
++
++ if (reselectFlags.testFlag(QVirtualKeyboardInputEngine::ReselectFlag::WordAtCursor) && replaceFrom == -word.length())
++ return false;
++
++ if (d->isJoiner(word.at(0)))
++ return false;
++
++ if (d->isJoiner(word.at(word.length() - 1)))
++ return false;
++
++ if (!d->reselectWord(word))
++ return false;
++
++ ic->setPreeditText(word, QList<QInputMethodEvent::Attribute>(), replaceFrom, word.length());
++ d->setAutoSpaceAllowed(false);
++
++ return true;
++ }
++
++ void Xt9AwInputMethod::reset()
++ {
++ Q_D(Xt9AwInputMethod);
++
++ d->reset();
++ }
++
++ void Xt9AwInputMethod::update()
++ {
++ Q_D(Xt9AwInputMethod);
++
++ if (d->xt9Ime()->hasActiveInput()) {
++ d->learnWord(d->xt9Ime()->exactWord());
++ inputContext()->commit();
++ }
++
++ reset();
++ }
++
++ } // namespace QtVirtualKeyboard
++ QT_END_NAMESPACE