1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "tcinputmethod_p.h" |
5 | #include <QtVirtualKeyboard/qvirtualkeyboardinputengine.h> |
6 | #include <QtVirtualKeyboard/qvirtualkeyboardinputcontext.h> |
7 | #if QT_CONFIG(cangjie) |
8 | #include "cangjiedictionary.h" |
9 | #include "cangjietable.h" |
10 | #endif |
11 | #if QT_CONFIG(zhuyin) |
12 | #include "zhuyindictionary.h" |
13 | #include "zhuyintable.h" |
14 | #endif |
15 | #include "phrasedictionary.h" |
16 | #include <QLoggingCategory> |
17 | |
18 | #include <QLibraryInfo> |
19 | #include <QFileInfo> |
20 | |
21 | #include <array> |
22 | |
23 | QT_BEGIN_NAMESPACE |
24 | namespace QtVirtualKeyboard { |
25 | |
26 | Q_LOGGING_CATEGORY(lcTCIme, "qt.virtualkeyboard.tcime" ) |
27 | |
28 | using namespace tcime; |
29 | |
30 | class TCInputMethodPrivate |
31 | { |
32 | Q_DECLARE_PUBLIC(TCInputMethod) |
33 | public: |
34 | |
35 | TCInputMethodPrivate(TCInputMethod *q_ptr) : |
36 | q_ptr(q_ptr), |
37 | inputMode(QVirtualKeyboardInputEngine::InputMode::Latin), |
38 | wordDictionary(nullptr), |
39 | highlightIndex(-1) |
40 | {} |
41 | |
42 | bool setCandidates(const QStringList &values, bool highlightDefault) |
43 | { |
44 | bool candidatesChanged = candidates != values; |
45 | candidates = values; |
46 | highlightIndex = !candidates.isEmpty() && highlightDefault ? 0 : -1; |
47 | return candidatesChanged; |
48 | } |
49 | |
50 | bool clearCandidates() |
51 | { |
52 | if (candidates.isEmpty()) |
53 | return false; |
54 | |
55 | candidates.clear(); |
56 | highlightIndex = -1; |
57 | return true; |
58 | } |
59 | |
60 | QString pickHighlighted() const |
61 | { |
62 | return (highlightIndex >= 0 && highlightIndex < candidates.size()) ? candidates[highlightIndex] : QString(); |
63 | } |
64 | |
65 | void reset() |
66 | { |
67 | if (clearCandidates()) { |
68 | Q_Q(TCInputMethod); |
69 | emit q->selectionListChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList); |
70 | emit q->selectionListActiveItemChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList, index: highlightIndex); |
71 | } |
72 | input.clear(); |
73 | } |
74 | |
75 | bool compose(const QChar &c) |
76 | { |
77 | bool accept; |
78 | Q_Q(TCInputMethod); |
79 | QVirtualKeyboardInputContext *ic = q->inputContext(); |
80 | switch (inputMode) |
81 | { |
82 | #if QT_CONFIG(cangjie) |
83 | case QVirtualKeyboardInputEngine::InputMode::Cangjie: |
84 | accept = composeCangjie(ic, c); |
85 | break; |
86 | #endif |
87 | #if QT_CONFIG(zhuyin) |
88 | case QVirtualKeyboardInputEngine::InputMode::Zhuyin: |
89 | accept = composeZhuyin(ic, c); |
90 | break; |
91 | #endif |
92 | default: |
93 | accept = false; |
94 | break; |
95 | } |
96 | return accept; |
97 | } |
98 | |
99 | #if QT_CONFIG(cangjie) |
100 | bool composeCangjie(QVirtualKeyboardInputContext *ic, const QChar &c) |
101 | { |
102 | bool accept = false; |
103 | if (!input.contains(c: QChar(0x91CD)) && CangjieTable::isLetter(c)) { |
104 | if (input.size() < (cangjieDictionary.simplified() ? CangjieTable::MAX_SIMPLIFIED_CODE_LENGTH : CangjieTable::MAX_CODE_LENGTH)) { |
105 | input.append(c); |
106 | ic->setPreeditText(text: input); |
107 | if (setCandidates(values: wordDictionary->getWords(input), highlightDefault: true)) { |
108 | Q_Q(TCInputMethod); |
109 | emit q->selectionListChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList); |
110 | emit q->selectionListActiveItemChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList, index: highlightIndex); |
111 | } |
112 | } |
113 | accept = true; |
114 | } else if (c.unicode() == 0x91CD) { |
115 | if (input.isEmpty()) { |
116 | input.append(c); |
117 | ic->setPreeditText(text: input); |
118 | checkSpecialCharInput(); |
119 | } |
120 | accept = true; |
121 | } else if (c.unicode() == 0x96E3) { |
122 | if (input.size() == 1) { |
123 | Q_ASSERT(input.at(0).unicode() == 0x91CD); |
124 | input.append(c); |
125 | ic->setPreeditText(text: input); |
126 | checkSpecialCharInput(); |
127 | } |
128 | accept = true; |
129 | } |
130 | return accept; |
131 | } |
132 | |
133 | bool checkSpecialCharInput() |
134 | { |
135 | if (input.size() == 1 && input.at(i: 0).unicode() == 0x91CD) { |
136 | static const QStringList specialChars1 = QStringList() |
137 | << QChar(0xFF01) << QChar(0x2018) << QChar(0x3000) << QChar(0xFF0C) |
138 | << QChar(0x3001) << QChar(0x3002) << QChar(0xFF0E) << QChar(0xFF1B) |
139 | << QChar(0xFF1A) << QChar(0xFF1F) << QChar(0x300E) << QChar(0x300F) |
140 | << QChar(0x3010) << QChar(0x3011) << QChar(0xFE57) << QChar(0x2026) |
141 | << QChar(0x2025) << QChar(0xFE50) << QChar(0xFE51) << QChar(0xFE52) |
142 | << QChar(0x00B7) << QChar(0xFE54) << QChar(0x2574) << QChar(0x2027) |
143 | << QChar(0x2032) << QChar(0x2035) << QChar(0x301E) << QChar(0x301D) |
144 | << QChar(0x201D) << QChar(0x201C) << QChar(0x2019) << QChar(0xFE55) |
145 | << QChar(0xFE5D) << QChar(0xFE5E) << QChar(0xFE59) << QChar(0xFE5A) |
146 | << QChar(0xFE5B) << QChar(0xFE5C) << QChar(0xFE43) << QChar(0xFE44); |
147 | Q_Q(TCInputMethod); |
148 | if (setCandidates(values: specialChars1, highlightDefault: true)) { |
149 | emit q->selectionListChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList); |
150 | emit q->selectionListActiveItemChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList, index: highlightIndex); |
151 | } |
152 | q->inputContext()->setPreeditText(text: candidates[highlightIndex]); |
153 | return true; |
154 | } else if (input.size() == 2 && input.at(i: 0).unicode() == 0x91CD && input.at(i: 1).unicode() == 0x96E3) { |
155 | static const QStringList specialChars2 = QStringList() |
156 | << QChar(0x3008) << QChar(0x3009) << QChar(0xFE31) << QChar(0x2013) |
157 | << QChar(0xFF5C) << QChar(0x300C) << QChar(0x300D) << QChar(0xFE40) |
158 | << QChar(0xFE3F) << QChar(0x2014) << QChar(0xFE3E) << QChar(0xFE3D) |
159 | << QChar(0x300A) << QChar(0x300B) << QChar(0xFE3B) << QChar(0xFE3C) |
160 | << QChar(0xFE56) << QChar(0xFE30) << QChar(0xFE39) << QChar(0xFE3A) |
161 | << QChar(0x3014) << QChar(0x3015) << QChar(0xFE37) << QChar(0xFE38) |
162 | << QChar(0xFE41) << QChar(0xFE42) << QChar(0xFF5B) << QChar(0xFF5D) |
163 | << QChar(0xFE35) << QChar(0xFE36) << QChar(0xFF08) << QChar(0xFF09) |
164 | << QChar(0xFE4F) << QChar(0xFE34) << QChar(0xFE33); |
165 | Q_Q(TCInputMethod); |
166 | if (setCandidates(values: specialChars2, highlightDefault: true)) { |
167 | emit q->selectionListChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList); |
168 | emit q->selectionListActiveItemChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList, index: highlightIndex); |
169 | } |
170 | q->inputContext()->setPreeditText(text: candidates[highlightIndex]); |
171 | return true; |
172 | } |
173 | return false; |
174 | } |
175 | #endif |
176 | |
177 | #if QT_CONFIG(zhuyin) |
178 | bool composeZhuyin(QVirtualKeyboardInputContext *ic, const QChar &c) |
179 | { |
180 | if (ZhuyinTable::isTone(c)) { |
181 | if (input.isEmpty()) |
182 | // Tones are accepted only when there's text in composing. |
183 | return false; |
184 | |
185 | auto strippedTones = ZhuyinTable::stripTones(input); |
186 | if (!strippedTones.ok) |
187 | // Tones cannot be composed if there's no syllables. |
188 | return false; |
189 | |
190 | // Replace the original tone with the new tone, but the default tone |
191 | // character should not be composed into the composing text. |
192 | QChar tone = strippedTones.pair[1].at(n: 0); |
193 | if (c == ZhuyinTable::DEFAULT_TONE) { |
194 | if (tone != ZhuyinTable::DEFAULT_TONE) |
195 | input.remove(i: input.size() - 1, len: 1); |
196 | } else { |
197 | if (tone == ZhuyinTable::DEFAULT_TONE) |
198 | input.append(c); |
199 | else |
200 | input.replace(i: input.size() - 1, len: 1, after: c); |
201 | } |
202 | } else if (ZhuyinTable::getInitials(initials: c) > 0) { |
203 | // Insert the initial or replace the original initial. |
204 | if (input.isEmpty() || !ZhuyinTable::getInitials(initials: input.at(i: 0))) |
205 | input.insert(i: 0, c); |
206 | else |
207 | input.replace(i: 0, len: 1, after: c); |
208 | } else if (ZhuyinTable::getFinals(finals: QStringView(&c, 1)) > 0) { |
209 | // Replace the finals in the decomposed of syllables and tones. |
210 | std::array<QChar, 4> decomposed = decomposeZhuyin(); |
211 | if (ZhuyinTable::isYiWuYuFinals(c)) { |
212 | decomposed[1] = c; |
213 | } else { |
214 | decomposed[2] = c; |
215 | } |
216 | |
217 | // Compose back the text after the finals replacement. |
218 | input.clear(); |
219 | for (QChar ch : decomposed) { |
220 | if (!ch.isNull()) |
221 | input.append(c: ch); |
222 | } |
223 | } else { |
224 | return false; |
225 | } |
226 | |
227 | ic->setPreeditText(text: input); |
228 | if (setCandidates(values: wordDictionary->getWords(input), highlightDefault: true)) { |
229 | Q_Q(TCInputMethod); |
230 | emit q->selectionListChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList); |
231 | emit q->selectionListActiveItemChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList, index: highlightIndex); |
232 | } |
233 | |
234 | return true; |
235 | } |
236 | |
237 | std::array<QChar, 4> decomposeZhuyin() |
238 | { |
239 | std::array<QChar, 4> results = {}; |
240 | auto strippedTones = ZhuyinTable::stripTones(input); |
241 | if (strippedTones.ok) { |
242 | // Decompose tones. |
243 | QChar tone = strippedTones.pair[1].at(n: 0); |
244 | if (tone != ZhuyinTable::DEFAULT_TONE) |
245 | results[3] = tone; |
246 | |
247 | // Decompose initials. |
248 | QStringView syllables = strippedTones.pair[0]; |
249 | if (ZhuyinTable::getInitials(initials: syllables.at(n: 0)) > 0) { |
250 | results[0] = syllables.at(n: 0); |
251 | syllables = syllables.mid(pos: 1); |
252 | } |
253 | |
254 | // Decompose finals. |
255 | if (!syllables.isEmpty()) { |
256 | if (ZhuyinTable::isYiWuYuFinals(c: syllables.at(n: 0))) { |
257 | results[1] = syllables.at(n: 0); |
258 | if (syllables.size() > 1) |
259 | results[2] = syllables.at(n: 1); |
260 | } else { |
261 | results[2] = syllables.at(n: 0); |
262 | } |
263 | } |
264 | } |
265 | return results; |
266 | } |
267 | #endif |
268 | |
269 | TCInputMethod *q_ptr; |
270 | QVirtualKeyboardInputEngine::InputMode inputMode; |
271 | #if QT_CONFIG(cangjie) |
272 | CangjieDictionary cangjieDictionary; |
273 | #endif |
274 | #if QT_CONFIG(zhuyin) |
275 | ZhuyinDictionary zhuyinDictionary; |
276 | #endif |
277 | PhraseDictionary phraseDictionary; |
278 | WordDictionary *wordDictionary; |
279 | QString input; |
280 | QStringList candidates; |
281 | int highlightIndex; |
282 | }; |
283 | |
284 | /*! |
285 | \class QtVirtualKeyboard::TCInputMethod |
286 | \internal |
287 | */ |
288 | |
289 | TCInputMethod::TCInputMethod(QObject *parent) : |
290 | QVirtualKeyboardAbstractInputMethod(parent), |
291 | d_ptr(new TCInputMethodPrivate(this)) |
292 | { |
293 | } |
294 | |
295 | TCInputMethod::~TCInputMethod() |
296 | { |
297 | } |
298 | |
299 | bool TCInputMethod::simplified() const |
300 | { |
301 | #if QT_CONFIG(cangjie) |
302 | Q_D(const TCInputMethod); |
303 | return d->cangjieDictionary.simplified(); |
304 | #else |
305 | return false; |
306 | #endif |
307 | } |
308 | |
309 | void TCInputMethod::setSimplified(bool simplified) |
310 | { |
311 | qCDebug(lcTCIme) << "TCInputMethod::setSimplified(): " << simplified; |
312 | #if QT_CONFIG(cangjie) |
313 | Q_D(TCInputMethod); |
314 | if (d->cangjieDictionary.simplified() != simplified) { |
315 | d->reset(); |
316 | QVirtualKeyboardInputContext *ic = inputContext(); |
317 | if (ic) |
318 | ic->clear(); |
319 | d->cangjieDictionary.setSimplified(simplified); |
320 | emit simplifiedChanged(); |
321 | } |
322 | #else |
323 | Q_UNUSED(simplified); |
324 | #endif |
325 | } |
326 | |
327 | QList<QVirtualKeyboardInputEngine::InputMode> TCInputMethod::inputModes(const QString &locale) |
328 | { |
329 | Q_UNUSED(locale); |
330 | return QList<QVirtualKeyboardInputEngine::InputMode>() |
331 | #if QT_CONFIG(zhuyin) |
332 | << QVirtualKeyboardInputEngine::InputMode::Zhuyin |
333 | #endif |
334 | #if QT_CONFIG(cangjie) |
335 | << QVirtualKeyboardInputEngine::InputMode::Cangjie |
336 | #endif |
337 | ; |
338 | } |
339 | |
340 | bool TCInputMethod::setInputMode(const QString &locale, QVirtualKeyboardInputEngine::InputMode inputMode) |
341 | { |
342 | Q_UNUSED(locale); |
343 | Q_D(TCInputMethod); |
344 | if (d->inputMode == inputMode) |
345 | return true; |
346 | update(); |
347 | bool result = false; |
348 | d->inputMode = inputMode; |
349 | d->wordDictionary = nullptr; |
350 | #if QT_CONFIG(cangjie) |
351 | if (inputMode == QVirtualKeyboardInputEngine::InputMode::Cangjie) { |
352 | if (d->cangjieDictionary.isEmpty()) { |
353 | QString cangjieDictionary(qEnvironmentVariable(varName: "QT_VIRTUALKEYBOARD_CANGJIE_DICTIONARY" )); |
354 | if (!QFileInfo::exists(file: cangjieDictionary)) { |
355 | cangjieDictionary = QLibraryInfo::path(p: QLibraryInfo::DataPath) + QLatin1String("/qtvirtualkeyboard/tcime/dict_cangjie.dat" ); |
356 | if (!QFileInfo::exists(file: cangjieDictionary)) |
357 | cangjieDictionary = QLatin1String(":/qt-project.org/imports/QtQuick/VirtualKeyboard/3rdparty/tcime/data/qt/dict_cangjie.dat" ); |
358 | } |
359 | d->cangjieDictionary.load(fileName: cangjieDictionary); |
360 | } |
361 | d->wordDictionary = &d->cangjieDictionary; |
362 | } |
363 | #endif |
364 | #if QT_CONFIG(zhuyin) |
365 | if (inputMode == QVirtualKeyboardInputEngine::InputMode::Zhuyin) { |
366 | if (d->zhuyinDictionary.isEmpty()) { |
367 | QString zhuyinDictionary(qEnvironmentVariable(varName: "QT_VIRTUALKEYBOARD_ZHUYIN_DICTIONARY" )); |
368 | if (!QFileInfo::exists(file: zhuyinDictionary)) { |
369 | zhuyinDictionary = QLibraryInfo::path(p: QLibraryInfo::DataPath) + QLatin1String("/qtvirtualkeyboard/tcime/dict_zhuyin.dat" ); |
370 | if (!QFileInfo::exists(file: zhuyinDictionary)) |
371 | zhuyinDictionary = QLatin1String(":/qt-project.org/imports/QtQuick/VirtualKeyboard/3rdparty/tcime/data/qt/dict_zhuyin.dat" ); |
372 | } |
373 | d->zhuyinDictionary.load(fileName: zhuyinDictionary); |
374 | } |
375 | d->wordDictionary = &d->zhuyinDictionary; |
376 | } |
377 | #endif |
378 | result = d->wordDictionary && !d->wordDictionary->isEmpty(); |
379 | if (result && d->phraseDictionary.isEmpty()) { |
380 | QString phraseDictionary(qEnvironmentVariable(varName: "QT_VIRTUALKEYBOARD_PHRASE_DICTIONARY" )); |
381 | if (!QFileInfo::exists(file: phraseDictionary)) { |
382 | phraseDictionary = QLibraryInfo::path(p: QLibraryInfo::DataPath) + QLatin1String("/qtvirtualkeyboard/tcime/dict_phrases.dat" ); |
383 | if (!QFileInfo::exists(file: phraseDictionary)) |
384 | phraseDictionary = QLatin1String(":/qt-project.org/imports/QtQuick/VirtualKeyboard/3rdparty/tcime/data/qt/dict_phrases.dat" ); |
385 | } |
386 | d->phraseDictionary.load(fileName: phraseDictionary); |
387 | } |
388 | if (!result) |
389 | inputMode = QVirtualKeyboardInputEngine::InputMode::Latin; |
390 | return result; |
391 | } |
392 | |
393 | bool TCInputMethod::setTextCase(QVirtualKeyboardInputEngine::TextCase textCase) |
394 | { |
395 | Q_UNUSED(textCase); |
396 | return true; |
397 | } |
398 | |
399 | bool TCInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::KeyboardModifiers modifiers) |
400 | { |
401 | Q_UNUSED(key); |
402 | Q_UNUSED(text); |
403 | Q_UNUSED(modifiers); |
404 | Q_D(TCInputMethod); |
405 | QVirtualKeyboardInputContext *ic = inputContext(); |
406 | bool accept = false; |
407 | switch (key) { |
408 | case Qt::Key_Context1: |
409 | // Do nothing on symbol mode switch |
410 | accept = true; |
411 | break; |
412 | |
413 | case Qt::Key_Enter: |
414 | case Qt::Key_Return: |
415 | update(); |
416 | break; |
417 | |
418 | case Qt::Key_Tab: |
419 | case Qt::Key_Space: |
420 | if (!d->input.isEmpty()) { |
421 | accept = true; |
422 | if (d->highlightIndex >= 0) { |
423 | QString finalWord = d->pickHighlighted(); |
424 | d->reset(); |
425 | inputContext()->commit(text: finalWord); |
426 | if (d->setCandidates(values: d->phraseDictionary.getWords(input: finalWord.left(n: 1)), highlightDefault: false)) { |
427 | emit selectionListChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList); |
428 | emit selectionListActiveItemChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList, index: d->highlightIndex); |
429 | } |
430 | } |
431 | } else { |
432 | update(); |
433 | } |
434 | break; |
435 | |
436 | case Qt::Key_Backspace: |
437 | if (!d->input.isEmpty()) { |
438 | d->input.remove(i: d->input.size() - 1, len: 1); |
439 | ic->setPreeditText(text: d->input); |
440 | #if QT_CONFIG(cangjie) |
441 | if (!d->checkSpecialCharInput()) { |
442 | #endif |
443 | if (d->setCandidates(values: d->wordDictionary->getWords(input: d->input), highlightDefault: true)) { |
444 | emit selectionListChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList); |
445 | emit selectionListActiveItemChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList, index: d->highlightIndex); |
446 | } |
447 | #if QT_CONFIG(cangjie) |
448 | } |
449 | #endif |
450 | accept = true; |
451 | } else if (d->clearCandidates()) { |
452 | emit selectionListChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList); |
453 | emit selectionListActiveItemChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList, index: d->highlightIndex); |
454 | } |
455 | break; |
456 | |
457 | default: |
458 | if (text.size() == 1) |
459 | accept = d->compose(c: text.at(i: 0)); |
460 | if (!accept) |
461 | update(); |
462 | break; |
463 | } |
464 | return accept; |
465 | } |
466 | |
467 | QList<QVirtualKeyboardSelectionListModel::Type> TCInputMethod::selectionLists() |
468 | { |
469 | return QList<QVirtualKeyboardSelectionListModel::Type>() << QVirtualKeyboardSelectionListModel::Type::WordCandidateList; |
470 | } |
471 | |
472 | int TCInputMethod::selectionListItemCount(QVirtualKeyboardSelectionListModel::Type type) |
473 | { |
474 | Q_UNUSED(type); |
475 | Q_D(TCInputMethod); |
476 | return d->candidates.size(); |
477 | } |
478 | |
479 | QVariant TCInputMethod::selectionListData(QVirtualKeyboardSelectionListModel::Type type, int index, QVirtualKeyboardSelectionListModel::Role role) |
480 | { |
481 | QVariant result; |
482 | Q_D(TCInputMethod); |
483 | switch (role) { |
484 | case QVirtualKeyboardSelectionListModel::Role::Display: |
485 | result = QVariant(d->candidates.at(i: index)); |
486 | break; |
487 | case QVirtualKeyboardSelectionListModel::Role::WordCompletionLength: |
488 | result.setValue(0); |
489 | break; |
490 | default: |
491 | result = QVirtualKeyboardAbstractInputMethod::selectionListData(type, index, role); |
492 | break; |
493 | } |
494 | return result; |
495 | } |
496 | |
497 | void TCInputMethod::selectionListItemSelected(QVirtualKeyboardSelectionListModel::Type type, int index) |
498 | { |
499 | Q_UNUSED(type); |
500 | Q_D(TCInputMethod); |
501 | QString finalWord = d->candidates.at(i: index); |
502 | reset(); |
503 | inputContext()->commit(text: finalWord); |
504 | if (d->setCandidates(values: d->phraseDictionary.getWords(input: finalWord.left(n: 1)), highlightDefault: false)) { |
505 | emit selectionListChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList); |
506 | emit selectionListActiveItemChanged(type: QVirtualKeyboardSelectionListModel::Type::WordCandidateList, index: d->highlightIndex); |
507 | } |
508 | } |
509 | |
510 | void TCInputMethod::reset() |
511 | { |
512 | Q_D(TCInputMethod); |
513 | d->reset(); |
514 | } |
515 | |
516 | void TCInputMethod::update() |
517 | { |
518 | Q_D(TCInputMethod); |
519 | if (d->highlightIndex >= 0) { |
520 | QString finalWord = d->pickHighlighted(); |
521 | d->reset(); |
522 | inputContext()->commit(text: finalWord); |
523 | } else { |
524 | inputContext()->clear(); |
525 | d->reset(); |
526 | } |
527 | } |
528 | |
529 | } // namespace QtVirtualKeyboard |
530 | QT_END_NAMESPACE |
531 | |