Releases: ExpertKT/SnapWheel
Release list
v0.9.5 — 引导整理:那个【新】标记一直是假的
把「引导性质的东西」整个盘了一遍
起因是一个具体的错:引导里的【新】标记是假的。
原来的实现是一个写死的布尔量,贴在 7 条说明上(传递模式、贴图、取字、符号、界面语言、自动更新…)。
于是每次升级那 7 条都重新标一遍【新】 —— 升到 0.9.4,还在告诉你「传递模式」是新的,而那是 0.9.0 的东西。
标错的【新】比不标更糟:你会以为功能是刚加的,然后去找一个早就存在、早就该会的东西。
现在:每条说明都记着自己是什么版本加的,只有比你看过的那版更新的才标【新】。
| 你看过的版本 | 标【新】的条数 |
|---|---|
| 0.9.5 | 0 |
| 0.9.4 | 1(v0.9.5 新加的那条) |
| 0.8.0 | 3(自动更新 / 传递模式 / 新增说明) |
| 空 | 19(全部) |
全新安装一条都不标 —— 对第一次来的人每一条都是新的,标满等于没标。
这 5 条已经是自动化测试里的断言,不是靠人眼看的。
为什么截图时微信会「突然消失」
这是很多人会撞上、但完全猜不到原因的事,已写进引导和 README:
微信给 Windows 设了「把我排除在截屏之外」(SetWindowDisplayAffinity +
WDA_EXCLUDEFROMCAPTURE,Windows 10 2004 起的系统级机制)。
它的效果不是"拍成黑块",而是让抓屏透过去看到窗口后面的东西 ——
所以你按下截图热键、浮层盖住屏幕的那一刻,微信的位置显示的是它背后的桌面,看起来就是"微信咻地消失了"。
不是 SnapWheel 的问题,换任何截图工具都一样。
30 秒自助验证:按 Win+Shift+S(Windows 自带截图)框住微信 —— 同样拍不到,
那就说明是微信在反截屏。
顺手一提:SnapWheel 自己也给轮盘设了同一个标志,否则轮盘会拍进你截的每一张图里。
同一个机制,两边各用一次。
这不是推测,是量出来的。新增
tests/affinity-probe.cs,一条命令列出所有"反截屏"的窗口:
0x11 pid 59664 Weixin | Qt51514QWindowIcon | 微信 <== 从截屏里整个删掉
0x11 pid 57552 SnapWheel 快照轮环 | ... <== 同一个机制(它自己故意设的)
还补了两条本来就该有的说明
删掉 / 撤回 / 退出:右键删除、托盘「撤销上一次删除」、关闭键长按 0.65 秒退出程序。
这三件事之前引导里一个字都没提,而删除还是单击右键即生效的 ——
相当于一个会丢数据的操作完全没有说明。
工程
- 版本比较只留一份:更新检查要「远端比本地新吗」,引导要「这条说明比你看过的那版新吗」——
现在统一到AppInfo.IsNewer。两处各写一份迟早不一致。 ui-probe测试以前只能手动跑,现在进了标准测试套件 —— 否则上面那 5 条【新】断言等于没写。
完整版 SnapWheel-v0.9.5-full.zip | 无万能键版 SnapWheel-v0.2.22-nokey.zip
绿色免安装,解压双击即可,零第三方依赖。
v0.9.4 — 修掉「自动更新永远不会生效」
⚠️ 请手动下载,不要等自动更新
v0.8.1 ~ v0.9.3 的自动更新是坏的 —— 这个版本修的就是它本身,所以老版本收不到推送。
如果你在用老版本,请直接下载下面的 zip。
修掉「自动更新永远不会生效」
现象:托盘 →「检查更新」→ 下载完成 →「现在重启并安装?」→ 点「是」→ 程序重启 → 版本号一点没变。
根因:更新器模式的入口被注释吞掉了。
v0.8.1 给 Main 插入了这一行:
if (Update.IsApplyMode(args)) { Update.RunApply(args); return; }
但插入时它被挤进了同一行前面那段注释里,于是整行都成了注释。
Update.IsApplyMode / Update.RunApply 在 92-Update.cs 里定义得好好的,
却从来没有任何地方调用它们 —— 点了「是」之后启动的那个进程,走的还是普通启动流程。
为什么几个月都没被发现
这个 bug 把所有常规信号都躲过去了:
| 信号 | 为什么没报警 |
|---|---|
| 编译 | 通过 —— 注释本来就是合法的 |
| 警告 | 0 条 |
| 测试 | 全绿 —— 当时只测了「版本比较」和「ZIP 解压」,没人测入口 |
| README | 「自动更新」写得漂漂亮亮,功能看着齐全 |
| 日志 | 一切正常,因为根本没走进那条分支 |
它不是跑出来的,是逐行读代码读出来的。 Main 开头那行长得不对劲 ——
一行注释里塞了两个 // 和一段大括号。
新增守卫:tools/check-swallowed.ps1
这类 bug 编译器、警告、测试、CI 全都看不见。只有读能发现 ——
那就把「读」里能机械化的那部分交给机器:扫描纯注释行里出现完整块语句的形状。
判据是实测调出来的:先用事故原文验证它确实命中,再扫全仓库确认 0 误报。
中途试过「注释以分号结尾」这条更宽的判据,实测误报 5 处(文档注释里贴代码示例很正常),已弃用。
已接进构建流程。
测试不再「看运气」
修图标时发现测试套件是抖动的:同一份代码连跑三次,绘制测试报 3 / 2 / 1 个 FAIL。
「测试全绿」这句话当天骗了我们两次,所以这次治根 —— 三条抖动测试全改成确定性断言:
| 测试 | 原来为什么抖 | 现在怎么测 |
|---|---|---|
| 启动时把手渐显 | 隔 150ms 采样后断言像素数严格递增;动画一旦短于采样间隔,「中途」恰好等于「结束」 | 把动画进度直接拨到 0 / 0.5 / 1 再看画面。断言也更强:必须真的经过中间态 |
| 换背景有淡入过渡 | 靠 Sleep(120) 抓两帧比差异 —— 而且差异算出来根本没参与断言 |
种两张颜色明确的底,验证 fade=0.5 时像素恰好是两个端点的中点 |
| 展开/收起耗时对称 | 在共享机器上量真实墙钟,却用 1.3 的死阈值 | 各测两次取较快者抵消卡顿;阈值放到 1.4 容纳噪声 |
顺带发现:BackdropMix() 是按帧号缓存的(同一帧只混一次,这是性能设计),
测试直接调 DrawWheel 会绕过自增帧号的 RenderCore —— 不手动推进帧号,读到的一直是同一张缓存图。
完整版 SnapWheel-v0.9.4-full.zip | 无万能键版 SnapWheel-v0.2.22-nokey.zip
绿色免安装,解压双击即可,零第三方依赖。
v0.9.3 — 工具条图标修复与收尾
这一版不加新功能,只做收尾修复 —— 目标是进「稳定期」前的最后一轮打磨。
修掉的东西
标注工具条的 A- / A+ 图标
字母 A 原来"撑满按钮 + 居中",而减号/加号画在按钮右侧,两者压在一起。现在 A 只占左边 3/4。
标注工具条的撤销图标(换了两轮字符才确定不能用字符)
↶(U+21B6):弧线天生只占半格、字号偏小,看着就不对劲;⟲(U+27F2):先在候选对照图里挑了它(5 个字符 × 3 字体 × 3 字号),24pt 下是漂亮的圆环 + 箭头;
但按钮里只有 17pt,字形被 hinting 简化成"半圆 + 一竖",用户看到的仍然是异常。
结论:小字号下不该依赖字体字形。改为手绘「开口圆环 + 向左的实心三角箭头」,
半径写死 8*k,和旁边笑脸、另存为保持同一个量级。
工具条文字发虚 — T / A / 字 是白字深底,ClearType 的彩色次像素边会渲染出红蓝描边,
放大看像"字歪了、有重影"。工具条内改用灰度抗锯齿。
长图图标顶出按钮框 — 上下箭头原来画到 ±14,而按钮内高只有约 26px。
绘制层一个"整行不画"的隐藏 bug — 框高比字体实际高度小 1.2px 时,
Graphics.DrawString 既不裁切也不缩小,而是什么都不画。已用 Font.Height + 2 兜住,
并补了 6 字号 × 6 框高的回归测试。
体验
Esc取消传递时,缩略图飞回环上(缓动 + 淡出 + 缩小,320ms),不再瞬间消失。
工程
- 新增
tests/toolbar-zoom.cs:把工具条裁出来放大 6 倍出 PNG。
按钮只有 34×30 像素,在整屏图里根本看不清图标 —— 之前两轮"图标异常"都是靠肉眼猜的,一次也没看准。 - 新增
tests/ui-probe.cs:子控件矩形统一换算到窗口坐标系后两两求交,专测控件重叠。 - 修掉测试里的假 FAIL:断言写死的"工具条 14 个按钮"改成读源码常量。
完整版 SnapWheel-v0.9.3-full.zip | 无万能键版(多轮盘 + 框选缩放/锁定)SnapWheel-v0.2.22-nokey.zip
绿色免安装,解压双击即可,零第三方依赖。
v0.9.2 — 修传递模式放下没反应
v0.9.2
修掉传递模式"放下没反应"
现象一直是同一个:按空格之后鼠标从起点移到终点,然后什么都没发生,换任何参数都一样。
根因:SetCursorPos 只把光标"瞬移"过去,不产生鼠标移动消息。而轮盘的拖出是靠「按下 + 鼠标移动」启动的(OLE 拖放 DoDragDrop 的启动条件)—— 收不到移动消息,DoDragDrop 永远不会被调用。
修法:移动光标时补发一个 MOUSEEVENTF_MOVE。
这个修复曾经写对过一次(当时反馈"重新截一张图就能用了"),但后来做代码回退时被一起退掉了 —— 于是之后无论怎么改坐标、步数、时序、DPI,都必然得到同一个失败现象。现在这段加了显眼注释防止再丢。
顺带修的
- 起点可能落在屏幕外:轮盘贴屏幕底部时,缩略图中心会超出虚拟屏幕(实测 Y=1199 而屏幕高 1152),
SetCursorPos把光标夹到边缘,按下就落在空白处。现在取缩略图矩形与屏幕的交集中心。 - 图取不到内容时明确提示,不再默默无反应。
- 传递模式加了诊断日志(是否被调用 / 轮盘项数 / 起点坐标 / 实际光标位置)。
下载
SnapWheel-v0.9.2-full.zip— 完整版(含万能键)SnapWheel-v0.2.22-nokey.zip— 无万能键版
v0.9.1 — 修新手引导(遮挡 / 过长 / 首次限制失效)
v0.9.1
只修 v0.9.0 里新手引导的三个问题:
- 内容被「开始使用」按钮遮住 —— 滚动是靠移动控件位置实现的,而 WinForms 的窗体不裁剪子控件,超出窗口的内容照样画出来,于是有个标签正好压在按钮上。现在滚动内容放进一个
Panel(它会裁剪子控件),滚到边界就被切断。 - 窗口太长 —— 高度上限原来是「屏幕高度 − 24px」,内容一多就顶满整屏。现在收到屏幕的 72%,内容超出靠滚轮翻看。
- 「首次安装只显示 3 条」没生效、设置里的说明反而被截断 —— 判断条件用错了(拿
markNew当"是否首次")。现在改用独立的brief参数:只有首次安装才只给 3 条,设置里和升级提示都完整显示。
三种引导(设置里 / 首次 / 升级)都用离线探针实测过:与按钮重叠 = 0。
下载
SnapWheel-v0.9.1-full.zip— 完整版(含万能键)SnapWheel-v0.2.22-nokey.zip— 无万能键版
v0.9.0 — 传递模式(不用鼠标也能把图送出去)+ 引导改版 + 自动更新
v0.9.0
新功能:传递模式(不用鼠标也能把图送出去)
按 Ctrl+Alt+C,屏幕上出现一个「假光标」,右下角吸附着当前选中的缩略图。自己 Alt+Tab 切到目标窗口,把它移过去,按空格放下 —— 它会真的替你完成一次鼠标拖放,所以任何支持拖放的窗口都能用。
| 键 | 作用 |
|---|---|
| 方向键(或 WASD) | 移动假光标 |
| Shift | 加速 |
| 空格 / Enter | 放下 |
[ ] |
换一张 |
| C | 只复制到剪贴板(不自动粘贴) |
| Esc | 取消 |
移动推荐用方向键、换图用方括号 —— 它们不产生文字,不会在目标窗口里留下字母、也不会把输入法叫出来。
热键被占用时会自动换备选(Ctrl+Alt+W / F9 / F10),托盘菜单上显示当前实际生效的那个。
引导改版
- 首次安装只显示 3 条(三步上手),不再一上来丢一长串没人看
- 设置里的说明补全到 20 条:新增传递模式、取字 OCR、滚动长截图、另存为与单击复制、符号标注、界面语言、自动更新
- 跟着版本走:升级后自动弹「这次多了什么」,新增条目带【新】标记
自动更新(不花一分钱)
托盘 →「检查更新」→ 下载 → 自动替换并重启,轮盘和设置都保留。不需要服务器、不需要代码签名。
修掉的重要问题
- 模拟拖放一直不成功 —— 根因是轮盘是不激活窗口,而 Windows 会把「非活动窗口的第一次点击」用来激活它、应用收不到,模拟点击被系统吃掉,OLE 拖放永远不会启动(所以之前无论怎么调参数都是同一个效果)。现在放下前先把轮盘拉到前台。
- 图取不到内容时明确提示,不再默默什么都不做。
- 传递模式刚进入时窗口一闪就关 —— 手指还压在热键上,被当成"用户操作"了;现在一次性动作键用上升沿判断 + 350ms 保护期。
下载
SnapWheel-v0.9.0-full.zip— 完整版(含万能键)SnapWheel-v0.2.22-nokey.zip— 无万能键版
v0.8.0 — 工程重构(绘制度量层/拆大文件/i18n自检)+ 自动更新
v0.8.0
这一版没加新功能,做的是工程上的三件事(避免项目变成没人敢改的"屎山"),外加一个自动更新。
一、绘制度量层 DrawKit
项目里同一个错误犯过四次:测量用一套参数、绘制用另一套 → 文字被裁、框和图形错位、预览正常但导出跑偏。
根子不是"写错了",而是约定没有被强制。
新层把「量」的结果封装成 Fit 值(字体、字号、样式都在里面),画的时候只接受它 —— 调用方拿不到单独的字号,也就没法"另起一套"去画。错误在结构上写不出来。
配套 tests/drawkit-test.cs(项目第一套像素级自动化测试,6/6 通过),当场逼出两个没预料到的问题:字号与宽度不是线性关系(改迭代缩小)、缩到下限仍放不下时会一直溢出(改逐字截断加省略号)。
同时全线改用 GDI+:实测 GDI 的 DrawText 在 2560×1440 画布上单次 9.2ms(小画布 0.43ms,差 21 倍)。
二、拆大文件
| 文件 | 拆前 | 拆后 |
|---|---|---|
75-SettingsForm.cs |
1607 | 1057 |
61-WheelForm.Draw.cs |
1205 | 357 |
51-OverlayForm.Annotate.cs |
1194 | 616 |
50-OverlayForm.cs |
1000 | 763 |
64-WheelForm.Input.cs |
769 | 593 |
每一处都用同一个标准验证:拆完编译,exe 大小与拆分前完全一致(322,048 字节)—— 证明是纯搬移、零行为变化。
三、多语言自检脚本
tools/check-i18n.ps1:扫漏翻、扫"同一个中文配了不同英文"(翻译漂移)、扫长度异常。实测 395 条全部健康。
四、自动更新(不花一分钱)
不需要服务器、不需要代码签名、不需要任何付费账号。
检查(匿名读 GitHub Releases,限流 60 次/小时够用)→ 下载到临时目录 → 用 --apply-update 启动"更新器模式"的自己:等主进程退出 → 覆盖文件 → 重新拉起主程序 → 自己退出。
升级是覆盖已有文件,不触发 SmartScreen。托盘菜单新增「检查更新」,设置里保留开关(启动时静默检查,只在新版时提一句)。
自己实现了 ZIP 解压兜底(DeflateStream)—— 因为编译目标是 .NET 4.0,反射调不到系统解压组件,这个坑是测试发现的。
下载
SnapWheel-v0.8.0-full.zip— 完整版(含万能键)SnapWheel-v0.2.22-nokey.zip— 无万能键版
v0.7.1 — 比例动画性能修复(9倍)+ 层级焦点回归 + 界面语言
v0.7.1
性能:比例面板动画卡顿修掉了(该段 9 倍)
把一帧拆开逐个函数计时,发现比例胶囊的绘制占 8.2ms(一帧总共 16.4ms)。
真凶:TextRenderer.DrawText(GDI)在 2560×1440 的目标位图上单次要 9.2ms,而同样操作在小位图上只要 0.43ms —— 相差 21 倍。因为 GDI 的 DrawText 会沿整个目标表面处理裁剪区域,目标越大越慢;GDI+ 与目标大小无关。改用 DrawString 后该段 8.21ms → 0.91ms,全屏重绘 16.4ms → 5.9ms(约 166fps)。
完整的排查过程(含三轮错误猜测与实测数据对比)写进了 docs/LEARNING.md §2.4。
层级与焦点(回归修复)
- 修复「打开设置窗口,设置跑到主窗口下面」(上一版引入:只抑制了周期置顶,忘了轮盘本来就在顶层)
- 截图浮层显示后主动抢前台
- 轮盘在弹框/截图期间的置顶改用抑制计数,嵌套时不再丢状态
比例胶囊
- 未框选时不显示(原来按展开后总宽居中,收起时按钮偏左)
- 展开时与工具栏重叠会自动往下让开
- 收起时文字有渐隐过渡(原来 GDI 不认半透明,字是突然消失)
界面语言
新增「界面语言」设置项(跟随系统 / 中文 / English),380+ 条文案接入(托盘、设置窗口、对话框、截图浮层、取字窗口、长截图提示、反馈窗口…)。
其它修复
尺寸面板闪烁(双缓冲 Panel)、英文长句溢出(10 条改为两行)、拖出缩略图后不再从环上移除、系统版本读取改注册表、长截图避开任务栏、删除后视口平滑跟进。
下载
SnapWheel-v0.7.1-full.zip— 完整版(含万能键)SnapWheel-v0.2.22-nokey.zip— 无万能键版
v0.7.0 — 符号标注(可选颜色)+ 另存为 + 界面语言
v0.7.0
截图浮层新增两个工具
符号标注 —— 工具条上的符号按钮 → 弹出面板,顶部可选颜色(红/黄/蓝/黑,与标注色一致),下面三组共 72 个矢量符号:标记(✓ ★ ♥ ● ▲ ◆ …)、箭头(→ ⇒ ↻ …)、编号/其它(① ~ ⑫ ✎ ✂ ☎ …)。插入后和箭头、文字一样是标注元素:可拖动、滚轮/按钮改大小、Del 删除、Ctrl+Z 撤销,确认时合成进图。字体自带的矢量符号,单色可上色、放大不糊。
为什么不是 emoji:Windows 的彩色 emoji 靠
Segoe UI Emoji的 COLR/CPAL 表,而 .NET Framework 的整条文本栈都不读这两张表 —— GDI、GDI+、WPFFormattedText、WPFTextBlock四条路实测全是黑色剪影(做过像素分析确认)。真彩色只能上 Direct2D 的 COM 互操作,对这个"单 exe、零依赖"的项目代价不成比例。所以改用矢量符号,并因此回归零依赖。
另存为 —— 把当前框选(含标注)存到你选的位置,系统保存对话框,格式按扩展名走(PNG / JPEG / BMP,JPEG 自动铺白底避免透明变黑)。存完之后这张仍留在轮盘里,方便继续拖出去用。
界面语言(第一轮 i18n)
- 设置 → 行为 → 界面语言:
跟随系统 / 中文 / English,切换后重启生效 - 默认跟随系统语言,也可以显式指定后固定
- 第一轮已接入:托盘菜单全部 14 项
- 实现方式是
Lang.T("中文", "English")就地双写,不做 key 字典 —— 漏翻一眼能看见
修掉的问题
- 拖出缩略图后不再从环上移除:拖出是 Copy 语义,以前当成 Move,导致"拖一次就没了、不能再拖"。现在默认留一份,可在设置第 1 页关掉
- 轮盘置顶不再抢焦点(改用
SetWindowPos+SWP_NOACTIVATE):以前每 2 秒用TopMost重设会抢一次前台焦点,导致托盘右键菜单和打赏窗口"点出来过一会儿自己关了" - 反馈里的系统版本改读注册表(以前固定报
Windows NT 6.2= Win8) - 长截图:拼接时避开屏幕底部静止区(任务栏不再被一路重复贴进长图);自动滚改成一格一格,重叠区更大才拼得上
- 缩略图删除后视口平滑跟进;滚动范围放开到最后一张;计数序号改成"弧下端那一张"
- 大图缩略图的放大动画首次不再卡
下载
SnapWheel-v0.7.0-full.zip— 完整版(含万能键),解压即用SnapWheel-v0.2.22-nokey.zip— 无万能键版
两条产品线都编译 0 警告,只有一个 exe,不需要安装。
v0.6.0 — 滚动长截图 + 翻译引擎链 + 取字更准 + 弧线设计语言
这一版四件事
1. 滚动长截图(自动滚) —— 截图浮层里框一块区域 → 点工具条上的长图按钮 → 程序自己滚、自己按重叠区无缝拼接,到底自动停。拼不上时会明确说原因,绝不硬拼出错位的接缝。
2. 翻译换引擎链 —— 原来只有 MyMemory(机翻腔重)。现在:自填的 OpenAI 兼容接口(DeepSeek / 豆包 / 通义 / 本地 Ollama 都行)→ 有道免费接口(无 key、国内直连,默认走这层)→ MyMemory 保底。
3. 取字更准 —— 低对比度截图(暗色主题、浅灰字)先做直方图拉伸再识别:实测同一张图从 0% 认出提升到 92%~97%;普通 14px 正文 82.9% → 87.8%。
4. 弧线设计语言 —— 三个小按钮紧贴万能键左上方沿弧排布、悬停时按主题色发光;计数胶囊沿弧弯、数字顺着弧排。
另外:所有对话框在 150% DPI 下不再裁字、大图缩略图的放大动画首次也不再卡、删中间一张图时上面的图会平滑滑下来填补空位。
下载
SnapWheel-v0.6.0-full.zip— 完整版(含万能键),解压即用SnapWheel-v0.2.22-nokey.zip— 无万能键版
两条产品线都编译 0 警告,只有一个 exe,不需要安装。