Files
mtgodot-poc/audit/contracts/ui.input-camera-mobile.md
T
shenandshen c93894313a fix: 装备属性面板避让逻辑 + 多项功能更新
- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧
- inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域
- 包含其他累积的功能开发和测试文件
2026-09-21 16:38:59 -07:00

12 KiB
Raw Blame History

ui.input_camera_mobile —— 鼠标、相机、光标、IME、触屏和移动端窗口

状态:PARTIAL

本合同检查 40250 的输入优先级、键盘状态、鼠标按钮映射、智能拾取、相机连续控制、事件相机、光标状态、IME 生命周期,以及当前端的触屏/移动端适配。判断标准是状态机、调用顺序、拒绝条件、清理副作用和可观察结果一致;“有一个可用的 Godot 控件”不能单独视为与 40250 等价。

40250 参考调用链

  • UserInterface/PythonPlayerInputKeyboard.cpp
    • NEW_SetSingleDIKKeyState 先取消钓鱼,再处理方向键;NEW_SetSingleDirKeyState 更新方向按键状态并立即进入多方向计算。
    • NEW_SetMultiDirKeyState__CanMove 允许时按 WASD/方向键组合计算唯一旋转角,支持精确的四方向和四个对角方向;无方向时调用 NEW_Stop
    • 攻击键在钓鱼状态下走钓鱼分支,否则更新攻击状态。
  • UserInterface/PythonPlayerInputMouse.cpp
    • 移动、智能、相机、自动攻击、普通攻击和技能按钮由统一的 NEW_SetMouseState 分派。
    • 智能点击优先级为物品→角色→地面,并受私店、表情、眩晕等状态门控;相机按下进入拖拽,点击结束拖拽或选中目标并打开角色菜单。
    • 中键相机、Ctrl 行为、技能按钮和拾取/地面射线均有独立状态清理。
  • UserInterface/PythonApplicationCamera.cpp
    • 普通、站立、混合三类相机状态按帧更新;事件相机保存默认相机,混合期间锁定直接控制,结束后恢复普通相机。
    • 相机旋转、俯仰和缩放使用连续速度;缩放按 1.0 + zoomSpeed * direction 的比例更新,而不是固定距离步进。
  • UserInterface/PythonApplicationCursor.cpp / EterLib/Input.cpp
    • 光标有连续光标状态、硬件光标显隐和相机旋转等光标形状;DirectInput 键盘维护 256 字节状态并支持重新获取。
  • UserInterface/PythonIME.cpp
    • 文本输入显式处理左右/Home/End/删除、Tab/Return/Escape、字符输入、候选窗口和输入法状态回调。

当前端实现映射

  • project/player_controller.gd / project/game_scene.gd
    • 已实现桌面 WASD/方向键状态、按键释放清理、地面/物品/角色点击优先级,以及触屏点击与拖拽分离;移动端摇杆复用同一移动入口。
    • 当前按键分为 _input 处理释放、_unhandled_input 处理按下,和 40250 的统一即时输入回调不是同一时序;角色碰撞/拾取也由 Godot 射线和简化碰撞半径适配。
  • project/game_camera.gd
    • 已有桌面右键拖拽、滚轮缩放、触屏单指旋转、双指缩放、Q/E/R/F/T/G 连续控制、普通/站立/混合事件相机、地形遮挡和镜头震动。
    • 当前默认距离/俯仰角、固定缩放步进、相机目标高度和事件相机锁定/恢复语义没有与 CCamera 的常量和比例缩放逐项统一。
  • project/ui/mouse_controller.gd / project/ui/cursor_manager.gd
    • 已实现物品/技能/表情拖拽、右键/ESC/失焦取消,以及 .sub 光标资源加载和 Godot 光标映射。
    • 没有完整复刻 NEW_SetMouseState 的所有按钮分派;没有显式连续光标编号状态、硬件光标显隐封装和相机拖拽时隐藏硬件光标的等价链路。
  • project/ui/mobile/*
    • 已有安全区、横屏布局、虚拟摇杆、触屏按钮、长按技能瞄准、菜单返回和窗口焦点/暂停时触摸清理;这是移动平台适配层,不是 40250 Windows 输入实现本身。
  • Godot LineEdit/聊天 UI
    • 当前依赖引擎默认文本输入,没有独立的 PythonIME 等价封装来记录光标移动、删除、候选窗口、编码页和输入法回调。

分支等价矩阵

40250 判据/副作用 当前实现 结论
WASD/方向键组合、对角角度、无键停止和按键释放清理 _wasd 优先级、归一化、角色朝向和焦点清理已实现,输入按下/释放分属不同 Godot 阶段 部分等价;基础行为通过,时序和全部 __CanMove/钓鱼门控未形成同链证据
鼠标 MOVE/SMART/CAMERA/AUTO/ATTACK/SKILL 统一分派 物品、角色、地面点击和相机拖拽分别分布在 PlayerController/GameCamera/Quickbar 部分等价;完整按钮映射、Ctrl/中键/角色菜单和拒绝分支未统一证明
智能点击物品→角色→地面及状态门控 当前 ground item→实体→地面顺序存在,触摸仲裁也存在 部分等价;私店、表情、眩晕、可拾取资格和 native 射线语义仍为适配近似
普通相机按帧跟随、旋转/俯仰/比例缩放 当前有跟随、拖拽、滚轮和连续键控制 不等价;缩放为固定距离步进,默认值/目标高度/连续速度尚未与参考公式统一;game_camera_test 3 项失败
事件相机保存、混合、锁定和恢复 有 NORMAL/STAND/BLEND 与字典插值/恢复 部分等价;缺少完整 CameraManager 状态锁、roll/视线/交叉线和异常中断清理证据
连续光标、相机旋转光标、硬件光标显隐 有资源加载和形状映射 部分等价;没有连续光标状态,拖拽期间未证明隐藏硬件光标,运行时自定义光标形状映射也不完整
IME 光标/删除/候选/字符回调 依赖 Godot LineEdit GAP;没有可审计的独立等价实现和回调测试
触屏、摇杆、双指缩放、移动窗口和安全区 mobile UI/gesture/window 测试通过 平台适配通过;不应误标为 Windows 40250 输入链等价
失焦、暂停、重连、退出时输入状态清理 PlayerController、MouseController、MobileOverlay 分别清理 部分等价;缺少 GameScene 统一清理和相机/鼠标/IME 组合状态的生产级测试

已执行测试

  • project/mouse_controller_test.gd:通过;覆盖全局物品拖拽状态和取消。
  • project/input_key_test.gd:通过;覆盖 ClientVS22 桌面按键映射、Alt、快捷栏和模态 UI;进程有 20 个 ObjectDB 和 1 个 Camera RID 泄漏警告。
  • project/mobile_gesture_test.gd:通过;覆盖长按、技能瞄准、快捷栏切换和物品触摸拖拽。
  • project/mobile_ui_test.gd:通过;覆盖平台配置、横屏 HUD、菜单和控件。
  • project/mobile_window_host_test.gd:通过;覆盖安全区、触摸桥和模态返回。
  • project/game_camera_test.gd:失败 3 项:期望的默认距离 1550cm、默认俯仰角 27° 和 RESTORE_CAMERA 恢复保存普通视图均未满足;因此相机不能标记为等价。

上述三项是修复前的基线失败,已在本轮修正;后续结果见本合同末尾的实现修复记录。

Deep audit round 2026-09-21

Fresh regression results (修复前基线)

  • mouse_controller_test.gdmobile_gesture_test.gdmobile_ui_test.gdmobile_window_host_test.gd 均退出码 0;覆盖拖放取消、长按/技能瞄准、横屏控件、安全区、触摸桥和模态返回。
  • input_key_test.gd 断言通过,但有 20 个 ObjectDB 和 1 个 Camera RID 泄漏。
  • game_camera_test.gd 仍失败 3 项:默认距离 1550cm、默认俯仰 27°、RESTORE_CAMERA 恢复保存普通视图。

Static parity conclusion (修复前基线)

  • WASD/触屏和基础鼠标拖放路径可运行,但输入按下/释放分散在不同 Godot 阶段,尚未形成 40250 NEW_SetSingleDIKKeyState/统一鼠标状态分派的同一时序。
  • 相机缩放、默认常量和恢复快照仍与参考不一致;事件相机的异常中断、相机/鼠标/IME 组合清理没有生产级证据。
  • IME 仍依赖 Godot LineEdit,没有可审计的候选窗口、字符/删除/Home/End/Return/Escape 回调链;移动端测试通过不等于 Windows 40250 输入链一致。

修复前本轮仍为 PARTIAL;随后已针对相机默认值、缩放和目标高度完成实现修复,整体合同仍保持 PARTIAL

Active EterLib core review

  • EterLib/Camera.cppCCamera 维护普通/事件相机状态、Begin/EndDrag/Drag、滚轮和按比例 Zoom(float ratio);相机管理器还负责当前相机、事件相机和恢复路径。当前 game_camera.gd 虽有同名交互入口,但使用固定距离步进,默认距离/俯仰和恢复快照已有 3 项测试失败,不能视为公式或状态机一致。
  • EterLib/IME.cpp 不只是文本框包装:它维护输入法启停、键盘捕获、组合字符串、候选/reading 窗口、code page、TSF 回调和字符串编辑。当前依赖 Godot LineEdit,没有对应的候选窗口、组合提交、编码页和回调生命周期;这是 Windows 输入链的明确缺口。
  • 因此本轮确认 Camera.cpp/.hIME.cpp/.hInput.hmsctf.h 已完成活跃源码静态核对,但实现仍为 PARTIAL,静态核对不等于运行时一致。

已确认差异和未验证项

  1. 已统一参考端与当前端的相机默认常量、单位、比例缩放、滚轮阻尼、连续控制速度、相机目标高度和恢复快照;game_camera_test.gd 的修复前 3 项失败已通过。
  2. 建立鼠标按钮分派矩阵,覆盖 MOVE/SMART/CAMERA/AUTO/ATTACK/SKILL、Ctrl、中键、技能/物品/角色/地面优先级和每个拒绝分支。
  3. 增加硬件光标显隐、连续光标、相机拖拽结束、失焦、暂停和异常退出的组合测试。
  4. 为聊天/输入框补充 IME 适配合同:光标移动、Home/End、删除、Return/Escape、候选窗口和字符回调;不能以 LineEdit 存在代替功能等价。
  5. 增加生产 GameScene 级输入清理测试,确认切图、断线、重连、窗口失焦和移动端触摸取消后没有粘滞按键、相机拖拽或拖放状态。

下一轮验证入口

  • 先定位 game_camera.gd 默认值和 RESTORE_CAMERA 失败的具体断言,按 40250 的 Camera 状态快照建立边界测试。
  • 再审计 audio.bgm_ambience_3d,核对 BGM、区域环境音、角色音效、3D 监听器和前后台恢复调用链。

Active UserInterface IME bridge review

  • PythonIME.h/PythonIMEModule.cpp 是 Windows IME 的完整桥:光标左右/Home/End/删除/设置位置、Create/Destroy、Tab/Return/Escape、WM_CHAR、候选/reading 更新、codepage 和输入模式都通过 CPythonIME/EterLib::IME 暴露给 Python。
  • 当前端 LineEdit 能完成基本 UTF-8 文本输入,但没有证明多字节 codepage、候选窗口、reading string、组合态删除、焦点切换和系统 IME 回调的状态顺序一致;因此不能把普通键盘 smoke test 视为 IME 等价。

Static review evidence

已将 PythonIME.hPythonIMEModule.cpp 纳入 active source 证据;相机/输入合同仍为 PARTIAL,需补真实输入法和失焦/取消清理测试。

Implementation fix round 2026-09-21

Reference chain

  • source/UserInterface/CameraProcedure.cpp::CCamera::Update:距离边界为 200/2500cm,滚轮速度按帧应用并以 0.5 阻尼,目标高度按距离从 100cm 插值到 150cm。
  • source/UserInterface/PythonApplication.cpp:默认相机缩放速度为 0.05
  • source/UserInterface/PythonApplicationCamera.cppZoomCamera 使用 1.0 + speed * direction 的比例缩放。
  • source/EterLib/Camera.cpp::CCamera::WheelWin32 滚轮量按 0.3 resistance 转换为距离速度。

Current implementation

  • project/game_camera.gd 已将默认值固定为 1550cm/27°,加入 200/2500cm 对应的目标高度插值、0.05 比例键盘缩放、36cm/刻度的滚轮速度和 0.5 阻尼;事件相机锁定时不消费普通缩放输入。
  • project/game_camera_test.gd 已覆盖默认值、RESTORE_CAMERA、目标高度的最小/最大距离边界、滚轮缩放阻尼和键盘 0.05 比例。

Verification

  • game_camera_test.gd:通过;默认值、事件相机恢复、动态目标高度、滚轮阻尼和比例缩放均通过。
  • input_key_test.gdmobile_gesture_test.gdmobile_ui_test.gdmobile_window_host_test.gd:通过;input_key_test.gd 仍报告既有的 20 个 ObjectDB 与 1 个 Camera RID 泄漏警告。

该修复只闭合了相机默认值和缩放/目标高度的已确认差异;IME、完整鼠标按钮分派、硬件/连续光标和异常清理仍保持 PARTIAL,不能据此宣称输入系统整体等价。