port 4-a: text input through CPythonIME (login typed, in-game chat)
- UserInterface/PythonIME(+Module) ported verbatim; ime module stubs removed, initime() after initdbg() - EterLib/IME.cpp in platform/: 40250 buffer/WMChar bodies, IMM/TSF processors no-op; committed multi-byte text via PythonBoot::UIChar emulating GCS_RESULTSTR - GameApplicationAdapter RunIME* -> CWindowManager; Godot keys -> ui_ime_key/ui_char - port.login_flow/login_live type the account through the IME; chat CG_CHAT round-trip on the fake server - python_game_render_test logs in with Godot key events Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
1bda4390d6
commit
6ea0fa9889
@@ -1,381 +1,666 @@
|
||||
// Platform skeleton for EterLib/IME.h (40250 EterLib/IME.cpp), generated by platform_stub.py.
|
||||
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
|
||||
// Platform implementation of EterLib/IME.h (40250 EterLib/IME.cpp).
|
||||
// The edit buffer (m_wText, cursor, SetText/GetText, OnChar/InsertString, IsMax, the colour-tag aware cursor
|
||||
// moves) and WMChar are the 40250 bodies verbatim. What 40250 gets from Win32 IMM/TSF — composition strings,
|
||||
// the candidate list, the reading window, keyboard-layout code pages — has no counterpart under Godot: the
|
||||
// host delivers committed characters only (Metin2PythonHost.ui_char -> WMChar, or InsertString for text the
|
||||
// input code page cannot hold, which is what 40250's ResultProcess does with a GCS_RESULTSTR). Those entry
|
||||
// points keep 40250's "no IME present" behaviour: no composition, empty candidate/reading lists.
|
||||
#include "EterLib/StdAfx.h"
|
||||
#include "EterLib/IME.h"
|
||||
#include "EterLib/TextTag.h"
|
||||
#include "EterLib/GrpTextInstance.h"
|
||||
#include "EterLib/Util.h"
|
||||
|
||||
#include "../PlatformStub.h"
|
||||
#include <algorithm>
|
||||
#include <cwctype>
|
||||
|
||||
namespace
|
||||
{
|
||||
// 40250 s_aszIndicator[INDICATOR_NON_IME] (IME.cpp:67); CheckInputLocale overwrites it with the locale's
|
||||
// two-letter abbreviation, which here is the locale code page's language.
|
||||
wchar_t s_aszNonImeIndicator[3] = L"En";
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/ /* Public */
|
||||
CIME::CIME()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
ms_hWnd = NULL;
|
||||
|
||||
ms_bCandidateList = false;
|
||||
ms_bReadingInformation = false;
|
||||
|
||||
Clear();
|
||||
|
||||
m_max = 0;
|
||||
m_userMax = 0;
|
||||
|
||||
m_bOnlyNumberMode = FALSE;
|
||||
m_hOrgIMC = NULL;
|
||||
|
||||
m_bEnablePaste = false;
|
||||
m_bUseDefaultIME = false;
|
||||
}
|
||||
|
||||
CIME::~CIME()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
}
|
||||
|
||||
auto CIME::Initialize(HWND) -> bool
|
||||
// PORT: 40250 loads imm32.dll, disables Cicero, reads the keyboard layout and sets up the TSF sinks. The
|
||||
// Godot host has no IMM context; only the part the edit buffer depends on — the input/output code page from
|
||||
// CheckInputLocale and SetSupportLevel(2) — is kept.
|
||||
bool CIME::Initialize(HWND hWnd)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<bool>();
|
||||
}
|
||||
if(ms_bInitialized)
|
||||
return true;
|
||||
ms_hWnd = hWnd;
|
||||
|
||||
auto CIME::Uninitialize() -> void
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
}
|
||||
ms_bDisableIMECompletely = true;
|
||||
ms_bInitialized = true;
|
||||
|
||||
auto CIME::Clear() -> void
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
}
|
||||
CheckInputLocale();
|
||||
ChangeInputLanguageWorker();
|
||||
SetSupportLevel(2);
|
||||
|
||||
auto CIME::SetMax(int) -> void
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
}
|
||||
ms_bUILessMode = false;
|
||||
CheckToggleState();
|
||||
|
||||
auto CIME::SetUserMax(int) -> void
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return true;
|
||||
}
|
||||
|
||||
auto CIME::SetText(const char *, int) -> void
|
||||
void CIME::Uninitialize()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
if ( !ms_bInitialized )
|
||||
return;
|
||||
ms_hWnd = NULL;
|
||||
m_hOrgIMC = NULL;
|
||||
ms_bInitialized = false;
|
||||
}
|
||||
|
||||
auto CIME::GetText(std::string &, bool) -> int
|
||||
void CIME::UseDefaultIME()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<int>();
|
||||
m_bUseDefaultIME = true;
|
||||
}
|
||||
|
||||
auto CIME::GetCodePageText() -> const char *
|
||||
bool CIME::IsIMEEnabled()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<const char *>();
|
||||
return ms_bImeEnabled;
|
||||
}
|
||||
|
||||
auto CIME::GetCodePage() -> int
|
||||
// PORT: 40250 ImmAssociateContext()s the window; ms_bDisableIMECompletely (no imm32) forces bEnable=false,
|
||||
// which is always the case here.
|
||||
void CIME::EnableIME(bool bEnable)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<int>();
|
||||
if (!ms_bInitialized || !ms_hWnd)
|
||||
return;
|
||||
if (ms_bDisableIMECompletely)
|
||||
bEnable = false;
|
||||
ms_bImeEnabled = bEnable;
|
||||
if (bEnable)
|
||||
CheckToggleState();
|
||||
}
|
||||
|
||||
auto CIME::GetCandidateCount() -> int
|
||||
void CIME::DisableIME()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<int>();
|
||||
EnableIME(false);
|
||||
}
|
||||
|
||||
auto CIME::GetCandidatePageCount() -> int
|
||||
void CIME::EnableCaptureInput()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<int>();
|
||||
ms_bCaptureInput = true;
|
||||
}
|
||||
|
||||
auto CIME::GetCandidate(DWORD, std::string &) -> int
|
||||
void CIME::DisableCaptureInput()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<int>();
|
||||
ms_bCaptureInput = false;
|
||||
}
|
||||
|
||||
auto CIME::GetCandidateSelection() -> int
|
||||
bool CIME::IsCaptureEnabled()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<int>();
|
||||
return ms_bCaptureInput;
|
||||
}
|
||||
|
||||
auto CIME::GetReading(std::string &) -> int
|
||||
void CIME::Clear()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<int>();
|
||||
}
|
||||
ms_lastpos = 0;
|
||||
ms_curpos = 0;
|
||||
|
||||
auto CIME::GetReadingError() -> int
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<int>();
|
||||
ms_compLen = 0;
|
||||
ms_ulbegin = 0;
|
||||
ms_ulend = 0;
|
||||
}
|
||||
|
||||
auto CIME::SetInputMode(DWORD) -> void
|
||||
int CIME::GetReading(std::string & rstrText)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
}
|
||||
char reading[IMEREADING_MAXLEN];
|
||||
|
||||
auto CIME::GetInputMode() -> DWORD
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<DWORD>();
|
||||
if(ms_wstrReading.size() == 0)
|
||||
return 0;
|
||||
int readingLen = WideCharToMultiByte(ms_uOutputCodePage, 0, &ms_wstrReading[0], ms_wstrReading.size(), reading, sizeof(reading), NULL, NULL);
|
||||
|
||||
rstrText.append(GetCodePageText());
|
||||
rstrText.append(reading, reading + readingLen);
|
||||
|
||||
return rstrText.size();
|
||||
}
|
||||
|
||||
auto CIME::IsIMEEnabled() -> bool
|
||||
int CIME::GetReadingError()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<bool>();
|
||||
return ms_iReadingError;
|
||||
}
|
||||
|
||||
auto CIME::EnableIME(bool) -> void
|
||||
void CIME::SetMax(int iMax)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
m_max = iMax;
|
||||
}
|
||||
|
||||
auto CIME::DisableIME() -> void
|
||||
void CIME::SetUserMax(int iMax)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
m_userMax = iMax;
|
||||
}
|
||||
|
||||
auto CIME::EnableCaptureInput() -> void
|
||||
void CIME::SetText(const char* szText, int len)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
ms_compLen = 0;
|
||||
ms_ulbegin = 0;
|
||||
ms_ulend = 0;
|
||||
|
||||
const char* begin = szText;
|
||||
const char* end = begin + len;
|
||||
const char* iter = FindToken(begin, end);
|
||||
|
||||
int m_wTextLen = sizeof(m_wText)/sizeof(wchar_t);
|
||||
|
||||
ms_lastpos = MultiByteToWideChar(ms_uInputCodePage, 0, begin, iter-begin, m_wText, m_wTextLen);
|
||||
|
||||
if (iter < end)
|
||||
ms_lastpos += MultiByteToWideChar(ReadToken(iter), 0, (iter+5), end-(iter+5), m_wText+ms_lastpos, m_wTextLen-ms_lastpos);
|
||||
|
||||
ms_curpos = std::min(ms_curpos, ms_lastpos);
|
||||
}
|
||||
|
||||
auto CIME::DisableCaptureInput() -> void
|
||||
int CIME::GetText(std::string & rstrText, bool addCodePage)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
int outCodePage = ms_uOutputCodePage;
|
||||
int dataCodePage;
|
||||
switch (outCodePage)
|
||||
{
|
||||
//case 1256: // ARABIC
|
||||
case 1268: // VIETNAM
|
||||
dataCodePage = CP_UTF8;
|
||||
break;
|
||||
default:
|
||||
dataCodePage = outCodePage;
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
char text[IMESTR_MAXLEN];
|
||||
|
||||
len += WideCharToMultiByte(dataCodePage, 0, m_wText, ms_curpos, text, sizeof(text)-len, NULL, NULL);
|
||||
len += WideCharToMultiByte(dataCodePage, 0, m_wszComposition, ms_compLen, text+len, sizeof(text)-len, NULL, NULL);
|
||||
len += WideCharToMultiByte(dataCodePage, 0, m_wText+ms_curpos, ms_lastpos-ms_curpos, text+len, sizeof(text)-len, NULL, NULL);
|
||||
|
||||
int i;
|
||||
for(i=0; i<len; ++i)
|
||||
if((BYTE)text[i] > 0x7F) break;
|
||||
|
||||
if(i == len)
|
||||
{
|
||||
rstrText.append(text, text+len);
|
||||
}
|
||||
else
|
||||
{
|
||||
rstrText.append(text, text+i);
|
||||
|
||||
//if (addCodePage)
|
||||
// rstrText.append(GetCodePageText());
|
||||
|
||||
rstrText.append(text+i, text+len);
|
||||
}
|
||||
|
||||
return rstrText.size();
|
||||
}
|
||||
|
||||
auto CIME::IsCaptureEnabled() -> bool
|
||||
const char* CIME::GetCodePageText()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<bool>();
|
||||
static char szCodePage[16];
|
||||
|
||||
const int defCodePage = GetDefaultCodePage();
|
||||
const int outCodePage = ms_uOutputCodePage;
|
||||
|
||||
if (outCodePage != defCodePage)
|
||||
{
|
||||
sprintf(szCodePage, "@%04d", outCodePage);
|
||||
}
|
||||
else
|
||||
{
|
||||
szCodePage[0] = 0;
|
||||
}
|
||||
|
||||
return szCodePage;
|
||||
}
|
||||
|
||||
auto CIME::SetNumberMode() -> void
|
||||
int CIME::GetCodePage()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return ms_uOutputCodePage;
|
||||
}
|
||||
|
||||
auto CIME::SetStringMode() -> void
|
||||
int CIME::GetCandidatePageCount()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return ms_dwCandidatePageSize;
|
||||
}
|
||||
|
||||
auto CIME::__IsWritable(wchar_t) -> bool
|
||||
int CIME::GetCandidateCount()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<bool>();
|
||||
return ms_dwCandidateCount;
|
||||
}
|
||||
|
||||
auto CIME::AddExceptKey(wchar_t) -> void
|
||||
int CIME::GetCandidate(DWORD index, std::string & rstrText)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
if(index >= MAX_CANDLIST)
|
||||
return 0;
|
||||
|
||||
LPCWSTR wszText = ms_wszCandidate[index];
|
||||
if(wszText == NULL)
|
||||
return 0;
|
||||
|
||||
int wTextLen = wcslen(wszText);
|
||||
if(wTextLen == 0)
|
||||
return 0;
|
||||
|
||||
char text[IMESTR_MAXLEN];
|
||||
int len = ::WideCharToMultiByte(CP_UTF8, 0, wszText, wTextLen, text, sizeof(text), 0, 0);
|
||||
|
||||
rstrText.append("@9999");
|
||||
rstrText.append(text, text+len);
|
||||
|
||||
return wTextLen;
|
||||
}
|
||||
|
||||
auto CIME::ClearExceptKey() -> void
|
||||
int CIME::GetCandidateSelection()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return ms_dwCandidateSelection;
|
||||
}
|
||||
|
||||
auto CIME::PasteTextFromClipBoard() -> void
|
||||
// PORT: 40250 ImmSetConversionStatus / ImmGetConversionStatus. Without an IMM context the conversion mode is
|
||||
// the alphanumeric one (IME_CMODE_ALPHANUMERIC == 0) and cannot be changed.
|
||||
void CIME::SetInputMode(DWORD)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
}
|
||||
|
||||
auto CIME::EnablePaste(bool) -> void
|
||||
DWORD CIME::GetInputMode()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto CIME::PasteString(const char *) -> void
|
||||
void CIME::SetNumberMode()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
m_bOnlyNumberMode = TRUE;
|
||||
}
|
||||
|
||||
auto CIME::FinalizeString(bool) -> void
|
||||
void CIME::SetStringMode()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
m_bOnlyNumberMode = FALSE;
|
||||
}
|
||||
|
||||
auto CIME::UseDefaultIME() -> void
|
||||
void CIME::AddExceptKey(wchar_t key)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
m_exceptKey.push_back(key);
|
||||
}
|
||||
|
||||
auto CIME::GetCurPos() -> int
|
||||
void CIME::ClearExceptKey()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<int>();
|
||||
m_exceptKey.clear();
|
||||
}
|
||||
|
||||
auto CIME::GetCompLen() -> int
|
||||
bool CIME::__IsWritable(wchar_t key)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<int>();
|
||||
if ( m_exceptKey.end() == std::find(m_exceptKey.begin(),m_exceptKey.end(),key) )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
auto CIME::GetULBegin() -> int
|
||||
void CIME::EnablePaste(bool bFlag)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<int>();
|
||||
m_bEnablePaste = bFlag;
|
||||
}
|
||||
|
||||
auto CIME::GetULEnd() -> int
|
||||
// PORT: 40250 reads CF_TEXT from the Win32 clipboard. The host clipboard is not wired to the extension yet,
|
||||
// so this pastes nothing (the same as an empty clipboard).
|
||||
void CIME::PasteTextFromClipBoard()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<int>();
|
||||
if (!m_bEnablePaste)
|
||||
return;
|
||||
}
|
||||
|
||||
auto CIME::CloseCandidateList() -> void
|
||||
// PORT: 40250 cancels the IMM composition string and closes the candidate list. There is no composition
|
||||
// here; the candidate-list close (and its event) is kept.
|
||||
void CIME::FinalizeString(bool)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
static bool s_bProcessing = false; // to avoid infinite recursion
|
||||
if ( !ms_bInitialized || s_bProcessing )
|
||||
return;
|
||||
s_bProcessing = true;
|
||||
CloseCandidateList();
|
||||
s_bProcessing = false;
|
||||
}
|
||||
|
||||
auto CIME::CloseReadingInformation() -> void
|
||||
int CIME::GetCompLen()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return ms_compLen;
|
||||
}
|
||||
|
||||
auto CIME::ChangeInputLanguage() -> void
|
||||
int CIME::GetULBegin()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return ms_ulbegin;
|
||||
}
|
||||
|
||||
auto CIME::ChangeInputLanguageWorker() -> void
|
||||
int CIME::GetULEnd()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return ms_ulend;
|
||||
}
|
||||
|
||||
auto CIME::WMInputLanguage(HWND, UINT, WPARAM, LPARAM) -> LRESULT
|
||||
void CIME::CloseCandidateList()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<LRESULT>();
|
||||
ms_bCandidateList = false;
|
||||
ms_dwCandidateCount = 0;
|
||||
memset(&ms_wszCandidate, 0, sizeof(ms_wszCandidate));
|
||||
if(ms_pEvent)
|
||||
ms_pEvent->OnCloseCandidateList();
|
||||
}
|
||||
|
||||
auto CIME::WMStartComposition(HWND, UINT, WPARAM, LPARAM) -> LRESULT
|
||||
void CIME::CloseReadingInformation()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<LRESULT>();
|
||||
CIME::ms_bReadingInformation = false;
|
||||
if(CIME::ms_pEvent)
|
||||
CIME::ms_pEvent->OnCloseReadingWnd();
|
||||
}
|
||||
|
||||
auto CIME::WMComposition(HWND, UINT, WPARAM, LPARAM) -> LRESULT
|
||||
// PORT: 40250 re-reads the keyboard layout (GETLANG) and re-applies the IME support level when the language
|
||||
// changed. The host has one fixed input locale, so only the toggle check and the code-page event remain.
|
||||
void CIME::ChangeInputLanguage()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<LRESULT>();
|
||||
CheckToggleState();
|
||||
ChangeInputLanguageWorker();
|
||||
|
||||
if(ms_pEvent)
|
||||
ms_pEvent->OnChangeCodePage();
|
||||
}
|
||||
|
||||
auto CIME::WMEndComposition(HWND, UINT, WPARAM, LPARAM) -> LRESULT
|
||||
void CIME::ChangeInputLanguageWorker()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<LRESULT>();
|
||||
if ( !ms_bUILessMode )
|
||||
ms_iCandListIndexBase = 1;
|
||||
SetupImeApi();
|
||||
}
|
||||
|
||||
auto CIME::WMNotify(HWND, UINT, WPARAM, LPARAM) -> LRESULT
|
||||
// PORT: 40250 forces level 3 for the Korean keyboard layout; there is no keyboard layout here.
|
||||
void CIME::SetSupportLevel( DWORD dwImeLevel )
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<LRESULT>();
|
||||
if ( dwImeLevel < 2 || 3 < dwImeLevel )
|
||||
return;
|
||||
ms_dwIMELevel = dwImeLevel;
|
||||
// cancel current composition string.
|
||||
FinalizeString();
|
||||
}
|
||||
|
||||
auto CIME::WMChar(HWND, UINT, WPARAM, LPARAM) -> LRESULT
|
||||
LRESULT CIME::WMInputLanguage(HWND, UINT, WPARAM, LPARAM)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<LRESULT>();
|
||||
ChangeInputLanguage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto CIME::IncCurPos() -> void
|
||||
LRESULT CIME::WMStartComposition(HWND, UINT, WPARAM, LPARAM)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return 1L;
|
||||
}
|
||||
|
||||
auto CIME::DecCurPos() -> void
|
||||
// PORT: 40250 pulls GCS_RESULTSTR/GCS_COMPSTR out of the IMM context. The host never sends compositions.
|
||||
LRESULT CIME::WMComposition(HWND, UINT, WPARAM, LPARAM)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto CIME::SetCurPos(int) -> void
|
||||
LRESULT CIME::WMEndComposition(HWND, UINT, WPARAM, LPARAM)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
ms_compLen = 0;
|
||||
ms_ulbegin = 0;
|
||||
ms_ulend = 0;
|
||||
|
||||
if(ms_pEvent)
|
||||
ms_pEvent->OnUpdate();
|
||||
|
||||
return 0L;
|
||||
}
|
||||
|
||||
auto CIME::DelCurPos() -> void
|
||||
// PORT: 40250 handles IMN_* candidate/reading/toggle notifications from IMM; none are sent here.
|
||||
LRESULT CIME::WMNotify(HWND, UINT, WPARAM, LPARAM)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto CIME::CheckInputLocale() -> void
|
||||
LRESULT CIME::WMChar(HWND /*hWnd*/, UINT /*uiMsg*/, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
unsigned char c = (unsigned char)(wParam & 0xff);
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 8:
|
||||
if(ms_bCaptureInput == false)
|
||||
return 0;
|
||||
if (ms_curpos > 0)
|
||||
{
|
||||
DecCurPos();
|
||||
DelCurPos();
|
||||
}
|
||||
if(ms_pEvent)
|
||||
ms_pEvent->OnUpdate();
|
||||
return 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
if(ms_pEvent) {
|
||||
if (ms_pEvent->OnWM_CHAR(wParam, lParam))
|
||||
break;
|
||||
}
|
||||
if(ms_bCaptureInput == false)
|
||||
return 0;
|
||||
wchar_t w[10];
|
||||
MultiByteToWideChar(ms_uInputCodePage, 0, (char*)&c, 1, w, 1);
|
||||
|
||||
OnChar(w[0]);
|
||||
if (w[0] == L'|')
|
||||
OnChar(w[0]);
|
||||
if(ms_pEvent)
|
||||
ms_pEvent->OnUpdate();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto CIME::CheckToggleState() -> void
|
||||
/*---------------------------------------------------------------------------*/ /* Protected */
|
||||
void CIME::IncCurPos()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
if (ms_curpos < ms_lastpos)
|
||||
{
|
||||
int pos = FindColorTagEndPosition(m_wText + ms_curpos, ms_lastpos - ms_curpos);
|
||||
|
||||
if (pos > 0)
|
||||
ms_curpos = std::min(ms_lastpos, std::max(0, ms_curpos + (pos + 1)));
|
||||
else
|
||||
++ms_curpos;
|
||||
//++ms_curpos;
|
||||
}
|
||||
}
|
||||
|
||||
auto CIME::SetSupportLevel(DWORD) -> void
|
||||
void CIME::DecCurPos()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
if (ms_curpos > 0)
|
||||
{
|
||||
int pos = FindColorTagStartPosition(m_wText + ms_curpos - 1, ms_curpos);
|
||||
|
||||
if (pos > 0)
|
||||
ms_curpos = std::min(ms_lastpos, std::max(0, ms_curpos - (pos + 1)));
|
||||
else
|
||||
--ms_curpos;
|
||||
//--ms_curpos;
|
||||
}
|
||||
}
|
||||
|
||||
auto CIME::InsertString(wchar_t *, int) -> void
|
||||
int CIME::GetCurPos()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
int pos = GetTextTagOutputLen(m_wText, ms_curpos);
|
||||
return pos;
|
||||
//return ms_curpos;
|
||||
}
|
||||
|
||||
auto CIME::OnChar(wchar_t) -> void
|
||||
void CIME::SetCurPos(int offset)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
if (offset < 0 || offset > ms_lastpos)
|
||||
{
|
||||
ms_curpos = ms_lastpos;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// offset is a position in the rendered text, so it has to be mapped back to the buffer.
|
||||
//ms_curpos = min(ms_lastpos, offset);
|
||||
ms_curpos = std::min(ms_lastpos, GetTextTagInternalPosFromRenderPos(m_wText, ms_lastpos, offset));
|
||||
}
|
||||
}
|
||||
|
||||
auto CIME::GetCodePageFromLang(LANGID) -> UINT
|
||||
void CIME::DelCurPos()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<UINT>();
|
||||
if (ms_curpos < ms_lastpos)
|
||||
{
|
||||
int eraseCount = FindColorTagEndPosition(m_wText + ms_curpos, ms_lastpos - ms_curpos) + 1;
|
||||
// PORT: 40250 wcscpy()s the overlapping tail down; that is undefined for overlapping buffers, and the
|
||||
// buffer is not guaranteed NUL-terminated at ms_lastpos, so move exactly the live tail.
|
||||
memmove(m_wText + ms_curpos, m_wText + ms_curpos + eraseCount, sizeof(wchar_t) * (ms_lastpos - ms_curpos - eraseCount));
|
||||
ms_lastpos -= eraseCount;
|
||||
ms_curpos = std::min(ms_lastpos, ms_curpos);
|
||||
}
|
||||
}
|
||||
|
||||
auto CIME::ResultProcess(HIMC) -> void
|
||||
void CIME::PasteString(const char * str)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
const char * begin = str;
|
||||
const char * end = str + strlen(str);
|
||||
wchar_t m_wText[IMESTR_MAXLEN];
|
||||
int wstrLen = MultiByteToWideChar(ms_uInputCodePage, 0, begin, end - begin, m_wText, IMESTR_MAXLEN);
|
||||
InsertString(m_wText, wstrLen);
|
||||
if(ms_pEvent)
|
||||
ms_pEvent->OnUpdate();
|
||||
}
|
||||
|
||||
auto CIME::CompositionProcessBuilding(HIMC) -> void
|
||||
// PORT: 40250 reads the keyboard layout's default ANSI code page (GetLocaleInfoA LOCALE_IDEFAULTANSICODEPAGE).
|
||||
// The host's input locale is the client locale, so its code page (SetDefaultCodePage from locale.cfg) is used.
|
||||
void CIME::CheckInputLocale()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
static UINT s_uPrevCodePage = 0xFFFF;
|
||||
|
||||
ms_uInputCodePage = GetDefaultCodePage();
|
||||
if ( s_uPrevCodePage == ms_uInputCodePage )
|
||||
return;
|
||||
s_uPrevCodePage = ms_uInputCodePage;
|
||||
|
||||
ms_bVerticalCandidate = false;
|
||||
ms_wszCurrentIndicator = s_aszNonImeIndicator;
|
||||
|
||||
if(ms_uOutputCodePage != 1256) {
|
||||
ms_uOutputCodePage = ms_uInputCodePage;
|
||||
Clear();
|
||||
}
|
||||
}
|
||||
|
||||
auto CIME::CompositionProcess(HIMC) -> void
|
||||
// PORT: 40250 asks IMM whether an IME is open; there is none, so the state is IMEUI_STATE_OFF (0).
|
||||
void CIME::CheckToggleState()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
CheckInputLocale();
|
||||
ms_bChineseIME = false;
|
||||
ms_dwImeState = 0;
|
||||
}
|
||||
|
||||
auto CIME::AttributeProcess(HIMC) -> void
|
||||
/*---------------------------------------------------------------------------*/ /* Private */
|
||||
void CIME::InsertString(wchar_t* wString, int iSize)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
if (IsMax(wString, iSize))
|
||||
return;
|
||||
|
||||
if (ms_curpos < ms_lastpos)
|
||||
memmove(m_wText+ms_curpos+iSize, m_wText+ms_curpos, sizeof(wchar_t)*(ms_lastpos-ms_curpos));
|
||||
|
||||
memcpy(m_wText+ms_curpos, wString, sizeof(wchar_t)*iSize);
|
||||
|
||||
ms_curpos += iSize;
|
||||
ms_lastpos += iSize;
|
||||
}
|
||||
|
||||
auto CIME::CandidateProcess(HIMC) -> void
|
||||
void CIME::OnChar(wchar_t c)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
if (m_bOnlyNumberMode)
|
||||
if (!iswdigit(c))
|
||||
return;
|
||||
|
||||
if (!__IsWritable(c))
|
||||
return;
|
||||
|
||||
InsertString(&c, 1);
|
||||
}
|
||||
|
||||
auto CIME::ReadingProcess(HIMC) -> void
|
||||
// PORT: 40250 maps a keyboard-layout LANGID to its ANSI code page. Only CheckInputLocale's code page is used
|
||||
// here (see there), so this answers with it.
|
||||
UINT CIME::GetCodePageFromLang(LANGID)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return GetDefaultCodePage();
|
||||
}
|
||||
|
||||
auto CIME::IsMax(const wchar_t *, int) -> bool
|
||||
// PORT: the IMM composition/candidate/reading processors (40250 IME.cpp:951-1227). No IMM context exists.
|
||||
void CIME::ResultProcess(HIMC) {}
|
||||
void CIME::CompositionProcessBuilding(HIMC) {}
|
||||
void CIME::CompositionProcess(HIMC) {}
|
||||
void CIME::AttributeProcess(HIMC) {}
|
||||
void CIME::CandidateProcess(HIMC) {}
|
||||
void CIME::ReadingProcess(HIMC) {}
|
||||
|
||||
bool CIME::IsMax(const wchar_t* wInput, int len)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<bool>();
|
||||
if (ms_lastpos + len > IMESTR_MAXLEN)
|
||||
return true;
|
||||
|
||||
int textLen = WideCharToMultiByte(ms_uOutputCodePage, 0, m_wText, ms_lastpos, 0, 0, NULL, NULL);
|
||||
int inputLen = WideCharToMultiByte(ms_uOutputCodePage, 0, wInput, len, 0, 0, NULL, NULL);
|
||||
//return textLen + inputLen > m_max;
|
||||
|
||||
if (textLen + inputLen > m_max)
|
||||
return true;
|
||||
else if (m_userMax != 0 && m_max != m_userMax)
|
||||
{
|
||||
std::wstring str = GetTextTagOutputString(m_wText, ms_lastpos);
|
||||
std::wstring input = GetTextTagOutputString(wInput, len);
|
||||
int textLen = WideCharToMultiByte(ms_uOutputCodePage, 0, str.c_str(), str.length(), 0, 0, NULL, NULL);
|
||||
int inputLen = WideCharToMultiByte(ms_uOutputCodePage, 0, input.c_str(), input.length(), 0, 0, NULL, NULL);
|
||||
return textLen + inputLen > m_userMax;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto CIME::GetImeId(UINT) -> DWORD
|
||||
// PORT: 40250 identifies the CHT/CHS IME DLL version and the reading-window orientation. No IME DLL here.
|
||||
DWORD CIME::GetImeId(UINT)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<DWORD>();
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto CIME::GetReadingWindowOrientation() -> bool
|
||||
bool CIME::GetReadingWindowOrientation()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<bool>();
|
||||
return true;
|
||||
}
|
||||
|
||||
auto CIME::SetupImeApi() -> void
|
||||
void CIME::SetupImeApi()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
_GetReadingString = NULL;
|
||||
_ShowReadingWindow = NULL;
|
||||
}
|
||||
|
||||
decltype(CIME::_ImmLockIMC) CIME::_ImmLockIMC{};
|
||||
|
||||
@@ -63,11 +63,6 @@ void AddStubConstants_guild(PyObject* poModule)
|
||||
}
|
||||
|
||||
// 40250 UserInterface/PythonIMEModule.cpp
|
||||
void AddStubConstants_ime(PyObject* poModule)
|
||||
{
|
||||
(void) poModule;
|
||||
}
|
||||
|
||||
// 40250 UserInterface/PythonMessenger.cpp
|
||||
void AddStubConstants_messenger(PyObject* poModule)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
void AddStubConstants_event(PyObject* poModule);
|
||||
void AddStubConstants_eventMgr(PyObject* poModule);
|
||||
void AddStubConstants_guild(PyObject* poModule);
|
||||
void AddStubConstants_ime(PyObject* poModule);
|
||||
void AddStubConstants_messenger(PyObject* poModule);
|
||||
void AddStubConstants_profiler(PyObject* poModule);
|
||||
void AddStubConstants_quest(PyObject* poModule);
|
||||
@@ -154,76 +153,6 @@ PyMethodDef methods_guild[] = {
|
||||
{ "Destroy", stub_guild_Destroy, METH_VARARGS },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
// 40250 UserInterface/PythonIMEModule.cpp: ime export names.
|
||||
PyObject* stub_ime_Enable(PyObject*, PyObject*) { return stub_call_named("ime.Enable", Py_BuildNone()); }
|
||||
PyObject* stub_ime_Disable(PyObject*, PyObject*) { return stub_call_named("ime.Disable", Py_BuildNone()); }
|
||||
PyObject* stub_ime_EnableCaptureInput(PyObject*, PyObject*) { return stub_call_named("ime.EnableCaptureInput", Py_BuildNone()); }
|
||||
PyObject* stub_ime_DisableCaptureInput(PyObject*, PyObject*) { return stub_call_named("ime.DisableCaptureInput", Py_BuildNone()); }
|
||||
PyObject* stub_ime_SetMax(PyObject*, PyObject*) { return stub_call_named("ime.SetMax", Py_BuildNone()); }
|
||||
PyObject* stub_ime_SetUserMax(PyObject*, PyObject*) { return stub_call_named("ime.SetUserMax", Py_BuildNone()); }
|
||||
PyObject* stub_ime_SetText(PyObject*, PyObject*) { return stub_call_named("ime.SetText", Py_BuildNone()); }
|
||||
PyObject* stub_ime_GetText(PyObject*, PyObject*) { return stub_call_named("ime.GetText", Py_BuildValue("s", "")); }
|
||||
PyObject* stub_ime_GetCodePage(PyObject*, PyObject*) { return stub_call_named("ime.GetCodePage", Py_BuildValue("i", 0)); }
|
||||
PyObject* stub_ime_GetCandidateCount(PyObject*, PyObject*) { return stub_call_named("ime.GetCandidateCount", Py_BuildValue("i", 0)); }
|
||||
PyObject* stub_ime_GetCandidate(PyObject*, PyObject*) { return stub_call_named("ime.GetCandidate", Py_BuildValue("si", "", 0)); }
|
||||
PyObject* stub_ime_GetCandidateSelection(PyObject*, PyObject*) { return stub_call_named("ime.GetCandidateSelection", Py_BuildValue("i", 0)); }
|
||||
PyObject* stub_ime_GetReading(PyObject*, PyObject*) { return stub_call_named("ime.GetReading", Py_BuildValue("s", "")); }
|
||||
PyObject* stub_ime_GetReadingError(PyObject*, PyObject*) { return stub_call_named("ime.GetReadingError", Py_BuildValue("i", 0)); }
|
||||
PyObject* stub_ime_EnableIME(PyObject*, PyObject*) { return stub_call_named("ime.EnableIME", Py_BuildNone()); }
|
||||
PyObject* stub_ime_DisableIME(PyObject*, PyObject*) { return stub_call_named("ime.DisableIME", Py_BuildNone()); }
|
||||
PyObject* stub_ime_GetInputMode(PyObject*, PyObject*) { return stub_call_named("ime.GetInputMode", Py_BuildValue("i", 0)); }
|
||||
PyObject* stub_ime_SetInputMode(PyObject*, PyObject*) { return stub_call_named("ime.SetInputMode", Py_BuildNone()); }
|
||||
PyObject* stub_ime_SetNumberMode(PyObject*, PyObject*) { return stub_call_named("ime.SetNumberMode", Py_BuildNone()); }
|
||||
PyObject* stub_ime_SetStringMode(PyObject*, PyObject*) { return stub_call_named("ime.SetStringMode", Py_BuildNone()); }
|
||||
PyObject* stub_ime_AddExceptKey(PyObject*, PyObject*) { return stub_call_named("ime.AddExceptKey", Py_BuildNone()); }
|
||||
PyObject* stub_ime_ClearExceptKey(PyObject*, PyObject*) { return stub_call_named("ime.ClearExceptKey", Py_BuildNone()); }
|
||||
PyObject* stub_ime_MoveLeft(PyObject*, PyObject*) { return stub_call_named("ime.MoveLeft", Py_BuildNone()); }
|
||||
PyObject* stub_ime_MoveRight(PyObject*, PyObject*) { return stub_call_named("ime.MoveRight", Py_BuildNone()); }
|
||||
PyObject* stub_ime_MoveHome(PyObject*, PyObject*) { return stub_call_named("ime.MoveHome", Py_BuildNone()); }
|
||||
PyObject* stub_ime_MoveEnd(PyObject*, PyObject*) { return stub_call_named("ime.MoveEnd", Py_BuildNone()); }
|
||||
PyObject* stub_ime_SetCursorPosition(PyObject*, PyObject*) { return stub_call_named("ime.SetCursorPosition", Py_BuildNone()); }
|
||||
PyObject* stub_ime_Delete(PyObject*, PyObject*) { return stub_call_named("ime.Delete", Py_BuildNone()); }
|
||||
PyObject* stub_ime_PasteString(PyObject*, PyObject*) { return stub_call_named("ime.PasteString", Py_BuildNone()); }
|
||||
PyObject* stub_ime_PasteBackspace(PyObject*, PyObject*) { return stub_call_named("ime.PasteBackspace", Py_BuildNone()); }
|
||||
PyObject* stub_ime_PasteReturn(PyObject*, PyObject*) { return stub_call_named("ime.PasteReturn", Py_BuildNone()); }
|
||||
PyObject* stub_ime_PasteTextFromClipBoard(PyObject*, PyObject*) { return stub_call_named("ime.PasteTextFromClipBoard", Py_BuildNone()); }
|
||||
PyObject* stub_ime_EnablePaste(PyObject*, PyObject*) { return stub_call_named("ime.EnablePaste", Py_BuildNone()); }
|
||||
PyMethodDef methods_ime[] = {
|
||||
{ "Enable", stub_ime_Enable, METH_VARARGS },
|
||||
{ "Disable", stub_ime_Disable, METH_VARARGS },
|
||||
{ "EnableCaptureInput", stub_ime_EnableCaptureInput, METH_VARARGS },
|
||||
{ "DisableCaptureInput", stub_ime_DisableCaptureInput, METH_VARARGS },
|
||||
{ "SetMax", stub_ime_SetMax, METH_VARARGS },
|
||||
{ "SetUserMax", stub_ime_SetUserMax, METH_VARARGS },
|
||||
{ "SetText", stub_ime_SetText, METH_VARARGS },
|
||||
{ "GetText", stub_ime_GetText, METH_VARARGS },
|
||||
{ "GetCodePage", stub_ime_GetCodePage, METH_VARARGS },
|
||||
{ "GetCandidateCount", stub_ime_GetCandidateCount, METH_VARARGS },
|
||||
{ "GetCandidate", stub_ime_GetCandidate, METH_VARARGS },
|
||||
{ "GetCandidateSelection", stub_ime_GetCandidateSelection, METH_VARARGS },
|
||||
{ "GetReading", stub_ime_GetReading, METH_VARARGS },
|
||||
{ "GetReadingError", stub_ime_GetReadingError, METH_VARARGS },
|
||||
{ "EnableIME", stub_ime_EnableIME, METH_VARARGS },
|
||||
{ "DisableIME", stub_ime_DisableIME, METH_VARARGS },
|
||||
{ "GetInputMode", stub_ime_GetInputMode, METH_VARARGS },
|
||||
{ "SetInputMode", stub_ime_SetInputMode, METH_VARARGS },
|
||||
{ "SetNumberMode", stub_ime_SetNumberMode, METH_VARARGS },
|
||||
{ "SetStringMode", stub_ime_SetStringMode, METH_VARARGS },
|
||||
{ "AddExceptKey", stub_ime_AddExceptKey, METH_VARARGS },
|
||||
{ "ClearExceptKey", stub_ime_ClearExceptKey, METH_VARARGS },
|
||||
{ "MoveLeft", stub_ime_MoveLeft, METH_VARARGS },
|
||||
{ "MoveRight", stub_ime_MoveRight, METH_VARARGS },
|
||||
{ "MoveHome", stub_ime_MoveHome, METH_VARARGS },
|
||||
{ "MoveEnd", stub_ime_MoveEnd, METH_VARARGS },
|
||||
{ "SetCursorPosition", stub_ime_SetCursorPosition, METH_VARARGS },
|
||||
{ "Delete", stub_ime_Delete, METH_VARARGS },
|
||||
{ "PasteString", stub_ime_PasteString, METH_VARARGS },
|
||||
{ "PasteBackspace", stub_ime_PasteBackspace, METH_VARARGS },
|
||||
{ "PasteReturn", stub_ime_PasteReturn, METH_VARARGS },
|
||||
{ "PasteTextFromClipBoard", stub_ime_PasteTextFromClipBoard, METH_VARARGS },
|
||||
{ "EnablePaste", stub_ime_EnablePaste, METH_VARARGS },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
// 40250 UserInterface/PythonMessenger.cpp: messenger export names.
|
||||
PyObject* stub_messenger_RemoveFriend(PyObject*, PyObject*) { return stub_call_named("messenger.RemoveFriend", Py_BuildNone()); }
|
||||
PyObject* stub_messenger_IsFriendByName(PyObject*, PyObject*) { return stub_call_named("messenger.IsFriendByName", Py_BuildValue("i", 0)); }
|
||||
@@ -471,11 +400,6 @@ void init_2v0_gameplay_stubs() {
|
||||
PyModule_AddIntConstant(module, "__port_stub__", 1);
|
||||
AddStubConstants_guild(module);
|
||||
}
|
||||
{
|
||||
PyObject* module = Py_InitModule("ime", methods_ime);
|
||||
PyModule_AddIntConstant(module, "__port_stub__", 1);
|
||||
AddStubConstants_ime(module);
|
||||
}
|
||||
{
|
||||
PyObject* module = Py_InitModule("messenger", methods_messenger);
|
||||
PyModule_AddIntConstant(module, "__port_stub__", 1);
|
||||
|
||||
@@ -88,14 +88,15 @@ public:
|
||||
}
|
||||
void BlendEventCamera(const SCameraSetting&, float) override {}
|
||||
void SetDefaultCamera() override { CPythonApplication::Instance().SetDefaultCamera(); }
|
||||
void RunIMEUpdate() override {}
|
||||
void RunIMETabEvent() override {}
|
||||
void RunIMEReturnEvent() override {}
|
||||
void RunIMEChangeCodePage() override {}
|
||||
void RunIMEOpenCandidateListEvent() override {}
|
||||
void RunIMECloseCandidateListEvent() override {}
|
||||
void RunIMEOpenReadingWndEvent() override {}
|
||||
void RunIMECloseReadingWndEvent() override {}
|
||||
// 40250 CPythonApplication::RunIME* (PythonApplicationEvent.cpp:148-195): CPythonIME's event sink.
|
||||
void RunIMEUpdate() override { UI::CWindowManager::Instance().RunIMEUpdate(); }
|
||||
void RunIMETabEvent() override { UI::CWindowManager::Instance().RunIMETabEvent(); }
|
||||
void RunIMEReturnEvent() override { UI::CWindowManager::Instance().RunIMEReturnEvent(); }
|
||||
void RunIMEChangeCodePage() override { UI::CWindowManager::Instance().RunChangeCodePage(); }
|
||||
void RunIMEOpenCandidateListEvent() override { UI::CWindowManager::Instance().RunOpenCandidate(); }
|
||||
void RunIMECloseCandidateListEvent() override { UI::CWindowManager::Instance().RunCloseCandidate(); }
|
||||
void RunIMEOpenReadingWndEvent() override { UI::CWindowManager::Instance().RunOpenReading(); }
|
||||
void RunIMECloseReadingWndEvent() override { UI::CWindowManager::Instance().RunCloseReading(); }
|
||||
};
|
||||
std::unique_ptr<GameApplicationAdapter> g_game_application;
|
||||
// The CPythonApplication members the game phase reaches through Instance() (批次 2V2), in 40250's member
|
||||
@@ -109,6 +110,7 @@ struct GameSingletons
|
||||
CItemManager kItemMgr;
|
||||
CPythonCharacterManager kChrMgr;
|
||||
CPythonGraphic pyGraphic; // owns CCullingManager (m_CullingManager)
|
||||
CPythonIME pyIme;
|
||||
CPythonItem pyItem;
|
||||
CPythonShop pyShop;
|
||||
CPythonExchange pyExchange;
|
||||
@@ -266,6 +268,47 @@ void UIKey(int key, bool pressed)
|
||||
g_window_manager->RunKeyUp(key);
|
||||
}
|
||||
|
||||
// 40250 CPythonApplication::WindowProcedure (PythonApplicationProcedure.cpp:111-117): WM_CHAR goes to
|
||||
// CPythonIME::WMChar and WM_KEYDOWN to OnIMEKeyDown (the VK code, next to DirectInput's DIK stream). The host
|
||||
// delivers characters as Unicode code points; the 40250 window is an ANSI window, so a character that the input
|
||||
// code page holds as one byte arrives as that byte, like WM_CHAR. PORT: anything else is what a Windows IME
|
||||
// commits through WM_IME_COMPOSITION/GCS_RESULTSTR, which CIME::ResultProcess inserts as a wide string.
|
||||
void UIChar(unsigned codepoint)
|
||||
{
|
||||
if (!g_game_singletons || !codepoint) return;
|
||||
CPythonIME& ime = CPythonIME::Instance();
|
||||
if (codepoint < 0x80)
|
||||
{
|
||||
ime.WMChar(NULL, WM_CHAR, codepoint, 0);
|
||||
return;
|
||||
}
|
||||
const wchar_t wide = wchar_t(codepoint);
|
||||
char bytes[8];
|
||||
BOOL used_default = FALSE;
|
||||
const int n = WideCharToMultiByte(CIME::ms_uInputCodePage, 0, &wide, 1, bytes, sizeof(bytes), "?", &used_default);
|
||||
if (n == 1 && !used_default)
|
||||
{
|
||||
ime.WMChar(NULL, WM_CHAR, (unsigned char)bytes[0], 0);
|
||||
return;
|
||||
}
|
||||
// 40250 CIME::WMComposition with GCS_RESULTSTR: ResultProcess inserts the committed string, then OnUpdate.
|
||||
if (!CIME::ms_bCaptureInput)
|
||||
return;
|
||||
struct ResultAccess : CPythonIME
|
||||
{
|
||||
static void Insert(CPythonIME& ime, wchar_t* text, int len) { (ime.*(&ResultAccess::InsertString))(text, len); }
|
||||
};
|
||||
wchar_t text[1] = { wide };
|
||||
ResultAccess::Insert(ime, text, 1);
|
||||
if (CIME::ms_pEvent)
|
||||
CIME::ms_pEvent->OnUpdate();
|
||||
}
|
||||
|
||||
void UIIMEKeyDown(int vkey)
|
||||
{
|
||||
if (g_window_manager) g_window_manager->RunIMEKeyDown(vkey);
|
||||
}
|
||||
|
||||
void UIUpdate()
|
||||
{
|
||||
// While system.py is inside app.Loop(), one host frame is one CPythonApplication::Process(),
|
||||
@@ -341,6 +384,7 @@ bool run_main_script_body(const char* lpCmdLine, std::string* error)
|
||||
// The module initializers follow 40250's order; missing modules arrive in later 2V steps.
|
||||
initpack();
|
||||
initdbg();
|
||||
initime();
|
||||
initgrp();
|
||||
initgrpImage();
|
||||
initgrpText();
|
||||
|
||||
@@ -55,6 +55,9 @@ void SetUISize(int width, int height);
|
||||
void UIMouseMove(int x, int y);
|
||||
void UIMouseButton(int button, bool pressed, int x, int y);
|
||||
void UIKey(int key, bool pressed);
|
||||
// WM_CHAR (a Unicode code point) and WM_KEYDOWN (a Win32 VK code) for CPythonIME and OnIMEKeyDown.
|
||||
void UIChar(unsigned codepoint);
|
||||
void UIIMEKeyDown(int vkey);
|
||||
// While IsAppLooping(), UIUpdate is AppFrame() and UIRender keeps the commands that Process() drew.
|
||||
void UIUpdate();
|
||||
void UIRender();
|
||||
|
||||
@@ -68,7 +68,7 @@ void CPythonApplication::SetFrameSkip(bool) { MT_PLATFORM_STUB(); }
|
||||
// fonts and the IME here. The Godot window and its canvas already exist when the host starts the
|
||||
// script, so the window size is the canvas size (PythonBoot::SetUISize) rather than the width/height
|
||||
// passed from metin2.cfg, and the graphic device is the recording device (RecordingDevice.h) at that
|
||||
// size. Cursors, sound, keyboard, fonts and the IME are not created here yet.
|
||||
// size. Cursors, sound, keyboard and fonts are not created here yet.
|
||||
bool CPythonApplication::Create(PyObject*, const char*, int, int, int)
|
||||
{
|
||||
unsigned width = 0, height = 0;
|
||||
@@ -125,7 +125,11 @@ bool CPythonApplication::Create(PyObject*, const char*, int, int, int)
|
||||
// 40250 m_pyItem.Create() (PythonApplication.cpp:1253): registers dropitem.mse with CEffectManager.
|
||||
CPythonItem::Instance().Create();
|
||||
|
||||
// 40250 PythonApplication.cpp:1260, after DefaultFont_Startup and the IME.
|
||||
// 40250 PythonApplication.cpp:1258-1259 (after DefaultFont_Startup).
|
||||
CPythonIME::Instance().Create(GetWindowHandle());
|
||||
CPythonIME::Instance().SetText("", 0);
|
||||
|
||||
// 40250 PythonApplication.cpp:1260.
|
||||
CPythonTextTail::Instance().Initialize();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
#include "StdAfx.h"
|
||||
#include "PythonIME.h"
|
||||
#include "AbstractApplication.h"
|
||||
|
||||
CPythonIME::CPythonIME()
|
||||
: CIME()
|
||||
{
|
||||
ms_pEvent = this;
|
||||
}
|
||||
|
||||
CPythonIME::~CPythonIME()
|
||||
{
|
||||
Tracen("PythonIME Clear");
|
||||
}
|
||||
|
||||
void CPythonIME::Create(HWND hWnd)
|
||||
{
|
||||
Initialize(hWnd);
|
||||
}
|
||||
|
||||
void CPythonIME::MoveLeft()
|
||||
{
|
||||
DecCurPos();
|
||||
}
|
||||
|
||||
void CPythonIME::MoveRight()
|
||||
{
|
||||
IncCurPos();
|
||||
}
|
||||
|
||||
void CPythonIME::MoveHome()
|
||||
{
|
||||
ms_curpos = 0;
|
||||
}
|
||||
|
||||
void CPythonIME::MoveEnd()
|
||||
{
|
||||
ms_curpos = ms_lastpos;
|
||||
}
|
||||
|
||||
void CPythonIME::SetCursorPosition(int iPosition)
|
||||
{
|
||||
SetCurPos(iPosition);
|
||||
}
|
||||
|
||||
void CPythonIME::Delete()
|
||||
{
|
||||
DelCurPos();
|
||||
}
|
||||
|
||||
void CPythonIME::OnUpdate()
|
||||
{
|
||||
IAbstractApplication::GetSingleton().RunIMEUpdate();
|
||||
}
|
||||
|
||||
void CPythonIME::OnTab()
|
||||
{
|
||||
IAbstractApplication::GetSingleton().RunIMETabEvent();
|
||||
}
|
||||
|
||||
void CPythonIME::OnReturn()
|
||||
{
|
||||
IAbstractApplication::GetSingleton().RunIMEReturnEvent();
|
||||
}
|
||||
|
||||
void CPythonIME::OnEscape()
|
||||
{
|
||||
// IAbstractApplication::GetSingleton().RunIMEEscapeEvent();
|
||||
}
|
||||
|
||||
bool CPythonIME::OnWM_CHAR( WPARAM wParam, LPARAM lParam )
|
||||
{
|
||||
unsigned char c = (unsigned char)(wParam & 0xff); // PORT: functional cast of a two-word type is MSVC-only.
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case VK_RETURN:
|
||||
OnReturn();
|
||||
return true;
|
||||
|
||||
case VK_TAB:
|
||||
if(ms_bCaptureInput == false)
|
||||
return 0;
|
||||
OnTab();
|
||||
return true;
|
||||
|
||||
case VK_ESCAPE:
|
||||
if(ms_bCaptureInput == false)
|
||||
return 0;
|
||||
OnEscape();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CPythonIME::OnChangeCodePage()
|
||||
{
|
||||
IAbstractApplication::GetSingleton().RunIMEChangeCodePage();
|
||||
}
|
||||
|
||||
void CPythonIME::OnOpenCandidateList()
|
||||
{
|
||||
IAbstractApplication::GetSingleton().RunIMEOpenCandidateListEvent();
|
||||
}
|
||||
|
||||
void CPythonIME::OnCloseCandidateList()
|
||||
{
|
||||
IAbstractApplication::GetSingleton().RunIMECloseCandidateListEvent();
|
||||
}
|
||||
|
||||
void CPythonIME::OnOpenReadingWnd()
|
||||
{
|
||||
IAbstractApplication::GetSingleton().RunIMEOpenReadingWndEvent();
|
||||
}
|
||||
|
||||
void CPythonIME::OnCloseReadingWnd()
|
||||
{
|
||||
IAbstractApplication::GetSingleton().RunIMECloseReadingWndEvent();
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
#include "StdAfx.h"
|
||||
#include "PythonIME.h"
|
||||
#include "PythonApplication.h"
|
||||
|
||||
PyObject* imeEnable(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().Initialize(CPythonApplication::Instance().GetWindowHandle());
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imeDisable(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().Uninitialize();
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imeEnableCaptureInput(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().EnableCaptureInput();
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imeDisableCaptureInput(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().DisableCaptureInput();
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imeSetMax(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
int iMax;
|
||||
if (!PyTuple_GetInteger(poArgs, 0, &iMax))
|
||||
return Py_BuildException();
|
||||
|
||||
CPythonIME::Instance().SetMax(iMax);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imeSetUserMax(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
int iMax;
|
||||
if (!PyTuple_GetInteger(poArgs, 0, &iMax))
|
||||
return Py_BuildException();
|
||||
|
||||
CPythonIME::Instance().SetUserMax(iMax);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imeSetText(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
char* szText;
|
||||
if (!PyTuple_GetString(poArgs, 0, &szText))
|
||||
return Py_BuildException();
|
||||
|
||||
CPythonIME::Instance().SetText(szText, strlen(szText));
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imeGetText(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
int bCodePage;
|
||||
if (!PyTuple_GetInteger(poArgs, 0, &bCodePage))
|
||||
bCodePage = 0;
|
||||
|
||||
std::string strText;
|
||||
CPythonIME::Instance().GetText(strText, bCodePage ? true : false);
|
||||
return Py_BuildValue("s", strText.c_str());
|
||||
}
|
||||
|
||||
PyObject* imeGetCodePage(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
return Py_BuildValue("i", CPythonIME::Instance().GetCodePage());
|
||||
}
|
||||
|
||||
PyObject* imeGetCandidateCount(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
return Py_BuildValue("i", CPythonIME::Instance().GetCandidatePageCount());
|
||||
}
|
||||
|
||||
PyObject* imeGetCandidate(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
int index;
|
||||
if (!PyTuple_GetInteger(poArgs, 0, &index))
|
||||
return Py_BuildException();
|
||||
|
||||
std::string strText;
|
||||
int iLength = CPythonIME::Instance().GetCandidate(index, strText);
|
||||
return Py_BuildValue("si", strText.c_str(), iLength);
|
||||
}
|
||||
|
||||
PyObject* imeGetCandidateSelection(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
return Py_BuildValue("i", CPythonIME::Instance().GetCandidateSelection());
|
||||
}
|
||||
|
||||
PyObject* imeGetReading(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
std::string strText;
|
||||
CPythonIME::Instance().GetReading(strText);
|
||||
return Py_BuildValue("s", strText.c_str());
|
||||
}
|
||||
|
||||
PyObject* imeGetReadingError(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
return Py_BuildValue("i", CPythonIME::Instance().GetReadingError());
|
||||
}
|
||||
|
||||
PyObject* imeEnableIME(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().EnableIME();
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imeDisableIME(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().DisableIME();
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imeSetInputMode(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
int mode;
|
||||
if (!PyTuple_GetInteger(poArgs, 0, &mode))
|
||||
return Py_BuildException();
|
||||
|
||||
CPythonIME::Instance().SetInputMode(mode);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * imeSetNumberMode(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().SetNumberMode();
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * imeAddExceptKey(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
int key;
|
||||
if (!PyTuple_GetInteger(poArgs, 0, &key))
|
||||
return Py_BuildException();
|
||||
|
||||
CPythonIME::Instance().AddExceptKey(key);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * imeClearExceptKey(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().ClearExceptKey();
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject * imeSetStringMode(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().SetStringMode();
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imeGetInputMode(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
return Py_BuildValue("i", CPythonIME::Instance().GetInputMode());
|
||||
}
|
||||
|
||||
PyObject* imeMoveLeft(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().MoveLeft();
|
||||
|
||||
return Py_BuildNone();
|
||||
}
|
||||
PyObject* imeMoveRight(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().MoveRight();
|
||||
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imeMoveHome(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().MoveHome();
|
||||
|
||||
return Py_BuildNone();
|
||||
}
|
||||
PyObject* imeMoveEnd(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().MoveEnd();
|
||||
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imeSetCursorPosition(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
int iPosition;
|
||||
if (!PyTuple_GetInteger(poArgs, 0, &iPosition))
|
||||
return Py_BuildException();
|
||||
|
||||
CPythonIME::Instance().SetCursorPosition(iPosition);
|
||||
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imeDelete(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().Delete();
|
||||
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imePasteTextFromClipBoard(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
CPythonIME::Instance().PasteTextFromClipBoard();
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imeEnablePaste(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
int iFlag;
|
||||
if (!PyTuple_GetInteger(poArgs, 0, &iFlag))
|
||||
return Py_BuildException();
|
||||
|
||||
CPythonIME::Instance().EnablePaste(iFlag ? true : false);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imePasteString(PyObject * poSelf, PyObject * poArgs)
|
||||
{
|
||||
char* szText;
|
||||
if (!PyTuple_GetString(poArgs, 0, &szText))
|
||||
return Py_BuildException();
|
||||
CPythonIME::Instance().PasteString(szText);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imePasteBackspace(PyObject * poSelf, PyObject * poArgs)
|
||||
{
|
||||
CPythonIME::Instance().WMChar(NULL, WM_CHAR, 0x08, NULL);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
PyObject* imePasteReturn(PyObject * poSelf, PyObject * poArgs)
|
||||
{
|
||||
CPythonIME::Instance().WMChar(NULL, WM_CHAR, 0x0D, NULL);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
|
||||
void initime()
|
||||
{
|
||||
static PyMethodDef s_methods[] =
|
||||
{
|
||||
{ "Enable", imeEnable, METH_VARARGS },
|
||||
{ "Disable", imeDisable, METH_VARARGS },
|
||||
|
||||
{ "EnableCaptureInput", imeEnableCaptureInput, METH_VARARGS },
|
||||
{ "DisableCaptureInput", imeDisableCaptureInput, METH_VARARGS },
|
||||
{ "SetMax", imeSetMax, METH_VARARGS },
|
||||
{ "SetUserMax", imeSetUserMax, METH_VARARGS },
|
||||
{ "SetText", imeSetText, METH_VARARGS },
|
||||
{ "GetText", imeGetText, METH_VARARGS },
|
||||
{ "GetCodePage", imeGetCodePage, METH_VARARGS },
|
||||
{ "GetCandidateCount", imeGetCandidateCount, METH_VARARGS },
|
||||
{ "GetCandidate", imeGetCandidate, METH_VARARGS },
|
||||
{ "GetCandidateSelection", imeGetCandidateSelection, METH_VARARGS },
|
||||
{ "GetReading", imeGetReading, METH_VARARGS },
|
||||
{ "GetReadingError", imeGetReadingError, METH_VARARGS },
|
||||
{ "EnableIME", imeEnableIME, METH_VARARGS },
|
||||
{ "DisableIME", imeDisableIME, METH_VARARGS },
|
||||
{ "GetInputMode", imeGetInputMode, METH_VARARGS },
|
||||
{ "SetInputMode", imeSetInputMode, METH_VARARGS },
|
||||
|
||||
{ "SetNumberMode", imeSetNumberMode, METH_VARARGS },
|
||||
{ "SetStringMode", imeSetStringMode, METH_VARARGS },
|
||||
{ "AddExceptKey", imeAddExceptKey, METH_VARARGS },
|
||||
{ "ClearExceptKey", imeClearExceptKey, METH_VARARGS },
|
||||
|
||||
{ "MoveLeft", imeMoveLeft, METH_VARARGS },
|
||||
{ "MoveRight", imeMoveRight, METH_VARARGS },
|
||||
{ "MoveHome", imeMoveHome, METH_VARARGS },
|
||||
{ "MoveEnd", imeMoveEnd, METH_VARARGS },
|
||||
{ "SetCursorPosition", imeSetCursorPosition, METH_VARARGS },
|
||||
{ "Delete", imeDelete, METH_VARARGS },
|
||||
{ "PasteString", imePasteString, METH_VARARGS },
|
||||
{ "PasteBackspace", imePasteBackspace, METH_VARARGS },
|
||||
{ "PasteReturn", imePasteReturn, METH_VARARGS },
|
||||
{ "PasteTextFromClipBoard", imePasteTextFromClipBoard, METH_VARARGS },
|
||||
{ "EnablePaste", imeEnablePaste, METH_VARARGS },
|
||||
|
||||
{ NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
Py_InitModule("ime", s_methods);
|
||||
}
|
||||
@@ -44,6 +44,7 @@ enum
|
||||
// The Python module initializers RunMainScript calls, each defined in its own Python*Module.cpp.
|
||||
// Listed here as 40250 lists them; only the ported ones are defined.
|
||||
void initpack();
|
||||
void initime();
|
||||
void initapp();
|
||||
void initchr();
|
||||
void initchrmgr();
|
||||
|
||||
@@ -28,6 +28,12 @@
|
||||
#define VK_HOME 0x24
|
||||
#define VK_END 0x23
|
||||
#define VK_DELETE 0x2E
|
||||
#define VK_BACK 0x08
|
||||
#define VK_TAB 0x09
|
||||
#define VK_RETURN 0x0D
|
||||
#define VK_ESCAPE 0x1B
|
||||
#define WM_KEYDOWN 0x0100
|
||||
#define WM_CHAR 0x0102
|
||||
|
||||
// winuser.h functions the platform layer implements (platform/ScriptLib/PythonBoot.cpp).
|
||||
void PostQuitMessage(int nExitCode);
|
||||
|
||||
@@ -71,6 +71,8 @@ void Metin2PythonHost::ui_mouse_button(int button, bool pressed, int x, int y) {
|
||||
PythonBoot::UIMouseButton(button, pressed, x, y);
|
||||
}
|
||||
void Metin2PythonHost::ui_key(int key, bool pressed) { PythonBoot::UIKey(key, pressed); }
|
||||
void Metin2PythonHost::ui_char(int codepoint) { PythonBoot::UIChar(unsigned(codepoint)); }
|
||||
void Metin2PythonHost::ui_ime_key(int vkey) { PythonBoot::UIIMEKeyDown(vkey); }
|
||||
void Metin2PythonHost::ui_update() { PythonBoot::UIUpdate(); }
|
||||
Array Metin2PythonHost::ui_render_commands() {
|
||||
PythonBoot::UIRender();
|
||||
@@ -264,6 +266,8 @@ void Metin2PythonHost::set_ui_size(int, int) {}
|
||||
void Metin2PythonHost::ui_mouse_move(int, int) {}
|
||||
void Metin2PythonHost::ui_mouse_button(int, bool, int, int) {}
|
||||
void Metin2PythonHost::ui_key(int, bool) {}
|
||||
void Metin2PythonHost::ui_char(int) {}
|
||||
void Metin2PythonHost::ui_ime_key(int) {}
|
||||
void Metin2PythonHost::ui_update() {}
|
||||
Array Metin2PythonHost::ui_render_commands() { return Array(); }
|
||||
Ref<Image> Metin2PythonHost::memory_texture(const String &, int64_t) { return Ref<Image>(); }
|
||||
@@ -287,6 +291,8 @@ void Metin2PythonHost::_bind_methods() {
|
||||
ClassDB::bind_static_method("Metin2PythonHost", D_METHOD("ui_mouse_move", "x", "y"), &Metin2PythonHost::ui_mouse_move);
|
||||
ClassDB::bind_static_method("Metin2PythonHost", D_METHOD("ui_mouse_button", "button", "pressed", "x", "y"), &Metin2PythonHost::ui_mouse_button);
|
||||
ClassDB::bind_static_method("Metin2PythonHost", D_METHOD("ui_key", "key", "pressed"), &Metin2PythonHost::ui_key);
|
||||
ClassDB::bind_static_method("Metin2PythonHost", D_METHOD("ui_char", "codepoint"), &Metin2PythonHost::ui_char);
|
||||
ClassDB::bind_static_method("Metin2PythonHost", D_METHOD("ui_ime_key", "vkey"), &Metin2PythonHost::ui_ime_key);
|
||||
ClassDB::bind_static_method("Metin2PythonHost", D_METHOD("ui_update"), &Metin2PythonHost::ui_update);
|
||||
ClassDB::bind_static_method("Metin2PythonHost", D_METHOD("ui_render_commands"), &Metin2PythonHost::ui_render_commands);
|
||||
ClassDB::bind_static_method("Metin2PythonHost", D_METHOD("memory_texture", "name", "known_revision"),
|
||||
|
||||
@@ -38,6 +38,9 @@ public:
|
||||
static void ui_mouse_move(int x, int y);
|
||||
static void ui_mouse_button(int button, bool pressed, int x, int y);
|
||||
static void ui_key(int key, bool pressed);
|
||||
// WM_CHAR (Unicode code point) and WM_KEYDOWN (Win32 VK code) for the 40250 IME.
|
||||
static void ui_char(int codepoint);
|
||||
static void ui_ime_key(int vkey);
|
||||
static void ui_update();
|
||||
static godot::Array ui_render_commands();
|
||||
// The pixels of a "mem:<id>@<revision>" image command (the CGraphicFontTexture glyph pages) as an
|
||||
|
||||
@@ -655,6 +655,22 @@ bool FakeLoginServer::ServeGame(Connection& c, int index)
|
||||
if (!ok)
|
||||
return Fail(name + ": send GC_EXCHANGE");
|
||||
}
|
||||
// CInputMain::Chat (input_main.cpp): the line comes back to the speaker (PacketAround includes them)
|
||||
// as a CHAT_TYPE_TALKING GC_CHAT "<name> : <text>" carrying their vid and empire.
|
||||
if (header == HDR_CG_CHAT)
|
||||
{
|
||||
CGChatHead head;
|
||||
std::memcpy(&head, packet, sizeof(head));
|
||||
const size_t text_len = size > sizeof(head) ? size - sizeof(head) : 0;
|
||||
const std::string text(reinterpret_cast<const char*>(packet + sizeof(head)),
|
||||
strnlen(reinterpret_cast<const char*>(packet + sizeof(head)), text_len));
|
||||
Event(name + ":chat " + std::to_string(head.type) + " " + text);
|
||||
const std::string line = std::string(kCharacterName) + " : " + text;
|
||||
GCChatHead chat = {HDR_GC_CHAT, static_cast<std::uint16_t>(sizeof(GCChatHead) + line.size() + 1),
|
||||
0 /* CHAT_TYPE_TALKING */, kMainVID, 1};
|
||||
if (!c.Send(chat) || !c.Send(line.c_str(), line.size() + 1))
|
||||
return Fail(name + ": send GC_CHAT");
|
||||
}
|
||||
if (header == HDR_CG_MOVE)
|
||||
{
|
||||
CGMove move;
|
||||
|
||||
@@ -244,9 +244,29 @@ int main(int argc, char** argv)
|
||||
char ports[128];
|
||||
std::snprintf(ports, sizeof(ports), "_auth_port, _game_port, _slot = %d, %d, %d", auth_port, game_port, slot);
|
||||
CHECK(py(ports));
|
||||
CHECK(py("_stream.SetConnectInfo(_host, _game_port, _host, _auth_port)\n"
|
||||
"_stream.curPhaseWindow.Connect(_login, _password)\n"
|
||||
"del __main__._login, __main__._password"));
|
||||
CHECK(py("_stream.SetConnectInfo(_host, _game_port, _host, _auth_port)"));
|
||||
// Typed into the login board through the 40250 IME (WM_CHAR -> CPythonIME::WMChar, WM_KEYDOWN ->
|
||||
// OnIMEKeyDown): Tab moves to the password line, Return runs __OnClickLoginButton -> Connect.
|
||||
// The IME only reaches a rendering EditLine: open the login board as the server list's OK button does.
|
||||
CHECK(py("_w = _stream.curPhaseWindow\n"
|
||||
"_w._LoginWindow__OpenLoginBoard()\n"
|
||||
"_w.idEditLine.SetText('')\n"
|
||||
"_w.pwdEditLine.SetText('')\n"
|
||||
"_w.idEditLine.SetFocus()"));
|
||||
auto type = [](const std::string& text) {
|
||||
for (unsigned char c : text)
|
||||
PythonBoot::UIChar(c);
|
||||
};
|
||||
type(login + "xy");
|
||||
PythonBoot::UIIMEKeyDown(VK_LEFT);
|
||||
PythonBoot::UIIMEKeyDown(VK_DELETE); // y
|
||||
PythonBoot::UIChar(VK_BACK); // x
|
||||
CHECK(py("assert _w.idEditLine.GetText() == _login, repr(_w.idEditLine.GetText())"));
|
||||
PythonBoot::UIChar(VK_TAB);
|
||||
type(password);
|
||||
CHECK(py("assert _w.pwdEditLine.GetText() == _password, len(_w.pwdEditLine.GetText())\n"
|
||||
"del __main__._login, __main__._password, __main__._w"));
|
||||
PythonBoot::UIChar(VK_RETURN);
|
||||
|
||||
// 3. The character list.
|
||||
const bool selecting = pump_until(live ? 30 : 20, [&] {
|
||||
@@ -614,6 +634,22 @@ int main(int argc, char** argv)
|
||||
// uiexchange.CloseDialog armed wndMgr.OnceIgnoreMouseLeftButtonUpEvent (in the client that release belongs
|
||||
// to the click that closed the dialog); spend it so step 8's click-release is not swallowed.
|
||||
PythonBoot::UIMouseButton(1, false, 400, 520);
|
||||
|
||||
// Chat (批次 4-a): Return on the focused game.GameWindow → OnIMEReturn → interface.ToggleChat opens the
|
||||
// chat line; the typed text goes through CPythonIME, a second Return sends CG_CHAT (TALKING) and the fake
|
||||
// server echoes GC_CHAT back.
|
||||
CHECK(py_true("not _stream.curPhaseWindow.interface.IsOpenChat()"));
|
||||
PythonBoot::UIChar(VK_RETURN);
|
||||
CHECK(pump_until(1, [] { return py_true("_stream.curPhaseWindow.interface.IsOpenChat()"); }));
|
||||
for (char c : std::string("hello"))
|
||||
PythonBoot::UIChar((unsigned char)c);
|
||||
pump_until(0.05, [] { return false; });
|
||||
PythonBoot::UIChar(VK_RETURN);
|
||||
CHECK(pump_until(2, [&] { return server->Has("game2:chat 0 hello"); }));
|
||||
// uichat.__SendTalkingChatPacket only resets the line; a Return on the empty line closes it (eventReturn).
|
||||
CHECK(py_true("_stream.curPhaseWindow.interface.IsOpenChat() and __import__('ime').GetText(0) == ''"));
|
||||
PythonBoot::UIChar(VK_RETURN);
|
||||
CHECK(pump_until(1, [] { return py_true("not _stream.curPhaseWindow.interface.IsOpenChat()"); }));
|
||||
}
|
||||
|
||||
// 8. (批次 2V3) Click-to-move: a left click on the ground below the actor reaches game.GameWindow's
|
||||
@@ -664,7 +700,7 @@ int main(int argc, char** argv)
|
||||
for (const auto& e : events)
|
||||
if (e.rfind(prefix, 0) == 0 && e.find(":move ") == std::string::npos &&
|
||||
e.find(":pickup ") == std::string::npos &&
|
||||
e.find(":exchange ") == std::string::npos)
|
||||
e.find(":exchange ") == std::string::npos && e.find(":chat ") == std::string::npos)
|
||||
got.push_back(e);
|
||||
CHECK(want == got);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user