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:
shenlei
2026-09-24 08:35:53 +09:00
co-authored by Claude Opus 5.5
parent 1bda4390d6
commit 6ea0fa9889
21 changed files with 2117 additions and 277 deletions
+30
View File
@@ -20,6 +20,19 @@ const KEY_TO_DIK := {
KEY_RIGHT: 0xcd, KEY_DOWN: 0xd0,
}
# Win32 virtual-key codes of the keys EditLine.OnIMEKeyDown handles (WM_KEYDOWN → OnIMEKeyDown);
# letters and digits use their ASCII code, as VK_A..VK_Z / VK_0..VK_9 do.
const KEY_TO_VK := {
KEY_BACKSPACE: 0x08, KEY_TAB: 0x09, KEY_ENTER: 0x0d, KEY_KP_ENTER: 0x0d,
KEY_ESCAPE: 0x1b, KEY_SPACE: 0x20, KEY_END: 0x23, KEY_HOME: 0x24,
KEY_LEFT: 0x25, KEY_UP: 0x26, KEY_RIGHT: 0x27, KEY_DOWN: 0x28, KEY_DELETE: 0x2e,
}
# The control characters Windows turns these keys into (WM_CHAR); Godot reports them with unicode 0.
const KEY_TO_CHAR := {
KEY_BACKSPACE: 0x08, KEY_TAB: 0x09, KEY_ENTER: 0x0d, KEY_KP_ENTER: 0x0d, KEY_ESCAPE: 0x1b,
}
# "mem:<id>" → [revision, ImageTexture]: the CGraphicFontTexture glyph pages, refetched when the
# "@<revision>" of a command's name moves on (a glyph was added to the page).
var _memory_textures := {}
@@ -98,6 +111,23 @@ func _unhandled_key_input(event: InputEvent) -> void:
var dik: int = KEY_TO_DIK.get(event.physical_keycode, 0)
if dik != 0:
Metin2PythonHost.ui_key(dik, event.pressed)
if event.pressed:
_ime_key(event)
# 40250 gets every key press twice more through the window procedure: WM_KEYDOWN (a VK code, for
# OnIMEKeyDown) and then WM_CHAR (the typed character, for CPythonIME). Held keys repeat both.
func _ime_key(event: InputEventKey) -> void:
var keycode: int = event.keycode
var vk: int = KEY_TO_VK.get(keycode, 0)
if vk == 0 and ((keycode >= KEY_A and keycode <= KEY_Z) or (keycode >= KEY_0 and keycode <= KEY_9)):
vk = keycode
if vk != 0:
Metin2PythonHost.ui_ime_key(vk)
var ch: int = event.unicode
if ch == 0:
ch = KEY_TO_CHAR.get(keycode, 0)
if ch != 0:
Metin2PythonHost.ui_char(ch)
# The command stream is drawn into pooled child canvas items in order: a run of plain commands
# shares one item; a masked image (CPythonMiniMap's terrain tiles under minimap_image_filter.dds)