6.9 KiB
6.9 KiB
2026-10-23
按键精灵 v2:全 C# 重做(Lua + 积木 + 录制 + 录屏)
用户反馈 v1(自定义 VB-like 脚本 + TreeView 假积木)未达预期,明确要求「整个项目用 C」—— 即纯 C# 技术栈,不要网页方案。中途一度做了 WebView2 + Blockly,被要求停止并移除。
架构决策
- 脚本引擎:MoonSharp 2.0.0(纯托管,.NET 10 可用),替换自研 ScriptParser/ScriptEngine。
- 积木:
Forms/BlockCanvas.cs自绘 GDI+ 画布,圆角块、拖拽排序、容器嵌套、插入指示线、右键菜单。 - 录制:
Capture/InputRecorder.csWH_KEYBOARD_LL/WH_MOUSE_LL → 智能聚合成 Lua。 - 录屏:
Capture/ScreenRecorder.csGDI 抓帧 + JPEG + 手写 AVI(MJPG) 封装,无 ffmpeg 依赖。 - 删除旧
Scripting/目录(ScriptParser/ScriptEngine/Blocks/AutomationTask)与Forms/BlockDesigner.cs。
关键实现坑
- MoonSharp
Table["name"] = Delegate可直接赋值;CLR 回调抛异常会原样透传给DoString,pcall拦不住 → 用作 Abort 信号。 CoreModules枚举成员是String/Table/Math(不是 StrLib/TableLib)。- WinForms
UserControl.Text会遮蔽自定义属性;LuaEditor改用Script属性。 SplitContainer构造期设SplitterDistance会因宽度未定抛异常,改在Layout里初始化。- 积木模板里参数不要再手写引号(ArgKind 已负责加引号),否则
keyPress(""A"")。 - IDE 规则:
MainForm实现 ILuaHost 时与Control同名方法必须显式接口实现。
验收
dotnet build0 错误。- 积木→Lua 生成、Lua 执行、语法错误中文提示、录屏 AVI 结构、主窗体 5 页渲染均已实测通过。
v2.1 界面重构:四区布局(左任务列表 / 中详情 / 右插件 / 下日志)
用户要求按经典按键精灵布局重排,不要一堆平级标签页。
结构
- 左 248px:
ListBox+OwnerDrawFixed自绘任务卡(名称 + 循环/间隔 + 状态色条),右键新建/复制/删除/上下移/立即运行。 - 中:顶部任务属性条(名称/启用/无限/次数/间隔/来源/热键,改动实时回写) +
TabControl四页(脚本代码 / 积木编程 / 录制·录屏 / 内嵌浏览器)。 - 右 224px:插件面板
FlowLayoutPanel,17 项分 4 组(屏幕与定位 / 录制 / 脚本 / 系统与帮助),按钮宽 176 才不触发横向滚动条。 - 下:RichTextBox 日志跨全宽,错误红/成功绿,分割条可拖。
- 嵌套
SplitContainer×3,均在Layout事件里一次性设SplitterDistance。
新增
Forms/PickerForm.cs:置顶坐标取色器,15×15 抓屏 7 倍 NearestNeighbor 放大 + 准星,实时坐标/HEX/RGB,复制坐标/颜色/写日志。LuaTask增加Blocks(积木 JSON)与Hotkey字段,任务切换时脚本与积木各自恢复。- 插件:找图测试(全屏 MatchTemplate + 耗时/相似度)、窗口列表、打开图库/录像目录。
坑
ListBox.DataSource = BindingList<T>在句柄创建前绑定,Items.Count恒为 0 → 改为手工Items.Clear/Add同步 +_sync标志防重入。Label.AutoSize=true在FlowLayoutPanel里会被压到 100px 宽截断文字 → 改AutoSize=false+ 固定宽 +AutoEllipsis。Form.MainMenuStrip会把菜单塞到 Controls[0](最内层),工具栏Dock=Top会压到菜单上方 → 末尾Controls.SetChildIndex(menu, Count-1)强制菜单最外。
v2.2 积木插片耦合造型 + 功能补位
用户反馈:积木要"插片耦合"样式(可理解)、各功能位置没做好。
BlockCanvas 重写(Forms/BlockCanvas.cs)
- 几何:RowH=30 / NotchH=7 / WallW=22 / FootH=16 / ElseH=22;
TopEdge/BottomEdge/PuzzlePath/ContainerPath生成路径。 - 语句块 = 顶部凹槽 + 底部凸榫;相邻块 y 累加 RowH(无间隙)→ 凸榫嵌进凹槽,视觉咬合。
- 容器 = C 形路径(头 + 左壁 + 内腔 + 封口),内腔画浅色插槽底;空容器注册 Slot 行显示"把积木拖到这里"。
- 否则 = 内腔横向分隔条(整宽、块色加深)。
- 参数值 = 白色圆角插槽(SplitTitle 把 Title 按 {i} 拆段交替绘制固定文字/参数槽)。
- 命中用 _rows 倒序;End 行 Owner=末尾列表;Slot 行 Owner=空列表 → 拖入空容器可用。
坐标 bug(重要)
容器子块起点原为 innerTop+NotchH,而 InnerHeight 不含该偏移 → 子块总高比内腔多 7px,最后一块盖住底部封口。修复:子块从 innerTop 开始,elseY 同步去掉偏移。
主窗体补位
- 任务绑定启动热键:属性条 ComboBox(无/F1~F7)→ RebindTaskHotkeys() 注册 HK_TASK_BASE=200 起的动态 id,WndProc 派发 RunTaskByHotkey。
- 任务列表右侧画启用勾选框,点击直接切换(e.Y % 48 >= 16 判定行内区域)。
- 插件分组标题带类别色(▍ 前缀)。
- 积木页命令库 198 / 参数 230,画布 ~450px。
- 坑:构建时 exe 被残留进程锁定 → 先 taskkill 再 build。
v2.3 脚本⇄积木双向转换 + 显示修复
用户反馈:截图圈了三处——属性条按钮被截、积木顶部被截、脚本和积木不该是两份代码。
双向转换(核心)
- 单一数据源 = task.Script。BlockCatalog.FromLua()(LuaBlocks.cs):行解析器,支持 for/while/if/elseif(嵌套进 else)/else/end、ifExists(do+local __ix 三行结构还原)、varSet/varAdd、目录模板匹配(TplCache:按函数名+返回值数+参数占位符构建,顶层逗号 SplitArgs 尊重引号括号)、认不出→ Key="lua" 自定义代码块(Template="{0}" Raw)。
- ToLua 去掉了日期头注释,否则往返不稳定。
- MainForm:_converting 互斥标志;切积木页 SelectedIndexChanged→SyncScriptToBlocks;_canvas.Changed→回写 _editor.Script;参数面板 TextBox/Combo 改动→_canvas.NotifyChanged()(新增公开方法,原 Changed 只在结构变化时发,改参数不触发是坑);LoadTaskDetail 旧数据迁移(只有 Blocks 无 Script 时转脚本);OpenBlocks 载入后同步转脚本。
显示修复
- 详情属性条 head 78→88、row2 28→34(按钮曾被截半)。
- 积木页工具条 WrapContents=true、Height=74(8 个按钮一行放不下)。
- BlockCanvas.LoadBlocks 加 AutoScrollPosition 归零(旧滚动位置把首块顶出视野)。
- 插件栏 224→234、按钮/分组标题 176→186。
- 坑:用户开着旧 exe 锁文件,taskkill 后再 build。
v2.3 追修
- 用户再报:按钮底部仍被页签盖住 → head 88→96、row2 34→42 / Padding(2,2,0,0),按钮 28+m3 在 30 容器里溢出是根因。
- 用户报"没互相转换"→ LoadTaskDetail 改为任务载入后无条件 SyncScriptToBlocks()(原来只靠 SelectedIndexChanged,且启动首载时画布为空)。实测三流程全通:启动切积木页 18 块、改参数回写 delay(999)、脚本加行切页出现 TAB 块。