aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/openwnn/openwnninputmethod.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/openwnn/openwnninputmethod.cpp')
-rw-r--r--src/plugins/openwnn/openwnninputmethod.cpp806
1 files changed, 806 insertions, 0 deletions
diff --git a/src/plugins/openwnn/openwnninputmethod.cpp b/src/plugins/openwnn/openwnninputmethod.cpp
new file mode 100644
index 00000000..745edd14
--- /dev/null
+++ b/src/plugins/openwnn/openwnninputmethod.cpp
@@ -0,0 +1,806 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "openwnninputmethod_p.h"
+#include <QtVirtualKeyboard/qvirtualkeyboardinputcontext.h>
+#include <QLoggingCategory>
+#include <openwnnenginejajp.h>
+#include <composingtext.h>
+#include <romkan.h>
+#include <romkanfullkatakana.h>
+#include <romkanhalfkatakana.h>
+#include <QTextFormat>
+
+QT_BEGIN_NAMESPACE
+namespace QtVirtualKeyboard {
+
+Q_LOGGING_CATEGORY(lcOpenWnn, "qt.virtualkeyboard.openwnn")
+
+class OpenWnnInputMethodPrivate
+{
+ Q_DECLARE_PUBLIC(OpenWnnInputMethod)
+public:
+ enum EngineMode {
+ ENGINE_MODE_DEFAULT,
+ ENGINE_MODE_DIRECT,
+ ENGINE_MODE_NO_LV2_CONV,
+ ENGINE_MODE_FULL_KATAKANA,
+ ENGINE_MODE_HALF_KATAKANA,
+ };
+
+ enum ConvertType {
+ CONVERT_TYPE_NONE = 0,
+ CONVERT_TYPE_RENBUN = 1,
+ };
+
+ enum {
+ MAX_COMPOSING_TEXT = 30
+ };
+
+ OpenWnnInputMethodPrivate(OpenWnnInputMethod *q_ptr) :
+ q_ptr(q_ptr),
+ inputMode(QVirtualKeyboardInputEngine::InputMode::Latin),
+ exactMatchMode(false),
+ converter(nullptr),
+ converterJAJP(),
+ activeConvertType(CONVERT_TYPE_NONE),
+ preConverter(nullptr),
+ enableLearning(true),
+ enablePrediction(true),
+ enableConverter(true),
+ disableUpdate(false),
+ commitCount(0),
+ targetLayer(ComposingText::LAYER1),
+ activeWordIndex(-1)
+ {
+ }
+
+ void changeEngineMode(EngineMode mode)
+ {
+ switch (mode) {
+ case ENGINE_MODE_DIRECT:
+ /* Full/Half-width number or Full-width alphabet */
+ converter = nullptr;
+ preConverter.reset();
+ break;
+
+ case ENGINE_MODE_NO_LV2_CONV:
+ converter = nullptr;
+ preConverter.reset(new Romkan());
+ break;
+
+ case ENGINE_MODE_FULL_KATAKANA:
+ converter = nullptr;
+ preConverter.reset(new RomkanFullKatakana());
+ break;
+
+ case ENGINE_MODE_HALF_KATAKANA:
+ converter = nullptr;
+ preConverter.reset(new RomkanHalfKatakana());
+ break;
+
+ default:
+ /* HIRAGANA input mode */
+ setDictionary(OpenWnnEngineJAJP::DIC_LANG_JP);
+ converter = &converterJAJP;
+ preConverter.reset(new Romkan());
+ break;
+ }
+ }
+
+ void setDictionary(OpenWnnEngineJAJP::DictionaryType mode)
+ {
+ converterJAJP.setDictionary(mode);
+ }
+
+ void breakSequence()
+ {
+ converterJAJP.breakSequence();
+ }
+
+ bool isEnableL2Converter()
+ {
+ return converter != nullptr && enableConverter;
+ }
+
+ void startConvert(ConvertType convertType)
+ {
+ if (!isEnableL2Converter())
+ return;
+
+ if (activeConvertType != convertType) {
+ if (!exactMatchMode) {
+ if (convertType == CONVERT_TYPE_RENBUN) {
+ /* not specify */
+ composingText.setCursor(ComposingText::LAYER1, 0);
+ } else {
+ if (activeConvertType == CONVERT_TYPE_RENBUN) {
+ exactMatchMode = true;
+ } else {
+ /* specify all range */
+ composingText.setCursor(ComposingText::LAYER1,
+ composingText.size(ComposingText::LAYER1));
+ }
+ }
+ }
+
+ if (convertType == CONVERT_TYPE_RENBUN)
+ /* clears variables for the prediction */
+ exactMatchMode = false;
+
+ /* clears variables for the convert */
+ commitCount = 0;
+
+ activeConvertType = convertType;
+
+ updateViewStatus(ComposingText::LAYER2, true, true);
+
+ focusNextCandidate();
+ }
+ }
+
+ void changeL2Segment(const QSharedPointer<WnnWord> &word)
+ {
+ if (word.isNull())
+ return;
+ QList<StrSegment> ss;
+ ss.append(composingText.getStrSegment(ComposingText::LAYER2, 0));
+ if (!ss[0].clause.isNull())
+ ss[0].clause->candidate = word->candidate;
+ ss[0].string = word->candidate;
+ composingText.replaceStrSegment(ComposingText::LAYER2, ss);
+ if (lcOpenWnn().isDebugEnabled())
+ composingText.debugout();
+ updateViewStatus(ComposingText::LAYER2, false, false);
+ }
+
+ void initializeScreen()
+ {
+ if (composingText.size(ComposingText::LAYER0) != 0) {
+ Q_Q(OpenWnnInputMethod);
+ q->inputContext()->commit(QString());
+ }
+ composingText.clear();
+ exactMatchMode = false;
+ activeConvertType = CONVERT_TYPE_NONE;
+ clearCandidates();
+ }
+
+ void updateViewStatusForPrediction(bool updateCandidates, bool updateEmptyText)
+ {
+ activeConvertType = CONVERT_TYPE_NONE;
+
+ updateViewStatus(ComposingText::LAYER1, updateCandidates, updateEmptyText);
+ }
+
+ void updateViewStatus(ComposingText::TextLayer layer, bool updateCandidates, bool updateEmptyText)
+ {
+ targetLayer = layer;
+
+ if (updateCandidates)
+ updateCandidateView();
+
+ /* set the text for displaying as the composing text */
+ displayText.clear();
+ displayText.insert(0, composingText.toString(layer));
+
+ /* add decoration to the text */
+ if (!displayText.isEmpty() || updateEmptyText) {
+
+ QList<QInputMethodEvent::Attribute> attributes;
+
+ int cursor = composingText.getCursor(layer);
+ if (cursor != 0) {
+ int highlightEnd = 0;
+
+ if (exactMatchMode) {
+
+ QTextCharFormat textFormat;
+ textFormat.setBackground(QBrush(QColor(0x66, 0xCD, 0xAA)));
+ textFormat.setForeground(QBrush(Qt::black));
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, cursor, textFormat));
+ highlightEnd = cursor;
+
+ } else if (layer == ComposingText::LAYER2) {
+
+ highlightEnd = composingText.toString(layer, 0, 0).size();
+
+ /* highlights the first segment */
+ QTextCharFormat textFormat;
+ textFormat.setBackground(QBrush(QColor(0x88, 0x88, 0xFF)));
+ textFormat.setForeground(QBrush(Qt::black));
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, highlightEnd, textFormat));
+ }
+
+ if (highlightEnd != 0 && highlightEnd < displayText.size()) {
+ /* highlights remaining text */
+ QTextCharFormat textFormat;
+ textFormat.setBackground(QBrush(QColor(0xF0, 0xFF, 0xFF)));
+ textFormat.setForeground(QBrush(Qt::black));
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, highlightEnd, displayText.size() - highlightEnd, textFormat));
+ }
+ }
+
+ QTextCharFormat textFormat;
+ textFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline);
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, displayText.size(), textFormat));
+
+ int displayCursor = composingText.toString(layer, 0, cursor - 1).size();
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, displayCursor, 1, QVariant()));
+
+ Q_Q(OpenWnnInputMethod);
+ q->inputContext()->setPreeditText(displayText, attributes);
+ }
+ }
+
+ void updateCandidateView()
+ {
+ switch (targetLayer) {
+ case ComposingText::LAYER0:
+ case ComposingText::LAYER1: /* prediction */
+ if (enablePrediction)
+ /* update the candidates view */
+ updatePrediction();
+ break;
+ case ComposingText::LAYER2: /* convert */
+ if (commitCount == 0)
+ converter->convert(composingText);
+
+ if (converter->makeCandidateListOf(commitCount) != 0) {
+ composingText.setCursor(ComposingText::LAYER2, 1);
+ displayCandidates();
+ } else {
+ composingText.setCursor(ComposingText::LAYER1,
+ composingText.toString(ComposingText::LAYER1).size());
+ clearCandidates();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ void updatePrediction()
+ {
+ int candidates = 0;
+ int cursor = composingText.getCursor(ComposingText::LAYER1);
+ if (isEnableL2Converter()) {
+ if (exactMatchMode)
+ /* exact matching */
+ candidates = converter->predict(composingText, 0, cursor);
+ else
+ /* normal prediction */
+ candidates = converter->predict(composingText, 0, -1);
+ }
+
+ /* update the candidates view */
+ if (candidates > 0)
+ displayCandidates();
+ else
+ clearCandidates();
+ }
+
+ void displayCandidates()
+ {
+ int previousActiveWordIndex = activeWordIndex;
+ bool wasEmpty = candidateList.isEmpty();
+ clearCandidates(true);
+
+ QSharedPointer<WnnWord> result;
+ while ((result = converter->getNextCandidate()))
+ candidateList.append(result);
+
+ Q_Q(OpenWnnInputMethod);
+ if (!candidateList.isEmpty() || !wasEmpty)
+ emit q->selectionListChanged(QVirtualKeyboardSelectionListModel::Type::WordCandidateList);
+ if (previousActiveWordIndex != activeWordIndex)
+ emit q->selectionListActiveItemChanged(QVirtualKeyboardSelectionListModel::Type::WordCandidateList, activeWordIndex);
+ }
+
+ void clearCandidates(bool deferUpdate = false)
+ {
+ if (!candidateList.isEmpty()) {
+ candidateList.clear();
+ if (!deferUpdate) {
+ Q_Q(OpenWnnInputMethod);
+ emit q->selectionListChanged(QVirtualKeyboardSelectionListModel::Type::WordCandidateList);
+ }
+ clearFocusCandidate(deferUpdate);
+ }
+ }
+
+ QSharedPointer<WnnWord> focusNextCandidate()
+ {
+ Q_Q(OpenWnnInputMethod);
+ if (candidateList.isEmpty())
+ return QSharedPointer<WnnWord>();
+ activeWordIndex++;
+ if (activeWordIndex >= candidateList.size())
+ activeWordIndex = 0;
+ emit q->selectionListActiveItemChanged(QVirtualKeyboardSelectionListModel::Type::WordCandidateList, activeWordIndex);
+ return candidateList.at(activeWordIndex);
+ }
+
+ void clearFocusCandidate(bool deferUpdate = false)
+ {
+ Q_Q(OpenWnnInputMethod);
+ if (activeWordIndex != -1) {
+ activeWordIndex = -1;
+ if (!deferUpdate)
+ emit q->selectionListActiveItemChanged(QVirtualKeyboardSelectionListModel::Type::WordCandidateList, activeWordIndex);
+ }
+ }
+
+ void fitInputType()
+ {
+ Q_Q(OpenWnnInputMethod);
+ enableConverter = true;
+
+ Qt::InputMethodHints inputMethodHints = q->inputContext()->inputMethodHints();
+ if (inputMethodHints.testFlag(Qt::ImhDigitsOnly) ||
+ inputMethodHints.testFlag(Qt::ImhFormattedNumbersOnly) ||
+ inputMethodHints.testFlag(Qt::ImhDialableCharactersOnly)) {
+ enableConverter = false;
+ }
+
+ if (inputMethodHints.testFlag(Qt::ImhLatinOnly)) {
+ enableConverter = false;
+ }
+
+ if (inputMode != QVirtualKeyboardInputEngine::InputMode::Hiragana ||
+ inputMethodHints.testFlag(Qt::ImhHiddenText) ||
+ inputMethodHints.testFlag(Qt::ImhSensitiveData) ||
+ inputMethodHints.testFlag(Qt::ImhNoPredictiveText)) {
+ if (enablePrediction) {
+ enablePrediction = false;
+ emit q->selectionListsChanged();
+ }
+ } else if (inputMode == QVirtualKeyboardInputEngine::InputMode::Hiragana && !enablePrediction) {
+ enablePrediction = true;
+ emit q->selectionListsChanged();
+ }
+
+ activeConvertType = CONVERT_TYPE_NONE;
+ }
+
+ void learnWord(WnnWord &word)
+ {
+ if (enableLearning)
+ converter->learn(word);
+ }
+
+ void learnWord(int index)
+ {
+ if (enableLearning && index < composingText.size(ComposingText::LAYER2)) {
+ StrSegment seg = composingText.getStrSegment(ComposingText::LAYER2, index);
+ if (!seg.clause.isNull()) {
+ converter->learn(*seg.clause);
+ } else {
+ QString stroke = composingText.toString(ComposingText::LAYER1, seg.from, seg.to);
+ WnnWord word(seg.string, stroke);
+ converter->learn(word);
+ }
+ }
+ }
+
+ void commitAll()
+ {
+ if (activeConvertType != CONVERT_TYPE_NONE) {
+ commitConvertingText();
+ } else {
+ composingText.setCursor(ComposingText::LAYER1,
+ composingText.size(ComposingText::LAYER1));
+ commitText(true);
+ }
+ }
+
+ void commitConvertingText()
+ {
+ if (activeConvertType != CONVERT_TYPE_NONE) {
+ Q_Q(OpenWnnInputMethod);
+ int size = composingText.size(ComposingText::LAYER2);
+ for (int i = 0; i < size; i++) {
+ learnWord(i);
+ }
+
+ QString text = composingText.toString(ComposingText::LAYER2);
+ disableUpdate = true;
+ q->inputContext()->commit(text);
+ disableUpdate = false;
+
+ initializeScreen();
+ }
+ }
+
+ bool commitText(bool learn = false)
+ {
+ ComposingText::TextLayer layer = targetLayer;
+ int cursor = composingText.getCursor(layer);
+ if (cursor == 0) {
+ return false;
+ }
+ QString tmp = composingText.toString(layer, 0, cursor - 1);
+
+ if (converter != nullptr) {
+ if (learn) {
+ if (activeConvertType == CONVERT_TYPE_RENBUN) {
+ learnWord(0); /* select the top of the clauses */
+ } else {
+ if (composingText.size(ComposingText::LAYER1) != 0) {
+ QString stroke = composingText.toString(ComposingText::LAYER1, 0, composingText.getCursor(layer) - 1);
+ WnnWord word(tmp, stroke);
+ learnWord(word);
+ }
+ }
+ } else {
+ breakSequence();
+ }
+ }
+ return commitText(tmp);
+ }
+
+ bool commitText(const WnnWord &word)
+ {
+ return commitText(word.candidate);
+ }
+
+ bool commitText(const QString &string)
+ {
+ Q_Q(OpenWnnInputMethod);
+ ComposingText::TextLayer layer = targetLayer;
+
+ disableUpdate = true;
+ q->inputContext()->commit(string);
+ disableUpdate = false;
+
+ int cursor = composingText.getCursor(layer);
+ if (cursor > 0) {
+ composingText.deleteStrSegment(layer, 0, composingText.getCursor(layer) - 1);
+ composingText.setCursor(layer, composingText.size(layer));
+ }
+ exactMatchMode = false;
+ commitCount++;
+
+ if ((layer == ComposingText::LAYER2) && (composingText.size(layer) == 0))
+ layer = ComposingText::LAYER1; /* for connected prediction */
+
+ if (layer == ComposingText::LAYER2) {
+ activeConvertType = CONVERT_TYPE_RENBUN;
+ updateViewStatus(layer, true, false);
+ focusNextCandidate();
+ } else {
+ updateViewStatusForPrediction(true, false);
+ }
+
+ return composingText.size(ComposingText::LAYER0) > 0;
+ }
+
+ bool isAlphabetLast(const QString &str)
+ {
+ if (str.isEmpty())
+ return false;
+ ushort ch = str.at(str.size() - 1).unicode();
+ return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
+ }
+
+ void commitTextWithoutLastAlphabet()
+ {
+ QString last = composingText.getStrSegment(targetLayer, -1).string;
+
+ if (isAlphabetLast(last)) {
+ composingText.moveCursor(ComposingText::LAYER1, -1);
+ commitText(false);
+ composingText.moveCursor(ComposingText::LAYER1, 1);
+ } else {
+ commitText(false);
+ }
+ }
+
+ bool processLeftKeyEvent()
+ {
+ if (composingText.size(ComposingText::LAYER1) == 0)
+ return false;
+
+ if (activeConvertType != CONVERT_TYPE_NONE) {
+ if (composingText.getCursor(ComposingText::LAYER1) > 1) {
+ composingText.moveCursor(ComposingText::LAYER1, -1);
+ }
+ } else if (exactMatchMode) {
+ composingText.moveCursor(ComposingText::LAYER1, -1);
+ } else {
+ exactMatchMode = true;
+ }
+
+ if (lcOpenWnn().isDebugEnabled())
+ composingText.debugout();
+
+ commitCount = 0; /* retry consecutive clause conversion if necessary. */
+ updateViewStatus(targetLayer, true, true);
+
+ if (activeConvertType != CONVERT_TYPE_NONE)
+ focusNextCandidate();
+
+ return true;
+ }
+
+ bool processRightKeyEvent()
+ {
+ if (composingText.size(ComposingText::LAYER1) == 0)
+ return false;
+
+ ComposingText::TextLayer layer = targetLayer;
+ if (exactMatchMode || activeConvertType != CONVERT_TYPE_NONE) {
+ int textSize = composingText.size(ComposingText::LAYER1);
+ if (composingText.getCursor(ComposingText::LAYER1) == textSize) {
+ exactMatchMode = false;
+ layer = ComposingText::LAYER1; /* convert -> prediction */
+ activeConvertType = CONVERT_TYPE_NONE;
+ } else {
+ composingText.moveCursor(ComposingText::LAYER1, 1);
+ }
+ } else {
+ if (composingText.getCursor(ComposingText::LAYER1) < composingText.size(ComposingText::LAYER1)) {
+ composingText.moveCursor(ComposingText::LAYER1, 1);
+ }
+ }
+
+ if (lcOpenWnn().isDebugEnabled())
+ composingText.debugout();
+
+ commitCount = 0; /* retry consecutive clause conversion if necessary. */
+
+ updateViewStatus(layer, true, true);
+
+ if (activeConvertType != CONVERT_TYPE_NONE)
+ focusNextCandidate();
+
+ return true;
+ }
+
+ OpenWnnInputMethod *q_ptr;
+ QVirtualKeyboardInputEngine::InputMode inputMode;
+ bool exactMatchMode;
+ QString displayText;
+ OpenWnnEngineJAJP *converter;
+ OpenWnnEngineJAJP converterJAJP;
+ ConvertType activeConvertType;
+ ComposingText composingText;
+ QScopedPointer<LetterConverter> preConverter;
+ bool enableLearning;
+ bool enablePrediction;
+ bool enableConverter;
+ bool disableUpdate;
+ int commitCount;
+ ComposingText::TextLayer targetLayer;
+ QList<QSharedPointer<WnnWord> > candidateList;
+ int activeWordIndex;
+};
+
+/*!
+ \class QtVirtualKeyboard::OpenWnnInputMethod
+ \internal
+*/
+
+OpenWnnInputMethod::OpenWnnInputMethod(QObject *parent) :
+ QVirtualKeyboardAbstractInputMethod(parent),
+ d_ptr(new OpenWnnInputMethodPrivate(this))
+{
+}
+
+OpenWnnInputMethod::~OpenWnnInputMethod()
+{
+}
+
+QList<QVirtualKeyboardInputEngine::InputMode> OpenWnnInputMethod::inputModes(const QString &locale)
+{
+ Q_UNUSED(locale);
+ return QList<QVirtualKeyboardInputEngine::InputMode>()
+ << QVirtualKeyboardInputEngine::InputMode::Hiragana
+ << QVirtualKeyboardInputEngine::InputMode::Katakana
+ << QVirtualKeyboardInputEngine::InputMode::FullwidthLatin
+ << QVirtualKeyboardInputEngine::InputMode::Latin;
+}
+
+bool OpenWnnInputMethod::setInputMode(const QString &locale, QVirtualKeyboardInputEngine::InputMode inputMode)
+{
+ Q_UNUSED(locale);
+ Q_D(OpenWnnInputMethod);
+ if (d->inputMode == inputMode)
+ return true;
+ update();
+ switch (inputMode) {
+ case QVirtualKeyboardInputEngine::InputMode::Hiragana:
+ d->changeEngineMode(OpenWnnInputMethodPrivate::ENGINE_MODE_DEFAULT);
+ break;
+
+ case QVirtualKeyboardInputEngine::InputMode::Katakana:
+ d->changeEngineMode(OpenWnnInputMethodPrivate::ENGINE_MODE_FULL_KATAKANA);
+ break;
+
+ default:
+ d->changeEngineMode(OpenWnnInputMethodPrivate::ENGINE_MODE_DIRECT);
+ break;
+ }
+ d->inputMode = inputMode;
+ d->fitInputType();
+ return true;
+}
+
+bool OpenWnnInputMethod::setTextCase(QVirtualKeyboardInputEngine::TextCase textCase)
+{
+ Q_UNUSED(textCase);
+ return true;
+}
+
+bool OpenWnnInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::KeyboardModifiers modifiers)
+{
+ Q_UNUSED(key);
+ Q_UNUSED(text);
+ Q_UNUSED(modifiers);
+ Q_D(OpenWnnInputMethod);
+
+ if (d->preConverter == nullptr && !d->isEnableL2Converter())
+ return false;
+
+ switch (key) {
+ case Qt::Key_Left:
+ if (d->isEnableL2Converter() && d->composingText.size(ComposingText::LAYER1) > 0)
+ return d->processLeftKeyEvent();
+ else
+ return d->commitText(false);
+ break;
+
+ case Qt::Key_Right:
+ if (d->isEnableL2Converter() && d->composingText.size(ComposingText::LAYER1) > 0)
+ return d->processRightKeyEvent();
+ else
+ return d->commitText(false);
+ break;
+
+ case Qt::Key_Backspace:
+ if (d->composingText.size(ComposingText::LAYER1) > 0) {
+ if (d->activeConvertType == OpenWnnInputMethodPrivate::CONVERT_TYPE_RENBUN) {
+ d->composingText.setCursor(ComposingText::LAYER1,
+ d->composingText.toString(ComposingText::LAYER1).size());
+ d->exactMatchMode = false;
+ d->clearFocusCandidate();
+ } else {
+ if ((d->composingText.size(ComposingText::LAYER1) == 1) &&
+ d->composingText.getCursor(ComposingText::LAYER1) != 0) {
+ d->initializeScreen();
+ return true;
+ } else {
+ d->composingText.deleteAt(ComposingText::LAYER1, false);
+ }
+ }
+ if (lcOpenWnn().isDebugEnabled())
+ d->composingText.debugout();
+ d->updateViewStatusForPrediction(true, true);
+ return true;
+ }
+ break;
+
+ case Qt::Key_Space:
+ if (d->composingText.size(ComposingText::LAYER0) == 0) {
+ d->clearCandidates();
+ d->breakSequence();
+ } else {
+ if (d->targetLayer == ComposingText::LAYER2)
+ d->changeL2Segment(d->focusNextCandidate());
+ else if (d->isEnableL2Converter())
+ d->startConvert(OpenWnnInputMethodPrivate::CONVERT_TYPE_RENBUN);
+ else
+ return d->commitText(false);
+ return true;
+ }
+ break;
+
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ if (d->composingText.size(ComposingText::LAYER0) > 0) {
+ d->commitText(true);
+ return true;
+ }
+ break;
+
+ default:
+ if (key < Qt::Key_Escape && !text.isEmpty() && text.at(0).isPrint()) {
+ if (d->composingText.size(ComposingText::LAYER1) + text.size() > OpenWnnInputMethodPrivate::MAX_COMPOSING_TEXT)
+ return true;
+ const int last = text.size() - 1;
+ for (int i = 0; i <= last; ++i) {
+ if (d->isEnableL2Converter()) {
+ d->commitConvertingText();
+ d->composingText.insertStrSegment(ComposingText::LAYER0, ComposingText::LAYER1, text.mid(i, 1));
+ if (d->preConverter != nullptr)
+ d->preConverter->convert(d->composingText);
+ if (i == last)
+ d->updateViewStatusForPrediction(true, true);
+ } else {
+ d->composingText.insertStrSegment(ComposingText::LAYER0, ComposingText::LAYER1, text.mid(i, 1));
+ QString layer1 = d->composingText.toString(ComposingText::LAYER1);
+ if (!d->isAlphabetLast(layer1)) {
+ d->commitText(false);
+ } else {
+ bool completed = d->preConverter->convert(d->composingText);
+ if (completed) {
+ d->commitTextWithoutLastAlphabet();
+ } else {
+ if (i == last)
+ d->updateViewStatusForPrediction(true, true);
+ }
+ }
+ }
+ }
+ if (lcOpenWnn().isDebugEnabled())
+ d->composingText.debugout();
+ return true;
+ }
+ break;
+ }
+
+ return false;
+}
+
+QList<QVirtualKeyboardSelectionListModel::Type> OpenWnnInputMethod::selectionLists()
+{
+ Q_D(OpenWnnInputMethod);
+ if (!d->enablePrediction)
+ return QList<QVirtualKeyboardSelectionListModel::Type>();
+ return QList<QVirtualKeyboardSelectionListModel::Type>() << QVirtualKeyboardSelectionListModel::Type::WordCandidateList;
+}
+
+int OpenWnnInputMethod::selectionListItemCount(QVirtualKeyboardSelectionListModel::Type type)
+{
+ Q_UNUSED(type);
+ Q_D(OpenWnnInputMethod);
+ return d->candidateList.size();
+}
+
+QVariant OpenWnnInputMethod::selectionListData(QVirtualKeyboardSelectionListModel::Type type, int index, QVirtualKeyboardSelectionListModel::Role role)
+{
+ QVariant result;
+ Q_D(OpenWnnInputMethod);
+ switch (role) {
+ case QVirtualKeyboardSelectionListModel::Role::Display:
+ result = QVariant(d->candidateList.at(index)->candidate);
+ break;
+ case QVirtualKeyboardSelectionListModel::Role::WordCompletionLength:
+ result.setValue(0);
+ break;
+ default:
+ result = QVirtualKeyboardAbstractInputMethod::selectionListData(type, index, role);
+ break;
+ }
+ return result;
+}
+
+void OpenWnnInputMethod::selectionListItemSelected(QVirtualKeyboardSelectionListModel::Type type, int index)
+{
+ Q_UNUSED(type);
+ Q_D(OpenWnnInputMethod);
+ d->activeWordIndex = index;
+ // Set selected text as preeditText to place cursor at the end of selected text
+ inputContext()->setPreeditText(d->candidateList.at(index)->candidate);
+ d->commitText(*d->candidateList.at(index));
+}
+
+void OpenWnnInputMethod::reset()
+{
+ Q_D(OpenWnnInputMethod);
+ d->composingText.clear();
+ d->initializeScreen();
+ d->fitInputType();
+}
+
+void OpenWnnInputMethod::update()
+{
+ Q_D(OpenWnnInputMethod);
+ if (!d->disableUpdate) {
+ d->commitAll();
+ reset();
+ }
+}
+
+} // namespace QtVirtualKeyboard
+QT_END_NAMESPACE