diff --git a/Telex/Telex.h b/Telex/Telex.h index 04a95d6..122210a 100644 --- a/Telex/Telex.h +++ b/Telex/Telex.h @@ -9,15 +9,6 @@ namespace VietType { namespace Telex { -enum class Tones { - Z, - F, - J, - R, - S, - X, -}; - // State transition is as follows: // Valid (initial) -> Valid|Invalid (by pushing a character) @@ -54,81 +45,31 @@ struct TelexConfig { bool autocorrect = false; }; -class TelexEngine { +class ITelexEngine { public: - explicit TelexEngine(_In_ struct TelexConfig config); - TelexEngine(const TelexEngine&) = delete; - TelexEngine& operator=(const TelexEngine&) = delete; - TelexEngine(TelexEngine&&) = default; - TelexEngine& operator=(TelexEngine&&) = default; - - const TelexConfig& GetConfig() const; - void SetConfig(const TelexConfig& config); - - void Reset(); - TelexStates PushChar(_In_ wchar_t c); - TelexStates Backspace(); - TelexStates Commit(); - TelexStates ForceCommit(); - TelexStates Cancel(); - TelexStates Backconvert(_In_ const std::wstring& s); - - constexpr TelexStates GetState() const { - return _state; - } - std::wstring Retrieve() const; - std::wstring RetrieveRaw() const; - std::wstring Peek() const; - constexpr std::wstring::size_type Count() const { - return _keyBuffer.size(); - } - constexpr Tones GetTone() const { - return _t; - } - constexpr const std::vector& GetRespos() const { - return _respos; - } - constexpr bool IsBackconverted() const { - return _backconverted; - } - constexpr bool IsAutocorrected() const { - return _autocorrected; + virtual ~ITelexEngine() { } - bool CheckInvariants() const; - -private: - struct TelexConfig _config; - - TelexStates _state = TelexStates::Valid; - - std::wstring _keyBuffer; - std::wstring _c1; - std::wstring _v; - std::wstring _c2; - Tones _t = Tones::Z; - int _toneCount = 0; - // don't use bool vector since that's special cased in the STL - /// - /// only use when valid; - /// 1 = uppercase, 0 = lowercase - /// - std::vector _cases; - /// - /// for each character in the _keyBuffer, record which output character it's responsible for, - /// e.g. 'đuống' (dduoongs) _respos = 00122342 (T = tone, C = transition _c1, V = transition _v) - /// C V T - /// note that respos position masks are only valid if state is Valid - /// - std::vector _respos; - int _respos_current = 0; - bool _backconverted = false; - bool _autocorrected = false; - -private: - friend struct TelexEngineImpl; - bool CheckInvariantsBackspace(TelexStates prevState) const; + virtual const TelexConfig& GetConfig() const = 0; + virtual void SetConfig(const TelexConfig& configconfig) = 0; + + virtual void Reset() = 0; + virtual TelexStates PushChar(_In_ wchar_t c) = 0; + virtual TelexStates Backspace() = 0; + virtual TelexStates Commit() = 0; + virtual TelexStates ForceCommit() = 0; + virtual TelexStates Cancel() = 0; + virtual TelexStates Backconvert(_In_ const std::wstring& s) = 0; + + virtual TelexStates GetState() const = 0; + virtual std::wstring Retrieve() const = 0; + virtual std::wstring RetrieveRaw() const = 0; + virtual std::wstring Peek() const = 0; + virtual std::wstring::size_type Count() const = 0; }; +ITelexEngine* TelexNew(const TelexConfig&); +void TelexDelete(ITelexEngine*); + } // namespace Telex } // namespace VietType diff --git a/Telex/TelexEngine.cpp b/Telex/TelexEngine.cpp index 7cfe0c6..f63d6b8 100644 --- a/Telex/TelexEngine.cpp +++ b/Telex/TelexEngine.cpp @@ -12,6 +12,14 @@ namespace VietType { namespace Telex { +ITelexEngine* TelexNew(const TelexConfig& config) { + return new TelexEngine(config); +} + +void TelexDelete(ITelexEngine* engine) { + delete engine; +} + constexpr size_t MaxLength = 10; // enough for "nghieengsz" and "nhuwowngxf" static CharTypes ClassifyCharacter(_In_ wchar_t lc) { @@ -115,107 +123,93 @@ static void ApplyCases(_In_ std::wstring& str, _In_ const std::vector& case } } -struct TelexEngineImpl { - template - static bool TransitionV(TelexEngine& e, const T& source, bool w_mode = false) { - auto it = source.find(e._v); - if (it != source.end() && - (!w_mode || ((e._v != it->second || e._c2.empty()) && !(e._respos.back() & ResposTransitionW)))) { - e._v = it->second; - return true; - } else { - return false; - } - } - - static inline void Invalidate(TelexEngine& e) { - e._respos.push_back(e._respos_current++ | ResposInvalidate); - e._state = TelexStates::Invalid; - } +void TelexEngine::Invalidate() { + _respos.push_back(_respos_current++ | ResposInvalidate); + _state = TelexStates::Invalid; +} - static void InvalidateAndPopBack(TelexEngine& e, wchar_t c) { - assert(e._keyBuffer.length() > 1); - // pop back only if same char entered twice in a row - if (c == ToLower(e._keyBuffer.rbegin()[1])) - e._respos.push_back(e._respos_current++ | ResposDoubleUndo); - else - e._respos.push_back(e._respos_current++ | ResposInvalidate); - e._state = TelexStates::Invalid; - } +void TelexEngine::InvalidateAndPopBack(wchar_t c) { + assert(_keyBuffer.length() > 1); + // pop back only if same char entered twice in a row + if (c == ToLower(_keyBuffer.rbegin()[1])) + _respos.push_back(_respos_current++ | ResposDoubleUndo); + else + _respos.push_back(_respos_current++ | ResposInvalidate); + _state = TelexStates::Invalid; +} - static std::optional> FindTable(const TelexEngine& e) { - if (e._c1 == L"q") { - return valid_v_q.find_opt(e._v); - } else if (e._c1 == L"gi") { - return valid_v_gi.find_opt(e._v); - } else { - if (!e._c2.size() && !e._config.oa_uy_tone1) { - auto it = valid_v_oa_uy.find(e._v); - if (it != valid_v_oa_uy.end()) - return *it; - } - return valid_v.find_opt(e._v); +std::optional> TelexEngine::FindTable() const { + if (_c1 == L"q") { + return valid_v_q.find_opt(_v); + } else if (_c1 == L"gi") { + return valid_v_gi.find_opt(_v); + } else { + if (!_c2.size() && !_config.oa_uy_tone1) { + auto it = valid_v_oa_uy.find(_v); + if (it != valid_v_oa_uy.end()) + return *it; } + return valid_v.find_opt(_v); } +} - static bool GetTonePos(const TelexEngine& e, _In_ bool predict, _Out_ VInfo* vinfo) { - auto found = FindTable(e); - VInfo retinfo = {0, C2Mode::Either}; - if (found) { - retinfo = found->second; - } else if (predict) { - // guess tone position if _v is not known - switch (e._v.size()) { - case 1: - retinfo.tonepos = 0; - retinfo.c2mode = C2Mode::Either; - break; - case 2: - case 3: - retinfo.tonepos = 1; - retinfo.c2mode = C2Mode::Either; - break; - default: - retinfo.tonepos = -1; - retinfo.c2mode = C2Mode::Either; - break; - } - if (e._c1 == L"q") { - // quick fix to prevent pushing tone character when backspacing to 'qu' - retinfo.tonepos = -1; - retinfo.c2mode = C2Mode::Either; - } +bool TelexEngine::GetTonePos(_In_ bool predict, _Out_ VInfo* vinfo) const { + auto found = FindTable(); + VInfo retinfo = {0, C2Mode::Either}; + if (found) { + retinfo = found->second; + } else if (predict) { + // guess tone position if _v is not known + switch (_v.size()) { + case 1: + retinfo.tonepos = 0; + retinfo.c2mode = C2Mode::Either; + break; + case 2: + case 3: + retinfo.tonepos = 1; + retinfo.c2mode = C2Mode::Either; + break; + default: + retinfo.tonepos = -1; + retinfo.c2mode = C2Mode::Either; + break; + } + if (_c1 == L"q") { + // quick fix to prevent pushing tone character when backspacing to 'qu' + retinfo.tonepos = -1; + retinfo.c2mode = C2Mode::Either; } - *vinfo = retinfo; - return found.has_value(); } + *vinfo = retinfo; + return found.has_value(); +} - static void ReapplyTone(TelexEngine& e) { - e._toneCount++; - int found = -1; - for (int i = static_cast(e._respos.size() - 1); i >= 0; i--) { - if (e._respos[i] & ResposTone) { - found = i; - break; - } - } - if (found >= 0) { - e._respos.push_back(found | ResposTone); - } else { - VInfo vinfo; - if (TelexEngineImpl::GetTonePos(e, false, &vinfo)) - e._respos.push_back(static_cast(e._c1.size() + vinfo.tonepos) | ResposTone); - else - e._respos.push_back(static_cast(e._c1.size() + e._v.size() - 1) | ResposTone); +void TelexEngine::ReapplyTone() { + _toneCount++; + int found = -1; + for (int i = static_cast(_respos.size() - 1); i >= 0; i--) { + if (_respos[i] & ResposTone) { + found = i; + break; } } - - static bool HasValidRespos(const TelexEngine& e) { - return std::any_of(e._respos.begin(), e._respos.end(), [](auto rp) { return rp & ResposValidMask; }); + if (found >= 0) { + _respos.push_back(found | ResposTone); + } else { + VInfo vinfo; + if (GetTonePos(false, &vinfo)) + _respos.push_back(static_cast(_c1.size() + vinfo.tonepos) | ResposTone); + else + _respos.push_back(static_cast(_c1.size() + _v.size() - 1) | ResposTone); } -}; +} + +bool TelexEngine::HasValidRespos() const { + return std::any_of(_respos.begin(), _respos.end(), [](auto rp) { return rp & ResposValidMask; }); +} -TelexEngine::TelexEngine(_In_ TelexConfig config) { +TelexEngine::TelexEngine(const TelexConfig& config) { _config = config; _keyBuffer.reserve(MaxLength); _c1.reserve(MaxLength); @@ -265,7 +259,7 @@ TelexStates TelexEngine::PushChar(_In_ wchar_t corig) { _keyBuffer.push_back(corig); if (_state == TelexStates::Invalid || _keyBuffer.size() > MaxLength) { - TelexEngineImpl::Invalidate(*this); + Invalidate(); assert(CheckInvariants()); return _state; } @@ -274,7 +268,7 @@ TelexStates TelexEngine::PushChar(_In_ wchar_t corig) { auto ccase = c != corig; auto cat = ClassifyCharacter(c); if (cat == CharTypes::Uncategorized) { - TelexEngineImpl::Invalidate(*this); + Invalidate(); } else if (_c1.empty() && _v.empty() && IS(cat, CharTypes::ConsoC1)) { // ConsoContinue is a subset of ConsoC1, no need to check @@ -313,10 +307,10 @@ TelexStates TelexEngine::PushChar(_In_ wchar_t corig) { // vowel parts (aeiouy) _v.push_back(c); auto before = _v.size(); - if (TelexEngineImpl::TransitionV(*this, transitions)) { + if (TransitionV(transitions)) { auto after = _v.size(); if (_config.optimize_multilang >= 3 && _toneCount) { - TelexEngineImpl::Invalidate(*this); + Invalidate(); } else if ( _keyBuffer.size() > 1 && _respos.back() & ResposTransitionV && c == ToLower(_keyBuffer.rbegin()[1])) { _cases.push_back(ccase); @@ -350,21 +344,21 @@ TelexStates TelexEngine::PushChar(_In_ wchar_t corig) { if (!_v.empty()) { bool tw; if (_c1 == L"q") { - tw = TelexEngineImpl::TransitionV(*this, transitions_w_q, true); + tw = TransitionV(transitions_w_q, true); } else { - tw = TelexEngineImpl::TransitionV(*this, transitions_w, true); + tw = TransitionV(transitions_w, true); } if (tw) { if (!_c2.empty()) { if (_c1 == L"q") { - TelexEngineImpl::TransitionV(*this, transitions_v_c2_q); + TransitionV(transitions_v_c2_q); } else { - TelexEngineImpl::TransitionV(*this, transitions_v_c2); + TransitionV(transitions_v_c2); } } _respos.push_back(static_cast(_c1.size() + _v.size() - 1) | ResposTransitionW); } else { - TelexEngineImpl::InvalidateAndPopBack(*this, c); + InvalidateAndPopBack(c); } // 'w' always keeps V size constant, don't push case } else if (_config.autocorrect && !_toneCount && (!_c1.empty() || _config.optimize_multilang == 0)) { @@ -372,7 +366,7 @@ TelexStates TelexEngine::PushChar(_In_ wchar_t corig) { _cases.push_back(ccase); _respos.push_back(_respos_current++ | ResposAutocorrect); } else { - TelexEngineImpl::Invalidate(*this); + Invalidate(); } } else if ((_c1 == L"gi" || !_v.empty()) && IS(cat, CharTypes::Tone)) { @@ -380,13 +374,13 @@ TelexStates TelexEngine::PushChar(_In_ wchar_t corig) { auto newtone = GetCharTone(c); if (newtone != _t) { if (_config.optimize_multilang >= 3 && _toneCount) { - TelexEngineImpl::Invalidate(*this); + Invalidate(); } else { _t = newtone; - TelexEngineImpl::ReapplyTone(*this); + ReapplyTone(); } } else { - TelexEngineImpl::InvalidateAndPopBack(*this, c); + InvalidateAndPopBack(c); } } else if (((_c1 == L"gi" && _v.empty()) || !_v.empty()) && _c2.empty() && IS(cat, CharTypes::ConsoC2)) { @@ -403,15 +397,15 @@ TelexStates TelexEngine::PushChar(_In_ wchar_t corig) { } if (success) { if (_c1 == L"q") { - TelexEngineImpl::TransitionV(*this, transitions_v_c2_q); + TransitionV(transitions_v_c2_q); } else { - TelexEngineImpl::TransitionV(*this, transitions_v_c2); + TransitionV(transitions_v_c2); } _c2.push_back(c); _cases.push_back(ccase); _respos.push_back(_respos_current++); } else { - TelexEngineImpl::Invalidate(*this); + Invalidate(); } } else if (_c2.size() && IS(cat, CharTypes::ConsoContinue)) { @@ -421,7 +415,7 @@ TelexStates TelexEngine::PushChar(_In_ wchar_t corig) { _respos.push_back(_respos_current++); } else { - TelexEngineImpl::Invalidate(*this); + Invalidate(); } assert(CheckInvariants()); @@ -465,7 +459,7 @@ TelexStates TelexEngine::Backspace() { // if cannot set tone like in Peek, treat this as invalid (but do not mark word as invalid for further correction) VInfo vinfo; - auto found = TelexEngineImpl::GetTonePos(*this, false, &vinfo); + auto found = GetTonePos(false, &vinfo); if (!found && _t != Tones::Z) { Reset(); if (buf.size()) { @@ -581,13 +575,13 @@ TelexStates TelexEngine::Commit() { _c2 = L"ch"; _cases.push_back(_cases[_c1.length() + _v.length()]); _autocorrected = true; - } else if (_config.optimize_multilang <= 1 || TelexEngineImpl::HasValidRespos(*this)) { + } else if (_config.optimize_multilang <= 1 || HasValidRespos()) { _c2 = L"nh"; _cases.push_back(_cases[_c1.length() + _v.length()]); _autocorrected = true; } } - if (TelexEngineImpl::HasValidRespos(*this)) { + if (HasValidRespos()) { if (_c2 == L"gn") { _c2 = L"ng"; _autocorrected = true; @@ -622,7 +616,7 @@ TelexStates TelexEngine::Commit() { // validate v and get tone position VInfo vinfo; - auto found = TelexEngineImpl::GetTonePos(*this, false, &vinfo); + auto found = GetTonePos(false, &vinfo); if (!found) { _state = TelexStates::CommittedInvalid; assert(CheckInvariants()); @@ -670,7 +664,7 @@ TelexStates TelexEngine::ForceCommit() { } VInfo vinfo; - auto found = TelexEngineImpl::GetTonePos(*this, false, &vinfo); + auto found = GetTonePos(false, &vinfo); if (!found) { _state = TelexStates::CommittedInvalid; assert(CheckInvariants()); @@ -782,7 +776,7 @@ std::wstring TelexEngine::Peek() const { result.append(_v); VInfo vinfo; - auto found = TelexEngineImpl::GetTonePos(*this, false, &vinfo); + auto found = GetTonePos(false, &vinfo); if (!found) { if (_t == Tones::Z) { result.append(_c2); diff --git a/Telex/TelexEngine.h b/Telex/TelexEngine.h index f4d8cff..a8b0a87 100644 --- a/Telex/TelexEngine.h +++ b/Telex/TelexEngine.h @@ -3,9 +3,22 @@ #pragma once +#include +#include +#include + namespace VietType { namespace Telex { +enum class Tones { + Z, + F, + J, + R, + S, + X, +}; + enum class C2Mode { Either, MustC2, @@ -80,5 +93,103 @@ static const CharTypes letterClasses[26] = { CharTypes::Tone, // z }; +class TelexEngine : public ITelexEngine { +public: + explicit TelexEngine(const TelexConfig& config); + TelexEngine(const TelexEngine&) = delete; + TelexEngine& operator=(const TelexEngine&) = delete; + TelexEngine(TelexEngine&&) = default; + TelexEngine& operator=(TelexEngine&&) = default; + virtual ~TelexEngine() { + } + + const TelexConfig& GetConfig() const override; + void SetConfig(const TelexConfig& config) override; + + void Reset() override; + TelexStates PushChar(_In_ wchar_t c) override; + TelexStates Backspace() override; + TelexStates Commit() override; + TelexStates ForceCommit() override; + TelexStates Cancel() override; + TelexStates Backconvert(_In_ const std::wstring& s) override; + + constexpr TelexStates GetState() const override { + return _state; + } + std::wstring Retrieve() const override; + std::wstring RetrieveRaw() const override; + std::wstring Peek() const override; + constexpr std::wstring::size_type Count() const override { + return _keyBuffer.size(); + } + + constexpr Tones GetTone() const { + return _t; + } + constexpr const std::vector& GetRespos() const { + return _respos; + } + constexpr bool IsBackconverted() const { + return _backconverted; + } + constexpr bool IsAutocorrected() const { + return _autocorrected; + } + + bool CheckInvariants() const; + +private: + struct TelexConfig _config; + + TelexStates _state = TelexStates::Valid; + + std::wstring _keyBuffer; + std::wstring _c1; + std::wstring _v; + std::wstring _c2; + Tones _t = Tones::Z; + int _toneCount = 0; + // don't use bool vector since that's special cased in the STL + /// + /// only use when valid; + /// 1 = uppercase, 0 = lowercase + /// + std::vector _cases; + /// + /// for each character in the _keyBuffer, record which output character it's responsible for, + /// e.g. 'đuống' (dduoongs) _respos = 00122342 (T = tone, C = transition _c1, V = transition _v) + /// C V T + /// note that respos position masks are only valid if state is Valid + /// + std::vector _respos; + int _respos_current = 0; + bool _backconverted = false; + bool _autocorrected = false; + +private: + friend struct TelexEngineImpl; + bool CheckInvariantsBackspace(TelexStates prevState) const; + + template + bool TransitionV(const T& source, bool w_mode = false) { + auto it = source.find(_v); + if (it != source.end() && + (!w_mode || ((_v != it->second || _c2.empty()) && !(_respos.back() & ResposTransitionW)))) { + _v = it->second; + return true; + } else { + return false; + } + } + + void Invalidate(); + void InvalidateAndPopBack(wchar_t c); + std::optional> FindTable() const; + bool GetTonePos(_In_ bool predict, _Out_ VInfo* vinfo) const; + void ReapplyTone(); + bool HasValidRespos() const; +}; + } // namespace Telex } // namespace VietType diff --git a/VietTypeATL/EngineController.cpp b/VietTypeATL/EngineController.cpp index 8b343e8..dc704c0 100644 --- a/VietTypeATL/EngineController.cpp +++ b/VietTypeATL/EngineController.cpp @@ -20,7 +20,7 @@ static const GUID GUID_SystemNotifyCompartment = { 0xb2fbd2e7, 0x922f, 0x4996, {0xbe, 0x77, 0x21, 0x8, 0x5b, 0x91, 0xa8, 0xf0}}; _Check_return_ HRESULT -EngineController::Initialize(_In_ Telex::TelexEngine* engine, _In_ ITfThreadMgr* threadMgr, _In_ TfClientId clientid) { +EngineController::Initialize(_In_ Telex::ITelexEngine* engine, _In_ ITfThreadMgr* threadMgr, _In_ TfClientId clientid) { HRESULT hr; @@ -80,11 +80,11 @@ HRESULT EngineController::Uninitialize() { return S_OK; } -Telex::TelexEngine& EngineController::GetEngine() { +Telex::ITelexEngine& EngineController::GetEngine() { return *_engine; } -const Telex::TelexEngine& EngineController::GetEngine() const { +const Telex::ITelexEngine& EngineController::GetEngine() const { return *_engine; } diff --git a/VietTypeATL/EngineController.h b/VietTypeATL/EngineController.h index 00e77fc..9a559d1 100644 --- a/VietTypeATL/EngineController.h +++ b/VietTypeATL/EngineController.h @@ -39,11 +39,11 @@ class EngineController : public CComObjectRootEx { DECLARE_PROTECT_FINAL_CONSTRUCT() _Check_return_ HRESULT - Initialize(_In_ Telex::TelexEngine* engine, _In_ ITfThreadMgr* threadMgr, _In_ TfClientId clientid); + Initialize(_In_ Telex::ITelexEngine* engine, _In_ ITfThreadMgr* threadMgr, _In_ TfClientId clientid); HRESULT Uninitialize(); - Telex::TelexEngine& GetEngine(); - const Telex::TelexEngine& GetEngine() const; + Telex::ITelexEngine& GetEngine(); + const Telex::ITelexEngine& GetEngine() const; DWORD IsBackconvertOnBackspace(); @@ -67,7 +67,7 @@ class EngineController : public CComObjectRootEx { private: bool _initialized = false; - Telex::TelexEngine* _engine = nullptr; + Telex::ITelexEngine* _engine = nullptr; CComPtr _langBarItemMgr; TfClientId _clientid = TF_CLIENTID_NULL; diff --git a/VietTypeATL/KeyTranslator.cpp b/VietTypeATL/KeyTranslator.cpp index 8d983fe..f7659b6 100644 --- a/VietTypeATL/KeyTranslator.cpp +++ b/VietTypeATL/KeyTranslator.cpp @@ -45,7 +45,7 @@ bool VietType::IsKeyEaten( } VietType::Telex::TelexStates VietType::PushKey( - _In_ VietType::Telex::TelexEngine& engine, + _In_ VietType::Telex::ITelexEngine& engine, _In_ uintptr_t wParam, _In_ intptr_t lParam, _In_reads_(256) const unsigned char* keyState) { diff --git a/VietTypeATL/KeyTranslator.h b/VietTypeATL/KeyTranslator.h index 031dcdf..0d29355 100644 --- a/VietTypeATL/KeyTranslator.h +++ b/VietTypeATL/KeyTranslator.h @@ -12,7 +12,7 @@ bool IsEditKey(_In_ uintptr_t wParam, _In_ intptr_t lParam, _In_reads_(256) cons bool IsKeyEaten( _In_ bool isComposing, _In_ uintptr_t wParam, _In_ intptr_t lParam, _In_reads_(256) const unsigned char* keyState); Telex::TelexStates PushKey( - _In_ Telex::TelexEngine& engine, + _In_ Telex::ITelexEngine& engine, _In_ uintptr_t wParam, _In_ intptr_t lParam, _In_reads_(256) const unsigned char* keyState); diff --git a/VietTypeATL/TextService.cpp b/VietTypeATL/TextService.cpp index 8e05786..bead298 100644 --- a/VietTypeATL/TextService.cpp +++ b/VietTypeATL/TextService.cpp @@ -54,7 +54,7 @@ STDMETHODIMP TextService::ActivateEx(_In_ ITfThreadMgr* ptim, _In_ TfClientId ti _clientId = tid; _activateFlags = dwFlags; - _engine = std::make_unique(Telex::TelexConfig{}); + _engine = std::unique_ptr(Telex::TelexNew(Telex::TelexConfig{})); hr = CreateInitialize(&_engineController, _engine.get(), ptim, tid); HRESULT_CHECK_RETURN(hr, L"%s", L"CreateInitialize(&_engineController) failed"); diff --git a/VietTypeATL/TextService.h b/VietTypeATL/TextService.h index 60d6a58..5132210 100644 --- a/VietTypeATL/TextService.h +++ b/VietTypeATL/TextService.h @@ -17,7 +17,7 @@ using namespace ATL; namespace VietType { namespace Telex { -class TelexEngine; +class ITelexEngine; } class ThreadMgrEventSink; @@ -61,7 +61,7 @@ class ATL_NO_VTABLE TextService : public CComObjectRootEx TfClientId _clientId = TF_CLIENTID_NULL; DWORD _activateFlags = 0; - std::unique_ptr _engine; + std::unique_ptr _engine; CComPtr _engineController; diff --git a/VietTypeUnitTests/TestTelex.cpp b/VietTypeUnitTests/TestTelex.cpp index 95f9be5..a9d902a 100644 --- a/VietTypeUnitTests/TestTelex.cpp +++ b/VietTypeUnitTests/TestTelex.cpp @@ -21,15 +21,15 @@ class MultiConfigTester { : _config(config), _omMin(optimizeMultilangMin), _omMax(optimizeMultilangMax), _ac(testAutocorrect) { } - void Invoke(std::function f) const { + void Invoke(std::function f) const { for (int level = _omMin; level <= _omMax; level++) { for (int autocorrect = _ac ? 0 : 1; autocorrect <= 1; autocorrect++) { auto config = _config; config.optimize_multilang = level; if (_ac) config.autocorrect = !!autocorrect; - TelexEngine e(config); - f(e); + std::unique_ptr e(TelexNew(config)); + f(*e); } } } @@ -893,36 +893,36 @@ TEST_CLASS (TestTelex) { TEST_METHOD (TestMultilangVirus) { auto config1 = config; config1.optimize_multilang = 1; - TelexEngine e(config1); - VietType::UnitTests::TestInvalidWord(e, L"virus", L"virus"); + std::unique_ptr e(TelexNew(config1)); + VietType::UnitTests::TestInvalidWord(*e, L"virus", L"virus"); } TEST_METHOD (TestMultilangDense) { auto config1 = config; config1.optimize_multilang = 2; - TelexEngine e(config1); - VietType::UnitTests::TestInvalidWord(e, L"dense", L"dense"); + std::unique_ptr e(TelexNew(config1)); + VietType::UnitTests::TestInvalidWord(*e, L"dense", L"dense"); } TEST_METHOD (TestMultilangDefe) { auto config1 = config; config1.optimize_multilang = 3; - TelexEngine e(config1); - AssertTelexStatesEqual(TelexStates::Invalid, FeedWord(e, L"defe")); + std::unique_ptr e(TelexNew(config1)); + AssertTelexStatesEqual(TelexStates::Invalid, FeedWord(*e, L"defe")); } TEST_METHOD (TestMultilangVirusUpper) { auto config1 = config; config1.optimize_multilang = 1; - TelexEngine e(config1); - VietType::UnitTests::TestInvalidWord(e, L"VIRUS", L"VIRUS"); + std::unique_ptr e(TelexNew(config1)); + VietType::UnitTests::TestInvalidWord(*e, L"VIRUS", L"VIRUS"); } TEST_METHOD (TestMultilangDenseUpper) { auto config1 = config; config1.optimize_multilang = 2; - TelexEngine e(config1); - VietType::UnitTests::TestInvalidWord(e, L"DENSE", L"DENSE"); + std::unique_ptr e(TelexNew(config1)); + VietType::UnitTests::TestInvalidWord(*e, L"DENSE", L"DENSE"); } // test doublekey backspace diff --git a/VietTypeUnitTests/TestWordList.cpp b/VietTypeUnitTests/TestWordList.cpp index 07f2220..0474ebd 100644 --- a/VietTypeUnitTests/TestWordList.cpp +++ b/VietTypeUnitTests/TestWordList.cpp @@ -9,6 +9,7 @@ #include "WordListIterator.hpp" #include "FileUtil.hpp" #include "Util.h" +#include "TelexEngine.h" using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace VietType::Telex; diff --git a/VietTypeUnitTests/Util.cpp b/VietTypeUnitTests/Util.cpp index 9a7e8d8..3c57be4 100644 --- a/VietTypeUnitTests/Util.cpp +++ b/VietTypeUnitTests/Util.cpp @@ -10,7 +10,7 @@ using namespace VietType::Telex; namespace VietType { namespace UnitTests { -TelexStates FeedWord(TelexEngine& e, const wchar_t* input) { +TelexStates FeedWord(ITelexEngine& e, const wchar_t* input) { e.Reset(); for (auto c : std::wstring(input)) { e.PushChar(c); @@ -18,7 +18,7 @@ TelexStates FeedWord(TelexEngine& e, const wchar_t* input) { return e.GetState(); } -void TestValidWord(TelexEngine& e, const wchar_t* expected, const wchar_t* input) { +void TestValidWord(ITelexEngine& e, const wchar_t* expected, const wchar_t* input) { e.Reset(); for (auto c : std::wstring(input)) { AssertTelexStatesEqual(TelexStates::Valid, e.PushChar(c)); @@ -28,7 +28,7 @@ void TestValidWord(TelexEngine& e, const wchar_t* expected, const wchar_t* input Assert::AreEqual(expected, e.Retrieve().c_str()); } -void TestInvalidWord(TelexEngine& e, const wchar_t* expected, const wchar_t* input) { +void TestInvalidWord(ITelexEngine& e, const wchar_t* expected, const wchar_t* input) { e.Reset(); for (auto c : std::wstring(input)) { e.PushChar(c); @@ -37,7 +37,7 @@ void TestInvalidWord(TelexEngine& e, const wchar_t* expected, const wchar_t* inp Assert::AreEqual(expected, e.RetrieveRaw().c_str()); } -void TestPeekWord(TelexEngine& e, const wchar_t* expected, const wchar_t* input) { +void TestPeekWord(ITelexEngine& e, const wchar_t* expected, const wchar_t* input) { FeedWord(e, input); Assert::AreEqual(expected, e.Peek().c_str()); } diff --git a/VietTypeUnitTests/Util.h b/VietTypeUnitTests/Util.h index ea431fa..1d10b72 100644 --- a/VietTypeUnitTests/Util.h +++ b/VietTypeUnitTests/Util.h @@ -15,13 +15,13 @@ inline void AssertTelexStatesEqual(VietType::Telex::TelexStates expected, VietTy Assert::AreEqual(static_cast(expected), static_cast(actual)); } -VietType::Telex::TelexStates FeedWord(VietType::Telex::TelexEngine& e, const wchar_t* input); +VietType::Telex::TelexStates FeedWord(VietType::Telex::ITelexEngine& e, const wchar_t* input); -void TestValidWord(VietType::Telex::TelexEngine& e, const wchar_t* expected, const wchar_t* input); +void TestValidWord(VietType::Telex::ITelexEngine& e, const wchar_t* expected, const wchar_t* input); -void TestInvalidWord(VietType::Telex::TelexEngine& e, const wchar_t* expected, const wchar_t* input); +void TestInvalidWord(VietType::Telex::ITelexEngine& e, const wchar_t* expected, const wchar_t* input); -void TestPeekWord(VietType::Telex::TelexEngine& e, const wchar_t* expected, const wchar_t* input); +void TestPeekWord(VietType::Telex::ITelexEngine& e, const wchar_t* expected, const wchar_t* input); } // namespace UnitTests } // namespace VietType diff --git a/WordLister/Bench.cpp b/WordLister/Bench.cpp index dea47b6..a414d1c 100644 --- a/WordLister/Bench.cpp +++ b/WordLister/Bench.cpp @@ -4,6 +4,7 @@ #include "stdafx.h" #include #include "Telex.h" +#include "TelexEngine.h" #include "WordListIterator.hpp" #include "FileUtil.hpp" diff --git a/WordLister/Fuzz.cpp b/WordLister/Fuzz.cpp index e392668..4909b0c 100644 --- a/WordLister/Fuzz.cpp +++ b/WordLister/Fuzz.cpp @@ -4,6 +4,7 @@ #include "stdafx.h" #include #include "Telex.h" +#include "TelexEngine.h" using namespace VietType::Telex; diff --git a/WordLister/VietScan.cpp b/WordLister/VietScan.cpp index 8911892..21bcf63 100644 --- a/WordLister/VietScan.cpp +++ b/WordLister/VietScan.cpp @@ -5,6 +5,7 @@ #include "Telex.h" #include "WordListIterator.hpp" #include "FileUtil.hpp" +#include "TelexEngine.h" using namespace VietType::Telex; using namespace VietType::TestLib;