Skip to content

长截图自动滚动(阶段 2);设置拆出录屏标签;滚回开头也能接上 - #25

Merged
Cocoon-break merged 24 commits into
mainfrom
feat/long-shot-autoscroll
Nov 2, 2026
Merged

Cocoon-break merged 24 commits into
mainfrom
feat/long-shot-autoscroll

Conversation

@Cocoon-break

Copy link
Copy Markdown
Owner

改了什么

长截图自动滚动(M23 规则 13,规格 v0.1.43–v0.1.46,设计见 docs/specs/2026-11-01-长截图自动滚动-设计.md)

  • 设置“截图”标签新增“自动滚动”,默认关。关着时按 L 手动滚,按空格开始这一次的自动滚动。开着时按 L 直接自动滚动。
  • 自动滚动只发滚动事件,不发按键或点击,也不移动指针。滚动节奏和比例在过程中学习。拼接时按预期位移先在附近找位置。
  • 自动滚动中:用户自己滚动或点击会让它停下,停手 1 秒后继续。空格暂停或继续。滚到底时自动完成。窗口不响应时转为手动。几次接不上时暂停,按空格重试。
  • 平台层:
    • macOS 用私有事件源发滚动事件,用 HID 状态判断用户输入,需要辅助功能权限。
    • Windows 用 SendInput 加标记发事件,用低层钩子判断用户输入。
  • 按回车完成后,立即显示“正在生成长图…”提示。

拼接

  • 最后 4 屏里找不到位置时,再在整张长图里找,滚回长图开头也能接上。这次搜索排在近似比对之后。

设置

  • 标签改为:通用 / 记录 / 搜索 / 截图 / 录屏(仅 macOS)/ 翻译。“截图”标签分为“截图”“长截图”两组。

验证

  • make check 通过:fmt、clippy(含 Windows 交叉)、版本号、Rust 与前端测试、前端构建。
  • macOS 真机(Chrome、带背景图的终端),结果记在 docs/验收记录.md“长截图自动滚动”的真机结果里:
    • 自动滚动到底:52 步,没接上 0 帧。
    • 滚回开头后重新接上。
    • 手动模式、生成中提示、设置两个标签都正常。
  • 没验证的部分:
    • Windows 只经过交叉 clippy,没有在实机上跑过。
    • 其余“待验收”项这次没做,用户决定先发 0.5.2。
  • 已知限制新增两条:
    • 滚到截图起点上方时报没接上,哪怕只高出几行。
    • 一格滚动的行数不固定的终端界面(如 Claude Code)自动滚动会转为手动。

🤖 Generated with Claude Code

Cocoon-break and others added 24 commits November 1, 2026 22:13
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Stitch::position():最近一次定位到的帧第 0 行在长图里的行号
- Stitch::push_near(cur, near):先只在 near ± max(4, 选区高度 / 20) 行内按原规则找(精确比对明显胜出、
  近似比对只有一个像样的位置),找不到再按全范围找;push(cur) 即 push_near(cur, None)
- 近似比对在预期附近逐个位移核对、次好取离最好 3 行以外的,免得窄范围里隔 3 行挑位置时把“像”的位置挡掉而接错

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
每行完全一样时不给预期报没接上;给对预期在附近唯一对上,结果与一次截下相同。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 预期附近的范围有一部分超出能核对的范围(重叠不够或为负)时跳过这一档,不再截短后找:剩下部分里错开一个周期的位置会不经比较就胜出
- 查找顺序改为:附近精确 → 全范围精确 → 附近近似 → 全范围近似
- 测试换成真实的“像”的位置落在范围内的场景

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- macOS:scroll_at 用私有事件源建像素单位的滚轮事件,带 kCGEventSourceUserData 标记与位置,发到会话;
  InputWatch::age 查 HID 系统状态里滚轮、按键、鼠标按下距今的最小值(移动指针不算);
  pointer_position 取 CGEventCreate(NULL) 的位置;can_auto_scroll 即辅助功能权限。
  全部走 objc2-core-graphics 的安全封装(新开 CGEventSource 特性),没有新的 unsafe。
- PlatformError 加 Input 变体,消息只含错误说明。
- Windows:同名桩(scroll_at 返回 Unsupported、age 为 None、can_auto_scroll 为假),留给下一步实现。
- tests/scroll.rs:只读查询的冒烟测试;scroll_at_moves_content 标 #[ignore],会发真实滚动,本次没有运行。

待真机验收确认:私有源发到会话的滚动不计入 HID 系统状态(age 不变小);滚动方向(正数露出下面);
SCROLL_FOLLOWS_POINTER 暂按 false,若带位置的滚动仍只作用于指针下的窗口则改为 true。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- scroll_at:SendInput 发 MOUSEEVENTF_WHEEL,增量取反(WHEEL_DELTA 为正是往上),dwExtraInfo 带 SCROLL_MARK;
  不移动指针,作用于指针下的窗口(SCROLL_FOLLOWS_POINTER = true);只发出 0 个事件时报 Input 错误。
- InputWatch:专用线程装 WH_MOUSE_LL、WH_KEYBOARD_LL 并跑消息循环,滚轮(竖、横)、按键按下、鼠标按下
  记下时刻;带本进程标记或被标为注入的不算,移动不算。每个 InputWatch 各有线程与时刻;Drop 投递 WM_QUIT,
  等线程卸钩退出最多 500 ms,超时放手并记日志。
- pointer_position 用 GetCursorPos(物理像素,进程为 PMv2);can_auto_scroll 恒为真。
- 判定规则抽成 winfmt::is_user_input,全平台可测。
- tests/scroll.rs 也在 Windows 上编译与运行;scroll_at_moves_content 仍是 #[ignore],待用户在 Windows 11 实机跑。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 低层钩子线程装钩前提到 THREAD_PRIORITY_HIGHEST:回调屡次超时会被系统悄悄摘掉,拼接吃满 CPU 时也要及时响应。
- tests/scroll.rs:CI 里取不到指针位置时跳过而不失败;Windows 上测试先设 Per-Monitor-v2,坐标为物理像素。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
有辅助功能权限(Windows 不需要)时在选区中心发滚动事件,画面停下(距最近一次变化 120 ms,发出后一直没变则 300 ms)
再把位移报给节奏、发下一步;比例测出后把预期位移交给拼接。到底同回车完成;从没动过或发送失败转手动并提示不响应;
连续恢复不了暂停并提示。用户 1 秒内滚动、按键或点击时让出并丢掉在途的一步,停手后从头起步;自己的快捷键
(含开始时按的 L)300 ms 内的输入不算接手。空格临时注册为全局快捷键,切换暂停与继续;滚动跟着指针走的平台上
指针移出选区时等它回来。边框页加上新状态的文案,完成日志附自动滚动步数、比例与结束方式。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stitch 加 located():最近一次与上一帧不同的帧定位到了没有。自动滚动停下时按它报位移,一帧短暂没接上、
随后回到原位不再被当成没接上;发出时没定位到的一步不给预期、报没接上。画面一直在变(视频、轮播)时
发出 1 秒后也算停下,节奏才能判断恢复不了。到上限时也把空格还给应用;暂停时按原来的间隔取帧;
比例没测出时日志记“-”;用户接手时显示拼接自己的没接上提示。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 往回滚的恢复步停下时定位到就算恢复成功(发出时没定位到也算),报给节奏的位移抽成 `report` 并加测试
- 等帧期间按了回车或 Esc 不再多发一步滚动
- 第一次测偏的比例:连续两个偏离且彼此相符的样本取平均纠正
- macOS 滚动事件源的本地事件抑制间隔设为 0,指针不卡顿;手动测试断言发滚动不移动指针
- 自动滚动一直接不上改为 `autostuck`,提示带“空格重试”;用户接手期间按手动滚显示提示
- 规格说明、设计第 8 节、设备支持同步;移回错位的测试注释

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 设置“长截图自动滚动”(截图标签,默认关):开着按 L 直接自动滚;关着手动滚,
  有权限时提示“滚动选区里的内容 · 空格自动滚动”,按空格开始这一次的自动滚动
- 能自动滚动时手动滚也注册空格;到上限后不能再开始并注销空格
- 边框淡出后提示条立即显示“正在生成长图…”(转圈、不自动收起,减少动态效果时静止),
  编码、写剪切板后换成结果;Esc 取消不显示
- 选区旁提示提成纯函数 longTip 并补测试

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
验收时开发构建按回车后要等几百帧写盘(约 1.5 分钟)才出结果,和正式版的体验差太多;
release 不存图,不受影响。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 录屏几项移到新的“录屏”标签(标签与面板带 os-mac),控件 id 不变
- ← / → / Home / End 跳过隐藏的标签(shownTabTarget)
- 分组沿用翻译标签的小标题样式,tr-group 改名 st-group;组内开关列表不与组分隔线叠成两道
- “长截图自动滚动”开关改名为“长截图”一组里的“自动滚动”

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
验收反馈:往下滚远了没接上,滚回长图开头、按空格自动滚动仍一直没接上。存图重放确认第 300 帧与第 0 帧相同,
但精确比对只在最后 4 屏里找,长图已约 11 屏。现在先在最后 4 屏里找,找不到再在整张长图里找,判定规则不变;
近似比对不变。重放这次存图:没接上 200 → 132 帧,第 300 帧起全部定位到。重放例子另打印平均耗时。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
审查意见:整张长图的精确比对排在近似比对之前,只能近似接上的内容(背景图不动的终端)每帧都要先白扫一遍整张长图。
分层顺序改为:预期附近精确 → 最后 4 屏精确 → 预期附近近似 → 全范围近似 → 整张长图精确(先预期附近、再不限)。
终端存图里扫整张长图的帧从 146 降到 22;滚回开头的存图逐帧定位结果与改前相同。新增测试
whole_image_search_never_misjoins_repetitive_lines:拼过 4 屏的重复内容,滚回很远、甩过末尾都不接进内容。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Cocoon-break
Cocoon-break merged commit ee43ad5 into main Nov 2, 2026
2 checks passed
@Cocoon-break
Cocoon-break deleted the feat/long-shot-autoscroll branch November 2, 2026 03:22
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