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
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user