Source code

Revision control

Copy as Markdown

// 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 "xt9cpime.h"
#include "xt9languagemap.h"
#include "xt9dbfile.h"
#include "xt9callbacks.h"
#include <QStandardPaths>
#include <QLoggingCategory>
QT_BEGIN_NAMESPACE
namespace QtVirtualKeyboard {
static const ET9SYMB CANGJIE_MAP[] = {
0x65E5, 0x6708, 0x91D1, 0x6728, 0x6C34, 0x706B, 0x571F, 0x7AF9, 0x6208,
0x5341, 0x5927, 0x4E2D, 0x4E00, 0x5F13, 0x4EBA, 0x5FC3, 0x624B, 0x53E3,
0x5C38, 0x5EFF, 0x5C71, 0x5973, 0x7530, 0x96E3, 0x535C };
static const size_t CANGJIE_MAP_SIZE = sizeof(CANGJIE_MAP) / sizeof(ET9SYMB);
static const ET9SYMB CANGJIE_WILDCARD_SYMB = 0x91CD;
static ET9SYMB GetCangjieMappingSymb(ET9SYMB symb)
{
if (symb == CANGJIE_WILDCARD_SYMB)
return ET9CPCANGJIEWILDCARD;
for (size_t i = 0; i < CANGJIE_MAP_SIZE; i++) {
if (CANGJIE_MAP[i] == symb)
return static_cast<ET9SYMB>(i + 'a');
}
return symb;
}
static ET9SYMB GetCangjieSymb(ET9SYMB symb)
{
if (symb == ET9CPCANGJIEWILDCARD)
return CANGJIE_WILDCARD_SYMB;
if (ET9CPIsCangJieLowerSymbol(symb))
return CANGJIE_MAP[symb - 'a'];
if (ET9CPIsCangJieUpperSymbol(symb))
return CANGJIE_MAP[symb - 'A'];
return symb;
}
class CangjieConverter : public Xt9KeyboardGenerator::CodeConverter {
public:
QString convertTo(const QString &codes) const override
{
QVector<ushort> cangjieBuf(codes.size());
for (int i = 0; i < codes.size(); ++i) {
cangjieBuf[i] = GetCangjieSymb(codes.at(i).unicode());
}
return QString::fromUtf16(reinterpret_cast<const char16_t *>(cangjieBuf.constData()), cangjieBuf.size());
}
QString convertFrom(const QString &codes) const override
{
QVector<ushort> cangjieBuf(codes.size());
for (int i = 0; i < codes.size(); ++i) {
cangjieBuf[i] = GetCangjieMappingSymb(codes.at(i).unicode());
}
return QString::fromUtf16(reinterpret_cast<const char16_t *>(cangjieBuf.constData()), cangjieBuf.size());
}
};
Q_GLOBAL_STATIC(CangjieConverter, cangjieConverter)
Xt9CpIme::Xt9CpIme(Xt9RequestCallback *requestCallback) :
Xt9Ime(requestCallback)
{
}
Xt9KeyboardGenerator::CodeConverter *Xt9CpIme::getCangjieConverter()
{
return cangjieConverter;
}
void Xt9CpIme::sysInit()
{
Xt9Ime::sysInit();
memset(&sLingInfo, 0, sizeof(sLingInfo));
XT9_API(ET9CPSysInit, &sLingInfo, &sWordSymbInfo, this);
}
bool Xt9CpIme::ldbInit(ET9U32 dwFirstLdbNum, ET9U32 dwSecondLdbNum, ET9U32 eInputMode)
{
ET9STATUS eStatus;
Q_UNUSED(dwSecondLdbNum)
eStatus = XT9_API(ET9CPLdbInit, &sLingInfo, dwFirstLdbNum, &ET9CPLdbReadData);
if (!eStatus) {
XT9_API(ET9CPSetInputMode, &sLingInfo, static_cast<ET9CPMode>(eInputMode));
XT9_API(ET9CPClearComponent, &sLingInfo);
XT9_API(ET9CPSetBilingual, &sLingInfo);
}
return !eStatus;
}
qint64 Xt9CpIme::dlmPreferredSize() const
{
return ET9CPDLM_SIZE_NORMAL;
}
bool Xt9CpIme::dlmInit(void *data, qint64 size)
{
ET9STATUS eStatus;
eStatus = XT9_API(ET9CPDLMInit, &sLingInfo, static_cast<ET9CPDLM_info *>(data), static_cast<ET9U32>(size), nullptr);
return !eStatus;
}
QString Xt9CpIme::exactWord(int *wordCompLen)
{
QString exactWord = Xt9Ime::exactWord(wordCompLen);
ET9CPPhrase phrase;
ET9CPSpell spell;
ET9U8 selSymbCount = 0;
if (!XT9_API(ET9CPGetSelection, &sLingInfo, &phrase, &spell, &selSymbCount) && selSymbCount)
exactWord.remove(0, static_cast<int>(selSymbCount));
replaceSpecialSymbol(exactWord);
return exactWord;
}
void Xt9CpIme::replaceSpecialSymbol(QString &exactWord) const
{
for (int i = 0; i < exactWord.length(); ++i) {
ET9SYMB symb = exactWord.at(i).unicode();
if (ET9CPSymToCPTone(symb)) {
exactWord.replace(i, 1, QChar(symb - ET9CPTONE1 + '1'));
} else if (ET9CPIsStrokeSymbol(symb)) {
int strokeIndex = symb - ET9CPSTROKE1;
static const ushort STROKE_TABLE[ET9CPSTROKEWILDCARD - ET9CPSTROKE1 + 1] = {
0x4E00,
0x4E28,
0x4E3F,
0x4E36,
0x4E5B,
'*'
};
exactWord.replace(i, 1, QChar(STROKE_TABLE[strokeIndex]));
}
}
}
QString Xt9CpIme::spell()
{
ET9STATUS eStatus;
ET9CPSpell spell;
eStatus = XT9_API(ET9CPGetSpell, &sLingInfo, &spell);
if (eStatus == ET9STATUS_NEED_SELLIST_BUILD) {
ET9U16 gestureValue;
eStatus = XT9_API(ET9CPBuildSelectionList, &sLingInfo, &gestureValue);
if (eStatus)
return QString();
eStatus = XT9_API(ET9CPGetSpell, &sLingInfo, &spell);
if (eStatus)
return QString();
} else if (eStatus) {
return QString();
}
QString result = QString::fromUtf16(reinterpret_cast<const char16_t *>(spell.pSymbs), spell.bLen);
replaceSpecialSymbol(result);
return result;
}
QStringList Xt9CpIme::buildSelectionList(int *defaultListIndex, ET9U16 *gestureValue, ET9STATUS &eStatus)
{
ET9U16 totalWords;
eStatus = XT9_API(ET9CPBuildSelectionList, &sLingInfo, gestureValue);
if (defaultListIndex)
*defaultListIndex = -1;
if (eStatus)
return QStringList();
eStatus = XT9_API(ET9CPGetPhraseCount, &sLingInfo, &totalWords);
if (defaultListIndex && totalWords > 0 && !exactWord().isEmpty())
*defaultListIndex = 0;
QStringList list;
for (ET9U16 i = 0; i < totalWords; ++i) {
ET9CPPhrase phrase;
ET9CPSpell spell;
ET9CPPhraseSource phraseSource;
eStatus = ET9CPGetPhrase(&sLingInfo, i, &phrase, &spell, &phraseSource);
if (eStatus)
return QStringList();
const QString word = QString::fromUtf16(reinterpret_cast<const char16_t *>(phrase.pSymbs), phrase.bLen);
list.append(word);
}
return list;
}
ET9STATUS Xt9CpIme::selectWord(int index)
{
ET9CPPhrase phrase;
ET9CPSpell spell;
ET9CPPhraseSource phraseSource;
ET9STATUS eStatus;
qCDebug(lcXT9) << "selectWord" << index;
eStatus = XT9_API(ET9CPGetPhrase, &sLingInfo, static_cast<ET9U16>(index), &phrase, &spell, &phraseSource);
if (!eStatus) {
eStatus = XT9_API(ET9CPSelectPhrase, &sLingInfo, static_cast<ET9U16>(index), &spell);
}
return eStatus;
}
void Xt9CpIme::cursorMoved()
{
const ET9U32 maxBufLen = 456;
ET9SYMB buffer[maxBufLen];
ET9_Request request;
request.eType = ET9_REQ_BufferContext;
request.data.sBufferContextInfo.psBuf = buffer;
request.data.sBufferContextInfo.dwMaxBufLen = maxBufLen;
request.data.sBufferContextInfo.dwBufLen = static_cast<ET9U32>(-1);
_requestCallback->request(&request);
if (request.data.sBufferContextInfo.dwBufLen != static_cast<ET9U32>(-1))
ET9CPSetContext(&sLingInfo, request.data.sBufferContextInfo.psBuf, request.data.sBufferContextInfo.dwBufLen);
else
ET9CPSetContext(&sLingInfo, request.data.sBufferContextInfo.psBuf, 0);
}
void Xt9CpIme::commitSelection()
{
XT9_API(ET9CPCommitSelection, &sLingInfo);
}
ET9SYMB Xt9CpIme::lastSymb()
{
const QString word = Xt9Ime::exactWord();
const int wordLength = word.length();
return wordLength > 0 ? word.at(wordLength - 1).unicode() : 0;
}
bool Xt9CpIme::addTone(ET9CPSYMB symb)
{
ET9STATUS eStatus;
eStatus = XT9_API(ET9AddExplicitSymb, sLingInfo.Base.pWordSymbInfo, symb, 0, ET9NOSHIFT, ET9_NO_ACTIVE_INDEX);
if (eStatus)
return false;
eStatus = XT9_API(ET9CPBuildSelectionList, &sLingInfo, nullptr);
if (eStatus) {
XT9_API(ET9ClearOneSymb, sLingInfo.Base.pWordSymbInfo);
return false;
}
return true;
}
ET9STATUS Xt9CpIme::ET9CPLdbReadData(ET9CPLingInfo *pLingInfo, ET9U8 *ET9FARDATA *ppbSrc, ET9U32 *pdwSizeInBytes)
{
return reinterpret_cast<Xt9CpIme *>(pLingInfo->pPublicExtension)->ldbReadData(pLingInfo->dwLdbNum, ppbSrc, pdwSizeInBytes);
}
} // namespace QtVirtualKeyboard
QT_END_NAMESPACE