输入分发与模块依赖
isRequire.lua 在启动时返回 app 表,包含根场景、快捷键管理、事件总栈、按键状态、鼠标状态、窗口信息、路径和 UI 工厂。main.lua 从该表取得它需要的引用。旧场景模块仍通过 _G 兼容别名互相发现,后续迁移时应优先在模块顶部用 require(...) 取局部依赖,再逐步撤掉启动别名。
src.utils.input 的 require 只定义快捷键功能,不读写文件。启动时调用 input:init(options) 并传入文件系统、JSON、默认键位、文件路径和两份按键状态。快捷键匹配只读 keyboard;文本框和侧栏等 UI 读 uiKeyboard。新增模块应通过构造参数或 init 取得依赖,避免模块加载时读取应用全局变量。
src.services.inputRouter 按一次输入事件的生命周期统一处理 Nuklear、弹窗和当前场景:先更新原生按键状态,UI 消费的按键不会触发编辑快捷键;鼠标按下时记录事件归属,释放事件回到同一归属;焦点离开会清空按键并结束拖动;所有鼠标位置由 CoordinateService:screenToGame 统一换算。场景需要优先处理特殊命中区域时实现 inputBeforeUI。UI 已消费滚轮但某页面有专属补偿逻辑时,实现 uiWheelmoved,不要把滚轮重新广播给全部场景。
新增原生输入事件时,在 main.lua 的事件名列表中注册路由。扩展输入归属、快捷键状态或焦点行为时,维护 tests/input_router.lua 的纯 Lua 回归用例。
Nuklear 的透明窗口也会消费其覆盖范围内的鼠标和滚轮。demo/edit 内容、标签条底板与拖动条边框由 tabs:draw() 直接绘制,不为它们创建没有控件的整块 UI 窗口。真正的标签按钮、信息面板和侧栏继续使用 Nuklear,保持输入归属隔离。事件直观编辑的上下文菜单使用屏幕外的小窗口作为宿主,触发区域仍为 demo;菜单关闭时不会覆盖谱面输入。love tests/editor_input_love 验证真实 UI 下的谱面进度条拖拽、区域外松开、单页/多标签页时间滚轮、侧栏滚轮不移动谱面,以及事件直观编辑模式的右键菜单。