From 309774e67b29dd800974613ed419e2b0372f5df6 Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Mon, 2 Nov 2026 19:33:35 +0000 Subject: [PATCH] Maintenance: [forced, user-approved] CLanguage steps 2-4 (resubmit of #10182, which was returned only for the global rule). Fix: the Batch #10183 by ragnarok-clanker: forced by an admin (6 lower score(s), 50 changed function(s)); checked with 115 compiled unit(s), including every includer of Source/Client/Input/InputCharset.h, Source/Client/Input/Language.h, Source/Client/Input/LanguageTC.h, Source/UI/Chat/ChatNotifications.h, Source/UI/Edit/UIEditCtrl.h, Source/UI/Text/TextWrapping.h, Source/Client/Input/ImeInput.h. Deletes: Source/Client/Input/ImeInput.h --- Source/Client/Input/ImeInput.cpp | 64 ++++++------- Source/Client/Input/ImeInput.h | 30 ------- Source/Client/Input/InputCharset.cpp | 6 +- Source/Client/Input/InputCharset.h | 68 +------------- Source/Client/Input/Language.cpp | 90 ++++++++++++------- Source/Client/Input/Language.h | 27 +++++- Source/Client/Input/LanguageTC.cpp | 50 ++++++----- Source/Client/Input/LanguageTC.h | 41 +++++---- Source/Client/Mode/GameModePackets.cpp | 2 +- .../Configuration/ServiceConfiguration.cpp | 11 +-- Source/Resource/TextureNames.cpp | 2 +- Source/UI/Acceptance/UIChooseSellBuyWnd.cpp | 4 +- Source/UI/Buttons/UITextButton.cpp | 2 +- Source/UI/Chat/ChatNotifications.h | 2 +- Source/UI/Edit/UIEditCtrl.h | 3 +- Source/UI/Lists/UIComboBoxDefWnd.cpp | 4 +- Source/UI/Lists/UITagListBox.cpp | 2 +- Source/UI/Party/UIApplyForPartyWnd.cpp | 2 +- Source/UI/Party/UIRegisterPartyWnd.cpp | 2 +- Source/UI/Party/UIRequestJoinPartyWnd.cpp | 2 +- Source/UI/Text/TextWrapping.cpp | 9 +- Source/UI/Text/TextWrapping.h | 4 +- Source/UI/Text/UIBalloonText.cpp | 6 +- Source/UI/Text/UITextViewerMessages.cpp | 4 +- Source/UI/UIRoundBoxTooltipWnd.cpp | 2 +- Source/UI/Window/UIFrameWnd.cpp | 2 +- Source/UI/Window/UIWindow.cpp | 2 +- Source/UI/Window/UIWindowMgr.cpp | 2 +- 28 files changed, 206 insertions(+), 239 deletions(-) delete mode 100644 Source/Client/Input/ImeInput.h diff --git a/Source/Client/Input/ImeInput.cpp b/Source/Client/Input/ImeInput.cpp index f34913c0..b94c0638 100644 --- a/Source/Client/Input/ImeInput.cpp +++ b/Source/Client/Input/ImeInput.cpp @@ -1,50 +1,50 @@ -#include "Client/Input/ImeInput.h" -#include "Client/Input/LanguageTC.h" +#include "Client/Application/ApplicationWindow.h" +#include "Client/Input/Language.h" +#include "Network/TextEncoding.h" #include "Utility/Text/LanguageCharset.h" +#include "Utility/Text/TextTokens.h" #include +#include +#include #include // OFFSET: 0x00ACEF00 // FUNCTION: fn_17793 -LRESULT ImeInput::Message(HWND, UINT message, WPARAM value, LPARAM flags, std::uint8_t& handled) { +LRESULT CLanguageBase::Message(HWND, UINT message, WPARAM value, LPARAM flags, std::uint8_t& handled) { const auto options = static_cast(flags); switch (message) { case WM_INPUTLANGCHANGE: this->language = options; - this->codePage = this->languageCodePage ? LanguageCodePage(options) : this->fallbackCodePage; + this->codePage = g_inlineCharset ? LanguageCodePage(options) : g_textCodePage; break; case WM_IME_STARTCOMPOSITION: - this->input.DeleteSelection(); + this->ResetState(); + this->DeleteSelection(); break; case WM_IME_ENDCOMPOSITION: - if (this->traditional) { - this->traditional->ClearKeys(); - } - this->input.candidate.clear(); + this->EndComposition(); + this->candidate.assign("", 0); break; case WM_IME_COMPOSITION: if (options & GCS_COMPSTR) { - this->input.RefreshComposition(this->codePage); - if (this->traditional) { - this->traditional->FilterCandidate(this->input.candidate); - this->traditional->RetainSingleKey(); - } + this->RefreshComposition(); + this->ResetCandidate(); } if (options & GCS_CURSORPOS) { - HIMC context = ImmGetContext(this->input.window); + HIMC context = ImmGetContext(hWnd); if (context) { ImmGetCompositionStringA(context, GCS_CURSORPOS, &this->compositionCursor, sizeof(this->compositionCursor)); - ImmReleaseContext(this->input.window, context); + ImmReleaseContext(hWnd, context); } else { - this->input.candidate.clear(); + this->candidate.clear(); } } if (options & GCS_RESULTSTR) { - HIMC context = ImmGetContext(this->input.window); + HIMC context = ImmGetContext(hWnd); if (context) { WCHAR wide[256]; char converted[256]; @@ -56,35 +56,35 @@ LRESULT ImeInput::Message(HWND, UINT message, WPARAM value, LPARAM flags, std::u } converted[size] = 0; - ImmReleaseContext(this->input.window, context); - this->input.Insert(converted); + ImmReleaseContext(hWnd, context); + this->Insert(converted); } else { - this->input.candidate.clear(); + this->candidate.clear(); } } break; case WM_IME_NOTIFY: if (value == IMN_OPENCANDIDATE || value == IMN_CHANGECANDIDATE) { - HIMC context = ImmGetContext(this->input.window); + HIMC context = ImmGetContext(hWnd); if (context) { const auto bytes = ImmGetCandidateListW(context, 0, nullptr, 0); if (static_cast(bytes) > 0) { this->candidateStorage.resize(bytes); - this->candidateList = reinterpret_cast(this->candidateStorage.data()); + this->candidateList = reinterpret_cast(this->candidateStorage.empty() ? nullptr : this->candidateStorage.data()); ImmGetCandidateListW(context, 0, this->candidateList, bytes); - this->input.compositionState = this->candidateList->dwCount; - this->selection = this->candidateList->dwSelection; - this->pageSize = std::min(this->candidateList->dwPageSize, 9); + this->candidateCount = static_cast(this->candidateList->dwCount); + this->selection = static_cast(this->candidateList->dwSelection); + this->pageSize = static_cast(std::min(this->candidateList->dwPageSize, 9)); } else { - this->input.compositionState = 0; + this->candidateCount = 0; } - ImmReleaseContext(this->input.window, context); + ImmReleaseContext(hWnd, context); } else { - this->input.compositionState = 0; + this->candidateCount = 0; } } else if (value == IMN_CLOSECANDIDATE) { - this->input.compositionState = 0; + this->candidateCount = 0; } break; default: @@ -98,12 +98,12 @@ LRESULT ImeInput::Message(HWND, UINT message, WPARAM value, LPARAM flags, std::u // OFFSET: 0x00ACD840 // FUNCTION: fn_17770 -const char* ImeInput::Candidate(int index) const { +const char* CLanguageBase::Candidate(int index) const { // STATIC: 0x016D3978 // GLOBAL: gl_24374 static char output[256]; - if (index >= this->input.compositionState) { + if (index >= this->candidateCount) { return ""; } diff --git a/Source/Client/Input/ImeInput.h b/Source/Client/Input/ImeInput.h deleted file mode 100644 index c77cdbc4..00000000 --- a/Source/Client/Input/ImeInput.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef RAGNAROK_SOURCE_CLIENT_INPUT_IMEINPUT_H -#define RAGNAROK_SOURCE_CLIENT_INPUT_IMEINPUT_H - -#include "Client/Input/Language.h" - -#include -#include -#include - -struct CLanguageTC; - -struct ImeInput { - CLanguage& input; - std::uint16_t& language; - unsigned& codePage; - const bool& languageCodePage; - const unsigned& fallbackCodePage; - std::vector& candidateStorage; - CANDIDATELIST*& candidateList; - unsigned& selection; - unsigned& pageSize; - int& compositionCursor; - CLanguageTC* traditional; - - LRESULT Message(HWND unused, UINT message, WPARAM value, LPARAM flags, std::uint8_t& handled); - - const char* Candidate(int index) const; -}; - -#endif diff --git a/Source/Client/Input/InputCharset.cpp b/Source/Client/Input/InputCharset.cpp index 6a9bca0a..e85e68a4 100644 --- a/Source/Client/Input/InputCharset.cpp +++ b/Source/Client/Input/InputCharset.cpp @@ -6,7 +6,7 @@ // OFFSET: 0x00ACE360 // FUNCTION: fn_17781 -const char* InputCharset::Prefix(bool alternate) const { +const char* CLanguageBase::Prefix(bool alternate) const { // STATIC: 0x016D3964 // GLOBAL: gl_24373 static char prefix[8]; @@ -21,12 +21,12 @@ const char* InputCharset::Prefix(bool alternate) const { } // INLINED -unsigned InputCharset::CodePage(unsigned fallback) const { +unsigned CLanguageBase::CodePage(unsigned fallback) const { return g_inlineCharset ? LanguageCodePage(this->language) : fallback; } // OFFSET: 0x00D9CE80 // FUNCTION: fn_22314 -void InputCharset::SetServicePrefix(std::string prefix) { +void CLanguageBase::SetServicePrefix(std::string prefix) { this->servicePrefix = prefix; } diff --git a/Source/Client/Input/InputCharset.h b/Source/Client/Input/InputCharset.h index de3f86fe..fc7b05b5 100644 --- a/Source/Client/Input/InputCharset.h +++ b/Source/Client/Input/InputCharset.h @@ -1,72 +1,10 @@ #ifndef RAGNAROK_SOURCE_CLIENT_INPUT_INPUTCHARSET_H #define RAGNAROK_SOURCE_CLIENT_INPUT_INPUTCHARSET_H -#include -#include -#include -#include +#include "Client/Input/Language.h" -struct InputCharset { - virtual void Slot00(); - virtual const char* DisplayText() const; - virtual int DisplayLength() const; - virtual void ProcessKey(unsigned virtualKey); - virtual void Slot04(); - virtual const char* NextChar(const char* current, int remaining); - virtual void Slot06(); - virtual void ResetState(); - virtual void EndComposition(); - virtual void ResetCandidate(); +using InputCharset = CLanguageBase; - /* 0004 */ unsigned char unknown_0004[0x54]; - /* 0058 */ std::string composition; - /* 0070 */ unsigned char unknown_0070[0x1E]; - /* 008E */ std::uint16_t language; - /* 0090 */ unsigned char unknown_0090[0xC]; - /* 009C */ std::string servicePrefix; - /* 00B4 */ std::uint16_t alternateLanguage; - - const char* Prefix(bool alternate) const; - - const char* ServiceName(const char* name); - - unsigned CodePage(unsigned fallback) const; - - void SetServicePrefix(std::string prefix); -}; - -#if defined(_WIN32) && !defined(_WIN64) -static_assert(offsetof(InputCharset, language) == 0x8E); -static_assert(offsetof(InputCharset, servicePrefix) == 0x9C); -static_assert(offsetof(InputCharset, alternateLanguage) == 0xB4); -#endif - -struct DefaultInputCharset : InputCharset { - DefaultInputCharset(); - ~DefaultInputCharset(); -}; - -struct TraditionalChineseInputCharset : InputCharset { - /* 00B8 */ unsigned char unknown_00B8[0x40C]; - - TraditionalChineseInputCharset(); - ~TraditionalChineseInputCharset(); -}; - -struct ThaiInputCharset : InputCharset { - /* 00B8 */ bool unknown_00B8; - - ThaiInputCharset(); - ~ThaiInputCharset(); -}; - -struct ArabicInputCharset : InputCharset { - /* 00B8 */ bool unknown_00B8; - - ArabicInputCharset(); - ~ArabicInputCharset(); -}; - -extern InputCharset* g_serverLanguage; +extern CLanguageBase* g_serverLanguage; #endif diff --git a/Source/Client/Input/Language.cpp b/Source/Client/Input/Language.cpp index 1d1a6c2e..42e0affc 100644 --- a/Source/Client/Input/Language.cpp +++ b/Source/Client/Input/Language.cpp @@ -1,3 +1,5 @@ +#include "Client/Input/InputCharset.h" +#include "Client/Application/ApplicationWindow.h" #include "Client/Input/Language.h" #include "Contents/CashEmotionMgr.h" #include "Contents/Configuration/ServiceConfiguration.h" @@ -40,7 +42,7 @@ void CLanguage::ResetInput() { // OFFSET: 0x00ACD700 // FUNCTION: fn_17767 -void CLanguage::DeleteSelection() { +void CLanguageBase::DeleteSelection() { if (this->cursor == this->anchor) { return; } @@ -51,24 +53,32 @@ void CLanguage::DeleteSelection() { this->cursor = begin; this->anchor = begin; - if (this->suggestionsEnabled && this->chatOpen && this->chatInput && this->focused == this->chatInput) { - this->suggestions.Update(this->text.c_str()); + if (g_windowMgr.unknown_0024 && g_chatSuggestions && g_chatSuggestions->window && g_windowMgr.GetHoverWindow() == g_chatSuggestions->window) { + g_cashEmotionMgr->ProcessChatCommand(this->text.c_str()); } } // OFFSET: 0x00ACD360 // FUNCTION: fn_17760 -void CLanguage::Insert(const char* value) { +void CLanguageBase::Insert(const char* value) { this->DeleteSelection(); this->text.insert(static_cast(this->cursor), value, std::strlen(value)); this->anchor = this->cursor + static_cast(std::strlen(value)); this->cursor = this->anchor; - if (this->suggestionsEnabled && this->chatOpen && this->chatInput && this->focused == this->chatInput) { - this->suggestions.Update(this->text.c_str()); + if (g_windowMgr.unknown_0024 && g_chatSuggestions && g_chatSuggestions->window && g_windowMgr.GetHoverWindow() == g_chatSuggestions->window) { + g_cashEmotionMgr->ProcessChatCommand(this->text.c_str()); } } +void CLanguage::DeleteSelection() { + g_serverLanguage->DeleteSelection(); +} + +void CLanguage::Insert(const char* value) { + g_serverLanguage->Insert(value); +} + // OFFSET: 0x00ACF590 // FUNCTION: fn_17797 void CLanguage::Select(int anchor, int cursor) { @@ -102,34 +112,6 @@ void CLanguage::Selection(int& anchor, int& cursor) const { void __stdcall SubACDD10() { } -// OFFSET: 0x00ACDD20 -// FUNCTION: fn_17775 -void CLanguage::RefreshComposition(unsigned codePage) { - HIMC context = ImmGetContext(this->window); - if (!context) { - this->candidate.clear(); - return; - } - - WCHAR wide[256]; - char converted[256]; - const auto bytes = static_cast(ImmGetCompositionStringW(context, GCS_COMPSTR, wide, sizeof(wide))); - const unsigned size = WideCharToMultiByte(codePage, 0, wide, bytes >> 1, converted, sizeof(converted), nullptr, nullptr); - ImmReleaseContext(this->window, context); - this->candidate.assign(converted, size); - - char combined[256]; - const std::size_t committed = std::min(this->text.size(), 255); - std::memcpy(combined, this->text.data(), committed); - const std::size_t pending = std::min(this->candidate.size(), 255 - committed); - std::memcpy(combined + committed, this->candidate.data(), pending); - combined[committed + pending] = 0; - - if (this->suggestionsEnabled && this->chatOpen && this->chatInput && this->focused == this->chatInput) { - this->suggestions.Update(combined); - } -} - // OFFSET: 0x00ACD5C0 // FUNCTION: fn_17765 void CLanguage::CopySelection(bool password) { @@ -483,3 +465,43 @@ UIHairStyleButton::UIHairStyleButton(int style, int sex) : UIBitmapButton(), m_s } // OFFSET: 0x00999FF0 + +// OFFSET: 0x00ACD140 +// FUNCTION: fn_17755 +CLanguageBase::~CLanguageBase() = default; + +// OFFSET: 0x00ACD200 +// FUNCTION: fn_17757 +CLanguageArabic::~CLanguageArabic() = default; + +// OFFSET: 0x00ACD300 +// FUNCTION: fn_17759 +CLanguageTH::~CLanguageTH() = default; + +// OFFSET: 0x00ACDD20 +// FUNCTION: fn_17775 +void CLanguageBase::RefreshComposition() { + HIMC context = ImmGetContext(hWnd); + if (!context) { + this->candidate.clear(); + return; + } + + WCHAR wide[256]; + char converted[256]; + const auto bytes = static_cast(ImmGetCompositionStringW(context, GCS_COMPSTR, wide, sizeof(wide))); + const unsigned size = WideCharToMultiByte(this->codePage, 0, wide, bytes >> 1, converted, sizeof(converted), nullptr, nullptr); + ImmReleaseContext(hWnd, context); + this->candidate.assign(converted, size); + + char combined[256]; + const std::size_t committed = std::min(this->text.size(), 255); + std::memcpy(combined, this->text.data(), committed); + const std::size_t pending = std::min(this->candidate.size(), 255 - committed); + std::memcpy(combined + committed, this->candidate.data(), pending); + combined[committed + pending] = 0; + + if (g_windowMgr.unknown_0024 && g_chatSuggestions && g_chatSuggestions->window && g_windowMgr.GetHoverWindow() == g_chatSuggestions->window) { + g_cashEmotionMgr->ProcessChatCommand(combined); + } +} diff --git a/Source/Client/Input/Language.h b/Source/Client/Input/Language.h index 497e2ba1..afce520a 100644 --- a/Source/Client/Input/Language.h +++ b/Source/Client/Input/Language.h @@ -62,10 +62,19 @@ struct CLanguage { // VTABLE: vt_01604 struct CLanguageBase { - virtual ~CLanguageBase() = default; + virtual ~CLanguageBase(); + virtual const char* DisplayText() const; + virtual int DisplayLength() const; + virtual void ProcessKey(unsigned virtualKey); + virtual LRESULT Message(HWND window, UINT message, WPARAM value, LPARAM flags, std::uint8_t& handled); + virtual const char* NextChar(const char* current, int remaining); + virtual void RefreshComposition(); + virtual void ResetState(); + virtual void EndComposition(); + virtual void ResetCandidate(); /* 0004 */ std::deque unknown_0004; - /* 0018 */ void* candidateList; + /* 0018 */ CANDIDATELIST* candidateList; /* 001C */ int candidateCount; /* 0020 */ int pageSize; /* 0024 */ int selection; @@ -76,7 +85,9 @@ struct CLanguageBase { /* 0054 */ int anchor; /* 0058 */ std::string composition; /* 0070 */ std::string candidate; - /* 0088 */ unsigned char unknown_0088[6]; + /* 0088 */ int compositionCursor; + /* 008C */ unsigned char password; + /* 008D */ unsigned char unknown_008D; /* 008E */ std::uint16_t language; /* 0090 */ unsigned codePage; /* 0094 */ int unknown_0094; @@ -86,6 +97,13 @@ struct CLanguageBase { /* 00B6 */ unsigned char unknown_00B6[2]; CLanguageBase(); + const char* Candidate(int index) const; + const char* Prefix(bool alternate) const; + const char* ServiceName(const char* name); + unsigned CodePage(unsigned fallback) const; + void SetServicePrefix(std::string prefix); + void DeleteSelection(); + void Insert(const char* value); }; // VTABLE: vt_01607 @@ -93,6 +111,7 @@ struct CLanguageArabic : CLanguageBase { /* 00B8 */ bool lexiconLoaded; CLanguageArabic(); + ~CLanguageArabic() override; }; // VTABLE: vt_01606 @@ -100,6 +119,8 @@ struct CLanguageTH : CLanguageBase { /* 00B8 */ bool lexiconLoaded; CLanguageTH(); + ~CLanguageTH() override; + const char* NextChar(const char* current, int remaining) override; }; #if defined(_WIN32) && !defined(_WIN64) diff --git a/Source/Client/Input/LanguageTC.cpp b/Source/Client/Input/LanguageTC.cpp index 4001012c..607820ee 100644 --- a/Source/Client/Input/LanguageTC.cpp +++ b/Source/Client/Input/LanguageTC.cpp @@ -1,11 +1,11 @@ -#include "Client/Input/InputCharset.h" #include "Client/Input/LanguageTC.h" #include "Network/TextEncoding.h" +#include #include // OFFSET: 0x00ACCD30 // FUNCTION: fn_17752 -void CLanguageTC::InitializeMappings() { +CLanguageTC::CLanguageTC() : keys() { // STATIC: 0x011594E0 // GLOBAL: gl_13427 static constexpr std::uint8_t zhuyinBig5[] = {0xA3, 0x74, 0xA3, 0x78, 0xA3, 0xBE, 0xA3, 0xBF, 0xA3, 0xA4, 0xA3, 0xBD, 0xA3, 0xBB, 0xA3, 0xAB, 0xA3, @@ -13,8 +13,8 @@ void CLanguageTC::InitializeMappings() { 0xA3, 0xA9, 0xA3, 0xAC, 0xA3, 0xB9, 0xA3, 0xAD, 0xA3, 0xB1, 0xA3, 0xAA, 0xA3, 0xBA, 0xA3, 0xB0, 0xA3, 0xB4, 0xA3, 0x75, 0xA3, 0xA1, 0xA3, 0x7A, 0xA3, 0xA5, 0xA3, 0x74, 0xA3, 0xA3, 0xA3, 0x79, 0xA3, 0x74, 0xA3, 0xA8, 0xA3, 0x77, 0xA3, 0xB7, 0xA3, 0xB5, 0xA3, 0xAE, 0xA3, 0xB2, 0xA3, 0xB6}; - static constexpr char categories[] = "11441443331111111132331233111121111133333"; - static constexpr unsigned char keys[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + const char categories[] = "11441443331111111132331233111121111133333"; + const unsigned char keys[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'N', 'M', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', VK_OEM_MINUS, VK_OEM_1, VK_OEM_COMMA, VK_OEM_PERIOD, VK_OEM_2, 0}; @@ -39,14 +39,18 @@ void CLanguageTC::InitializeMappings() { this->mappings['X'].bytes[1] = 0x7B; } +// OFFSET: 0x00ACD260 +// FUNCTION: fn_17758 +CLanguageTC::~CLanguageTC() = default; + // OFFSET: 0x00ACF330 // FUNCTION: fn_17795 -void InputCharset::ProcessKey(unsigned) { +void CLanguageBase::ProcessKey(unsigned) { } // OFFSET: 0x00ACF340 // FUNCTION: fn_17796 -void CLanguageTC::Key(int virtualKey) { +void CLanguageTC::ProcessKey(unsigned virtualKey) { const auto key = static_cast(virtualKey); if (key == 8) { if (!this->keys.empty()) { @@ -68,13 +72,13 @@ void CLanguageTC::Key(int virtualKey) { // OFFSET: 0x00ACE270 // FUNCTION: fn_17777 -const char* InputCharset::DisplayText() const { +const char* CLanguageBase::DisplayText() const { return this->composition.c_str(); } // OFFSET: 0x00ACE280 // FUNCTION: fn_17778 -const char* CLanguageTC::Display() { +const char* CLanguageTC::DisplayText() const { char bytes[8] = {}; for (std::uint8_t key : this->keys) { @@ -85,19 +89,19 @@ const char* CLanguageTC::Display() { } } - this->display.assign(bytes, sizeof(bytes)); - return this->display.c_str(); + const_cast(this->composition).assign(bytes, sizeof(bytes)); + return this->composition.c_str(); } // OFFSET: 0x00ACE320 // FUNCTION: fn_17779 -int InputCharset::DisplayLength() const { +int CLanguageBase::DisplayLength() const { return static_cast(this->composition.size()); } // OFFSET: 0x00ACE330 // FUNCTION: fn_17780 -int CLanguageTC::GetKeyStrokeSize() const { +int CLanguageTC::DisplayLength() const { if (this->keys.size() == 1 && this->mappings[this->keys.back()].category == 4) { return 0; } @@ -107,39 +111,40 @@ int CLanguageTC::GetKeyStrokeSize() const { // OFFSET: 0x00ACE470 // FUNCTION: fn_17784 -const char* InputCharset::NextChar(const char* current, int) { +const char* CLanguageBase::NextChar(const char* current, int) { return CharNextExA(static_cast(g_textCodePage), current, 0); } // OFFSET: 0x00ACE490 // FUNCTION: fn_17785 -const char* CLanguageTC::NextCharArabic(const char* current, int) { +const char* CLanguageTH::NextChar(const char* current, int) { return CharNextExA(static_cast(g_textCodePage), current, 0); } // OFFSET: 0x00ACD7D0 // FUNCTION: fn_17768 -void InputCharset::EndComposition() {} +void CLanguageBase::EndComposition() { +} // OFFSET: 0x00ACD7E0 // FUNCTION: fn_17769 -void CLanguageTC::ClearKeys() { +void CLanguageTC::EndComposition() { this->keys.clear(); } // OFFSET: 0x00ACD4A0 // FUNCTION: fn_17761 -void InputCharset::ResetState() { +void CLanguageBase::ResetState() { } // OFFSET: 0x00ACD4E0 // FUNCTION: fn_17762 -void InputCharset::ResetCandidate() { +void CLanguageBase::ResetCandidate() { } // OFFSET: 0x00ACD4F0 // FUNCTION: fn_17763 -void CLanguageTC::RetainSingleKey() { +void CLanguageTC::ResetCandidate() { if (!this->keys.empty()) { const auto key = this->keys.back(); this->keys.clear(); @@ -151,8 +156,9 @@ void CLanguageTC::RetainSingleKey() { // OFFSET: 0x00ACE000 // FUNCTION: fn_17776 -void CLanguageTC::FilterCandidate(std::string& candidate) { - if (candidate.size() > 2 && std::strcmp(candidate.c_str() + candidate.size() - 2, "?") == 0) { - candidate.resize(candidate.size() - 2); +void CLanguageTC::RefreshComposition() { + CLanguageBase::RefreshComposition(); + if (this->candidate.size() > 2 && std::strcmp(this->candidate.c_str() + this->candidate.size() - 2, "?") == 0) { + this->candidate.resize(this->candidate.size() - 2); } } diff --git a/Source/Client/Input/LanguageTC.h b/Source/Client/Input/LanguageTC.h index f285f46c..f3d58bd4 100644 --- a/Source/Client/Input/LanguageTC.h +++ b/Source/Client/Input/LanguageTC.h @@ -1,6 +1,8 @@ #ifndef RAGNAROK_SOURCE_CLIENT_INPUT_LANGUAGETC_H #define RAGNAROK_SOURCE_CLIENT_INPUT_LANGUAGETC_H +#include "Client/Input/Language.h" + #include #include #include @@ -11,27 +13,32 @@ struct TraditionalKeyMapping { /* 0001 */ std::uint8_t bytes[3]; }; -struct CLanguageTC { - std::list& keys; - std::array& mappings; - std::string& display; - std::uint8_t& unknown04C1; +// VTABLE: vt_01605 +struct CLanguageTC : CLanguageBase { + /* 00B8 */ std::list keys; + /* 00C0 */ std::array mappings; + /* 04C0 */ unsigned char unknown_04C0; + /* 04C1 */ std::uint8_t unknown04C1; + /* 04C2 */ unsigned char unknown_04C2[2]; + + CLanguageTC(); + ~CLanguageTC() override; + const char* DisplayText() const override; + int DisplayLength() const override; + void ProcessKey(unsigned virtualKey) override; + void RefreshComposition() override; + void EndComposition() override; + void ResetCandidate() override; - void InitializeMappings(); - void Key(int virtualKey); - const char* Display(); - const char* DisplayText() const; - int DisplayLength() const; - const char* NextChar(const char* current, int unused); - const char* NextCharArabic(const char* current, int unused); int GetKeyStrokeSize() const; - void ClearKeys(); - void ResetState(); - void ResetCandidate(); - void RetainSingleKey(); - void FilterCandidate(std::string& candidate); }; static_assert(sizeof(TraditionalKeyMapping) == 4); +#if defined(_WIN32) && !defined(_WIN64) +static_assert(offsetof(CLanguageTC, keys) == 0xB8); +static_assert(offsetof(CLanguageTC, mappings) == 0xC0); +static_assert(offsetof(CLanguageTC, unknown04C1) == 0x4C1); +static_assert(sizeof(CLanguageTC) == 0x4C4); +#endif #endif diff --git a/Source/Client/Mode/GameModePackets.cpp b/Source/Client/Mode/GameModePackets.cpp index 9bd1c72a..3f40586d 100644 --- a/Source/Client/Mode/GameModePackets.cpp +++ b/Source/Client/Mode/GameModePackets.cpp @@ -15529,7 +15529,7 @@ void CGameMode::ReceiveTaggedBroadcast(const unsigned char* data) { message = std::move(linked); std::vector lines; - WrapPlainText(message.c_str(), lines, 0x48, g_serverLanguage->language); + WrapPlainText(message.c_str(), lines, 0x48); if (lines.begin() != lines.end()) { if (UIBroadcastBalloon* balloon = this->EnsureBroadcastBalloon()) { BroadcastBalloonMessage balloonMessage{{}, {}, std::chrono::seconds(20), 12, 0x40000000, 0, 0}; diff --git a/Source/Contents/Configuration/ServiceConfiguration.cpp b/Source/Contents/Configuration/ServiceConfiguration.cpp index d5375bce..a0c0c55f 100644 --- a/Source/Contents/Configuration/ServiceConfiguration.cpp +++ b/Source/Contents/Configuration/ServiceConfiguration.cpp @@ -1,4 +1,5 @@ #include "Client/Input/InputCharset.h" +#include "Client/Input/LanguageTC.h" #include "Contents/Configuration/ServiceConfiguration.h" #include "Archive/PakRegistry.h" #include "Client/Application/ErrorDialog.h" @@ -29,7 +30,7 @@ signed char g_language = 0; // GLOBAL: gl_24544 -InputCharset* g_serverLanguage; +CLanguageBase* g_serverLanguage; // GLOBAL: gl_24972 unsigned char g_startupSecondPhase; @@ -329,13 +330,13 @@ void sub_AD1270() { // FUNCTION: fn_17811 void InitializeLanguage() { // GLOBAL: gl_25359 - static DefaultInputCharset defaultCharset; + static CLanguageBase defaultCharset; // GLOBAL: gl_25360 - static TraditionalChineseInputCharset traditionalChineseCharset; + static CLanguageTC traditionalChineseCharset; // GLOBAL: gl_25361 - static ThaiInputCharset thaiCharset; + static CLanguageTH thaiCharset; // GLOBAL: gl_25362 - static ArabicInputCharset arabicCharset; + static CLanguageArabic arabicCharset; switch (g_serviceType) { case 0: diff --git a/Source/Resource/TextureNames.cpp b/Source/Resource/TextureNames.cpp index 4241eee9..457b458c 100644 --- a/Source/Resource/TextureNames.cpp +++ b/Source/Resource/TextureNames.cpp @@ -11,7 +11,7 @@ // OFFSET: 0x00ACE510 // FUNCTION: fn_17788 -const char* InputCharset::ServiceName(const char* name) { +const char* CLanguageBase::ServiceName(const char* name) { if (g_serviceType == 0 || g_serviceType == 2 || g_serviceType == 20) { return name; } diff --git a/Source/UI/Acceptance/UIChooseSellBuyWnd.cpp b/Source/UI/Acceptance/UIChooseSellBuyWnd.cpp index 90a72539..ceffb380 100644 --- a/Source/UI/Acceptance/UIChooseSellBuyWnd.cpp +++ b/Source/UI/Acceptance/UIChooseSellBuyWnd.cpp @@ -9089,7 +9089,7 @@ void UITipboxWnd::Slot19() { const int index = (std::max)(0, g_itemTagOwner->unknown_00B4); const std::string text = g_itemTagOwner->m_currentEntry.paragraphs[index]; std::vector lines; - WrapPlainText(text.c_str(), lines, 1000, static_cast(g_textCodePage)); + WrapPlainText(text.c_str(), lines, 1000); this->unknown_00BC->Clear(); for (const std::string& line : lines) { this->unknown_00BC->SendMsg(nullptr, 29, reinterpret_cast(line.c_str()), 32, 0, 0); @@ -9967,7 +9967,7 @@ void UITipboxWnd::RefreshTip() { this->unknown_00D8->Enable(g_itemTagOwner->m_currentEntry.searchable); std::vector lines; - WrapPlainText(title.c_str(), lines, 30, static_cast(g_textCodePage)); + WrapPlainText(title.c_str(), lines, 30); UIStaticText* const texts[2] = {this->unknown_00C0, this->unknown_00C4}; for (int index = 0; index < 2; ++index) { diff --git a/Source/UI/Buttons/UITextButton.cpp b/Source/UI/Buttons/UITextButton.cpp index 49c89d7c..5dc08a04 100644 --- a/Source/UI/Buttons/UITextButton.cpp +++ b/Source/UI/Buttons/UITextButton.cpp @@ -3609,7 +3609,7 @@ void UISlotBmpButton::Paint() { this->DrawBitmap(this->geometry.width / 2 - 0x2e, 0x1a, balloon ? &balloon->image : nullptr, false); std::vector lines; - WrapPlainText(LookupMessage(0xaed), lines, 0x14, static_cast(g_textCodePage)); + WrapPlainText(LookupMessage(0xaed), lines, 0x14); int y = 0x22; for (const std::string& line : lines) { this->DrawCenteredText(0x21, y, line.c_str(), 0x5c, 0, 0xb, 0xffffff, 0); diff --git a/Source/UI/Chat/ChatNotifications.h b/Source/UI/Chat/ChatNotifications.h index ddfe166c..f19be225 100644 --- a/Source/UI/Chat/ChatNotifications.h +++ b/Source/UI/Chat/ChatNotifications.h @@ -52,7 +52,7 @@ inline void ChatNotifications::Text(const char* text, std::uint32_t color, const } std::vector lines; - WrapPlainText(text, lines, 94, this->codePage); + WrapPlainText(text, lines, 94); for (const auto& line : lines) { this->queued.push_back({line, color}); diff --git a/Source/UI/Edit/UIEditCtrl.h b/Source/UI/Edit/UIEditCtrl.h index 36ed364a..39b5d67f 100644 --- a/Source/UI/Edit/UIEditCtrl.h +++ b/Source/UI/Edit/UIEditCtrl.h @@ -9,7 +9,8 @@ struct InputFocus; struct CLanguage; -struct InputCharset; +struct CLanguageBase; +using InputCharset = CLanguageBase; struct BitmapImage; #include "UI/Window/WindowManagerWindows.h" class NavigationDestination; diff --git a/Source/UI/Lists/UIComboBoxDefWnd.cpp b/Source/UI/Lists/UIComboBoxDefWnd.cpp index f44cb59c..08b5847f 100644 --- a/Source/UI/Lists/UIComboBoxDefWnd.cpp +++ b/Source/UI/Lists/UIComboBoxDefWnd.cpp @@ -513,7 +513,7 @@ void UIDescriptRace::sub_8A0B10() { this->DrawTextAt(50, 23, LookupMessage(3018), 0, 0, 12, 0x99634C, 1, 0); this->DrawTextAt(49, 22, LookupMessage(3018), 0, 0, 12, 0xFFFFFF, 1, 0); std::vector lines; - WrapPlainText(LookupMessage(3021), lines, 40, g_serverLanguage->language); + WrapPlainText(LookupMessage(3021), lines, 40); int y = 22; for (unsigned index = 0; index < lines.size(); ++index) { this->DrawTextAt(112, y, lines[index].c_str(), 0, 0, 12, 0, 0, 0); @@ -523,7 +523,7 @@ void UIDescriptRace::sub_8A0B10() { this->DrawTextAt(50, 23, LookupMessage(3016), 0, 0, 12, 0x99634C, 1, 0); this->DrawTextAt(49, 22, LookupMessage(3016), 0, 0, 12, 0xFFFFFF, 1, 0); std::vector lines; - WrapPlainText(LookupMessage(3020), lines, 40, g_serverLanguage->language); + WrapPlainText(LookupMessage(3020), lines, 40); int y = 22; for (unsigned index = 0; index < lines.size(); ++index) { this->DrawTextAt(112, y, lines[index].c_str(), 0, 0, 12, 0, 0, 0); diff --git a/Source/UI/Lists/UITagListBox.cpp b/Source/UI/Lists/UITagListBox.cpp index 57f0d797..ea060011 100644 --- a/Source/UI/Lists/UITagListBox.cpp +++ b/Source/UI/Lists/UITagListBox.cpp @@ -401,7 +401,7 @@ void UITagListBox::sub_9B9EA0(std::intptr_t argument1, std::intptr_t argument2, std::vector lines; if (width == 138) { - WrapPlainText(text, lines, 38, owner.codePage); + WrapPlainText(text, lines, 38); for (std::size_t index = 0; index < lines.size(); ++index) { this->AddLine(lines[index].c_str()); diff --git a/Source/UI/Party/UIApplyForPartyWnd.cpp b/Source/UI/Party/UIApplyForPartyWnd.cpp index 16a6c1a9..cd0d7f77 100644 --- a/Source/UI/Party/UIApplyForPartyWnd.cpp +++ b/Source/UI/Party/UIApplyForPartyWnd.cpp @@ -61,7 +61,7 @@ void UIApplyForPartyWnd::Slot15(int, int) { } std::vector lines; - WrapPlainText(LookupMessage(3370), lines, 40, this->m_application->codePage); + WrapPlainText(LookupMessage(3370), lines, 40); int y = 136; for (const auto& line : lines) { diff --git a/Source/UI/Party/UIRegisterPartyWnd.cpp b/Source/UI/Party/UIRegisterPartyWnd.cpp index 6812caac..5a8368ad 100644 --- a/Source/UI/Party/UIRegisterPartyWnd.cpp +++ b/Source/UI/Party/UIRegisterPartyWnd.cpp @@ -149,7 +149,7 @@ void UIRegisterPartyWnd::Slot15(int, int) { this->m_message0 = registered ? 564 : 565; this->AddChild(submit); std::vector lines; - WrapPlainText(LookupMessage(3370), lines, 40, owner.codePage); + WrapPlainText(LookupMessage(3370), lines, 40); int y = 136; for (const auto& line : lines) { diff --git a/Source/UI/Party/UIRequestJoinPartyWnd.cpp b/Source/UI/Party/UIRequestJoinPartyWnd.cpp index 3add855c..d1d80c0c 100644 --- a/Source/UI/Party/UIRequestJoinPartyWnd.cpp +++ b/Source/UI/Party/UIRequestJoinPartyWnd.cpp @@ -83,7 +83,7 @@ void UIRequestJoinPartyWnd::Slot15(int, int) { this->block->SetId(213); this->AddChild(this->block); std::vector unused; - WrapPlainText(LookupMessage(3518), unused, 30, text.list.codePage); + WrapPlainText(LookupMessage(3518), unused, 30); this->blockText = new UITextViewer(*this->m_context, text); this->blockText->Configure(31, 81, 182, 47, 0); diff --git a/Source/UI/Text/TextWrapping.cpp b/Source/UI/Text/TextWrapping.cpp index 9c2501ca..1462491d 100644 --- a/Source/UI/Text/TextWrapping.cpp +++ b/Source/UI/Text/TextWrapping.cpp @@ -1,3 +1,4 @@ +#include "Client/Input/InputCharset.h" #include "Contents/Items/ItemDescription.h" #include "Contents/Items/ItemInfo.h" #include "Render/Text/TextContext.h" @@ -14,7 +15,7 @@ // OFFSET: 0x009B4220 // FUNCTION: fn_13829 -void WrapPlainText(const char* text, std::vector& lines, int width, unsigned short codePage) { +void WrapPlainText(const char* text, std::vector& lines, int width) { const char* begin = text; const char* chunk = text; const char* current = text; @@ -25,7 +26,7 @@ void WrapPlainText(const char* text, std::vector& lines, int width, const char* marker = text + TextContext::Marker(text, bytes); while (current < end) { - current = CharNextExA(codePage, current, 0); + current = g_serverLanguage->NextChar(current, static_cast(end - current)); while (*current == ' ') { ++current; @@ -80,7 +81,7 @@ namespace { // OFFSET: 0x009B4730 // FUNCTION: fn_13833 void WrapRichText( - const char* text, std::vector& lines, int width, bool carriageReturns, unsigned short codePage, ItemDescriptions& items + const char* text, std::vector& lines, int width, bool carriageReturns, ItemDescriptions& items ) { const char* begin = text; const char* current = text; @@ -144,7 +145,7 @@ void WrapRichText( lines.emplace_back(name); } } else { - current = CharNextExA(codePage, current, 0); + current = g_serverLanguage->NextChar(current, static_cast(end - current)); } } diff --git a/Source/UI/Text/TextWrapping.h b/Source/UI/Text/TextWrapping.h index 9da00242..8a6a5842 100644 --- a/Source/UI/Text/TextWrapping.h +++ b/Source/UI/Text/TextWrapping.h @@ -6,10 +6,10 @@ struct ItemDescriptions; -void WrapPlainText(const char* text, std::vector& lines, int width, unsigned short codePage); +void WrapPlainText(const char* text, std::vector& lines, int width); void WrapRichText( - const char* text, std::vector& lines, int width, bool carriageReturns, unsigned short codePage, ItemDescriptions& items + const char* text, std::vector& lines, int width, bool carriageReturns, ItemDescriptions& items ); #endif diff --git a/Source/UI/Text/UIBalloonText.cpp b/Source/UI/Text/UIBalloonText.cpp index 18c4a664..8fcee56f 100644 --- a/Source/UI/Text/UIBalloonText.cpp +++ b/Source/UI/Text/UIBalloonText.cpp @@ -97,9 +97,9 @@ void UIBalloonText::SetText(const char* text, int width) { this->m_lines.clear(); if (this->m_richText != 0) { - WrapRichText(text, this->m_lines, width, false, this->m_textContext->codePage, this->m_textContext->items); + WrapRichText(text, this->m_lines, width, false, this->m_textContext->items); } else { - WrapPlainText(text, this->m_lines, width, this->m_textContext->codePage); + WrapPlainText(text, this->m_lines, width); } if (this->m_lines.size() != 0) { @@ -115,7 +115,7 @@ void UIBalloonText::WrapText(const char* text, int width) { } this->m_lines.clear(); - WrapPlainText(text, this->m_lines, width, this->m_textContext->codePage); + WrapPlainText(text, this->m_lines, width); } // OFFSET: 0x00853530 diff --git a/Source/UI/Text/UITextViewerMessages.cpp b/Source/UI/Text/UITextViewerMessages.cpp index 5aed1b6e..b233e746 100644 --- a/Source/UI/Text/UITextViewerMessages.cpp +++ b/Source/UI/Text/UITextViewerMessages.cpp @@ -115,7 +115,7 @@ void UITextViewer::AppendText(char* text, int width, bool carriageReturns, bool std::vector wrapped; if (width == 138) { - WrapPlainText(text, wrapped, 38, owner.codePage); + WrapPlainText(text, wrapped, 38); for (const auto& line : wrapped) { this->AddLine(line.c_str()); @@ -154,7 +154,7 @@ void UITextViewer::AppendText(char* text, int width, bool carriageReturns, bool WrapPixelText(*this->geometry.surface, owner.codePage, display.c_str(), wrapped, this->geometry.width - scrollWidth - 4); } else { WrapRichText( - display.c_str(), wrapped, width == 0 ? 35 : width, carriageReturns, owner.codePage, this->m_text->items.descriptions + display.c_str(), wrapped, width == 0 ? 35 : width, carriageReturns, this->m_text->items.descriptions ); } diff --git a/Source/UI/UIRoundBoxTooltipWnd.cpp b/Source/UI/UIRoundBoxTooltipWnd.cpp index fd08c9b9..8687f497 100644 --- a/Source/UI/UIRoundBoxTooltipWnd.cpp +++ b/Source/UI/UIRoundBoxTooltipWnd.cpp @@ -91,7 +91,7 @@ int UIColoringTextViewer::SendMsg(UIWindow* sender, int message, std::intptr_t a std::vector wrapped; ItemDescriptions descriptions{g_itemDescriptions}; - WrapRichText(reinterpret_cast(argument1), wrapped, 35, argument3 != 0, this->m_listContext->codePage, descriptions); + WrapRichText(reinterpret_cast(argument1), wrapped, 35, argument3 != 0, descriptions); for (unsigned index = 0; index < wrapped.size(); ++index) { this->AddLine(wrapped[index].c_str()); } diff --git a/Source/UI/Window/UIFrameWnd.cpp b/Source/UI/Window/UIFrameWnd.cpp index ec468b7c..17184e36 100644 --- a/Source/UI/Window/UIFrameWnd.cpp +++ b/Source/UI/Window/UIFrameWnd.cpp @@ -823,7 +823,7 @@ int UIChatRoomWnd::SendMsg(UIWindow* sender, int message, std::intptr_t a, std:: _mbsstr(reinterpret_cast(text), reinterpret_cast(""))) { lines.push_back(std::string(text)); } else { - WrapPlainText(text, lines, wrapWidth, g_serverLanguage->language); + WrapPlainText(text, lines, wrapWidth); } for (unsigned index = 0; index < lines.size(); ++index) { diff --git a/Source/UI/Window/UIWindow.cpp b/Source/UI/Window/UIWindow.cpp index bed722fd..14d72354 100644 --- a/Source/UI/Window/UIWindow.cpp +++ b/Source/UI/Window/UIWindow.cpp @@ -2620,7 +2620,7 @@ void UINavigationV4Wnd::Paint() { std::string message = LookupMessage(0xc8f); std::vector lines; - WrapPlainText(message.c_str(), lines, 0x26, g_serverLanguage->language); + WrapPlainText(message.c_str(), lines, 0x26); int y = (0x29 - static_cast(lines.size())) * 7; for (unsigned int index = 0; index < lines.size(); ++index) { DrawOutlinedText(*this, 0x2a, y, lines[index].c_str(), 0, 0xffffff, 0, 0, 0xb, 1, 0); diff --git a/Source/UI/Window/UIWindowMgr.cpp b/Source/UI/Window/UIWindowMgr.cpp index fbfbb80c..d44389e1 100644 --- a/Source/UI/Window/UIWindowMgr.cpp +++ b/Source/UI/Window/UIWindowMgr.cpp @@ -1666,7 +1666,7 @@ int UIWindowMgr::SendNotice(int selector, std::intptr_t a, std::intptr_t b, std: color = 0xFFFFFF; } std::vector lines; - WrapPlainText(text, lines, 94, 0); + WrapPlainText(text, lines, 94); for (unsigned int index = 0; index < lines.size(); ++index) { std::string line; line = lines[index];