Skip to content

modoptions: string 设置项直接给文本框 + 游戏内文本输入层(并修复键位配置界面被盖住) - #5

Open
std-external wants to merge 5 commits into
std-microblock:masterfrom
std-external:feat/string-text-input
Open

std-external wants to merge 5 commits into
std-microblock:masterfrom
std-external:feat/string-text-input

Conversation

@std-external

@std-external std-external commented Oct 19, 2026 •

Copy link
Copy Markdown

动机

群友反馈两件事,都落在模组设置页(MaterialModOptions):

  1. 字符串类型的设置项(截图里 MiaoNet 的名称 / 头衔 / 颜色 / 头像链接)在页面上只显示成一个通用「打开」按钮,值被塞在标题里,既不直观也没法直接在页面里改。希望像其它类型一样直接给一个文本框。
  2. 点「键盘配置 / 游戏手柄配置」后,Everest 的按键配置界面被模组设置页盖住:acrylic 合成会把整个 scene(含配置界面)画进模糊背景,设置页再画在最上层,导致配置界面几乎看不清也点不到。

改动

1. 可复用的游戏内文本输入层(新文件 Source/TextEntryOverlay.cs)

一个轻量版 OuiFileNaming / OuiModOptionString,键盘按手机输入法的 QWERTY 排版:

  • 全屏面板:标题、当前内容输入框(带光标、长度/上限、错误红框)、键盘、底部 取消 / 空格 / 退格 / 接受
  • 字母区三行 qwertyuiop / asdfghjkl / zxcvbnm(默认小写,左侧 shift 切大写),键帽右上角带数字/符号提示,和手机键盘一致
  • 字母页右下 123 / #+= 明确切到数字页 / 符号页;数字页有 ABC、#+=,符号页有 ABC、123(不再用单键循环)
  • 键帽角标(q 上面的 1、a 上面的 ~)只是照手机键盘做的视觉提示,不单独触发;真正切页靠上面两个键
  • 触屏 / 鼠标点按字符键立即输入并给按压高亮;长按空格键连续输入空格;手柄方向键导航 + 确认,焦点高亮跟随
  • 实体键盘直接输入(Enter 接受、Esc 取消)
  • 已有超长值不会被截断,上限只限制新输入的字符;取消不会回调、值不变

IMaterialAcrylicPage 新增 AllowsAcrylic:弹层打开时关闭 acrylic 合成,改走普通渲染,弹层才能画在最上面。

2. 按最近输入源分流(Source/MaterialModOptions.cs)

引擎里可直接用的信号(已核对 Monocle / Everest / CeleMod 源码):

  • MInput.ControllerHasFocus:MInput 每帧维护的「最近输入源」判据 —— 任意手柄 GamePads[i].HasAnyInput() 时为 true,键盘 Keyboard.HasAnyInput() 且没有手柄输入时清掉;只是想判断「有没有接手柄」不能只看 GamePads[i].Attached(接了没用也会是 true)。
  • Everest 的 CoreModuleSettings.UseKeyboardForTextInput(默认 true):vanilla 的 OuiFileNaming / OuiModOptionString 就是用它决定「物理键盘直输」还是「字符网格」;这里沿用同一个开关,关掉它会强制显示 QWERTY。
  • 键盘输入:TextInput.OnInput + TextInputEXT.TextEditing(IME 组字),和 vanilla 改名框同一条路径,直接编辑行内文本框。
  • 触屏软键盘:没有跨平台统一的「弹系统输入法」API;但本仓库的 Android 加载器 CeleMod 已经有现成入口 —— 发布 TouchKind: "text" 的触控目标后,DirectTouch.kt 会把它映射成键盘意图,GameActivity.kt 调 SDLActivity.showTextInput(0, 0, 1, 1) 拉起系统软键盘(返回键也能收起)。所以触屏不画自绘键盘。

因此实际行为:

  • 键鼠(桌面):点击或确认直接在行内编辑,走 SDL text input / 系统 IME,不弹 TextEntryOverlay
  • 触屏(Android/CeleMod):点文本框 → 系统软键盘;文字变更直接写回设置,不弹 QWERTY
  • 手柄:MInput.ControllerHasFocus 为 true 时进入 QWERTY 界面,方向键导航 + 确认
  • 兜底:UseKeyboardForTextInput == false 时,不管输入源都显示 QWERTY

鼠标/键盘触发时显式传入 allowGameKeyboard: false,避免「刚才用过手柄」把鼠标点击误判成手柄(鼠标移动本身不会清 ControllerHasFocus)。

3. 模组设置页支持 string 设置项(Source/MaterialModOptions.cs)

  • 字符串项改为行内文本框(当前值 / 「点击输入」占位 / 编辑图标);接受后写回属性并刷新按钮标题
  • 行内编辑会显示光标、IME 组字预览和错误红框;Esc 取消、Enter 接受、点外部提交(和 QolSettingsOverlay 的文本框一致)
  • 识别三类字符串入口:
    • Everest 自动生成的 string 设置(按 Everest 的命名规则反射回属性)
    • 手写菜单的 mod(例如 MiaoNet):通过 TextMenu.Button 的 Func<string> getter / Action<string> setter 闭包识别
    • 兜底:拦截 Overworld.Goto<OuiModOptionString>(),第一次按到的字符串按钮直接换成本输入层,之后也会显示为行内文本框
  • 最大/最小长度优先取 SettingMaxLength / SettingMinLength

4. 键位配置界面被盖住(MaterialModOptions + MaterialAcrylicRenderer + QolSettingsOverlay)

  • 检测 scene 里是否有 KeyboardConfigUI / ButtonConfigUI:有就关闭 acrylic、把设置页放到它们后面(Depth),并停止设置页自己的输入处理,让配置界面正常聚焦 / 改键
  • 弹层期间不发布设置页的触屏目标,避免摸到背后的隐藏行
  • QolSettingsOverlay 在打开键位配置时同样清空触屏目标(该页原本就会隐藏自己)

改了哪些文件

文件 说明
Source/TextEntryOverlay.cs 新增:可复用的游戏内文本输入层
Source/IMaterialAcrylicPage.cs 新增 AllowsAcrylic
Source/MaterialAcrylicRenderer.cs 弹层打开时跳过 acrylic 合成
Source/MaterialModOptions.cs string 行内文本框 / 系统输入接入、输入源分流、键位配置弹层修复
Source/MaterialChapterSelect.cs / Source/QolSettingsOverlay.cs 实现 AllowsAcrylic,后者清空弹层期间的触屏目标

验证

  • dotnet build Source/MicroblocksQolUtils.csproj:0 error / 0 warning(Everest stable lib-stripped)
  • dotnet run --project Tests/Capture/Capture.csproj:PASS(未涉及的部分回归)
  • 本机是 Linux,没法直接跑游戏实机截图;交互说明见上。请在 Windows 上按下面三步手工验证。

手工验证步骤

  1. 字符串项 / 输入源:主菜单 → Mod Options → 选一个带 string 设置的页(如 MiaoNet 或 Microblocks QOL 的「输出根目录」)。
    • 键鼠:点击文本框应直接出现光标并可用实体键盘/IME 输入,不应弹出全屏 QWERTY;Enter 提交、Esc 取消、点外部提交。
    • 触屏(Android):点文本框应拉起系统软键盘(CeleMod 的 text 目标),确认输入直接写回。
    • 手柄:用方向键选中后按确认应进入 QWERTY;123 / #+= / ABC 切页,shift 切大写,长按空格连打,退格删字,接受保存。
      回到列表确认值已更新,退出再进设置页确认已持久化;把内容删空后接受应提示无效(下限 1);超过上限后不再追加。
  2. 键位配置:Mod Options → Everest Core → 「键盘配置」/「游戏手柄配置」。确认弹出的配置界面完整可见、可聚焦、能改键;改一项后返回,设置页应恢复并且新键位生效(同一流程在游戏内暂停菜单的 Mod Options 里也试一次)。
  3. 回归:其它弹层(下拉、复合菜单、收藏/置顶、搜索框输入)以及普通按钮(如「试听音效」)行为不变;手柄和鼠标分别过一遍。

备注

  • 识别手写菜单的字符串按钮依赖按钮回调的闭包形状(Func<string> + Action<string>),如果某个 mod 写法特殊,会退回 Everest 原生字符串输入页,不会出错。
  • 手写菜单的最小/最大长度取不到属性,使用 1/128 作为宽松默认。

Render string settings as inline text fields in the material mod options
page and edit them through a reusable full-screen entry prompt (character
grid, cancel/space/backspace/accept) that works with gamepad, touch, mouse
and physical keyboards.

Also stop the acrylic composition and input handling from covering the
Everest key/button config screens opened from this page: disable acrylic
while they are open, place the page behind them and ignore input.
Reorder the prompt keyboard to qwertyuiop / asdfghjkl / zxcvbnm with
shift and a 123/symbol page cycle, matching a phone keyboard. Tapping a
key with mouse or touch now types immediately, the highlight follows the
pointer, and holding the space bar repeats spaces. Gamepad navigation and
Enter/Esc behaviour are unchanged.
Keyboard and mouse now edit string settings inline through SDL text input
(the same path as vanilla's rename box) instead of opening the self-drawn
keyboard; touch keeps using CeleMod's "text" touch target, which raises
the Android system soft keyboard. The QWERTY prompt is reserved for the
gamepad (MInput.ControllerHasFocus) or when Everest's
UseKeyboardForTextInput is off.

Replace the cycling page key with explicit 123 / #+= / ABC keys so the
number and symbol pages are discoverable; the corner hints on the letter
keys stay visual only, like a phone keyboard.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant