一个只有窗口置顶功能的 Windows 小工具(约 65 KB)。
TopPin 使用原生 Win32 C 编写。它没有主窗口、安装程序、后台服务或联网功能:运行后进入系统托盘,按一次快捷键置顶当前窗口,再按一次取消。
这是二创项目。 本仓库基于原作者 chiimyen/TopPin,并把 Microsoft PowerToys 的
AlwaysOnTop模块的边框外观、 不透明度调节、游戏模式判定与拖动跟随策略移植了过来。详细署名、源文件对照与许可见 ATTRIBUTION.md。与 Microsoft / PowerToys 官方无任何关系。
本项目是二次创作(derivative work),不是原创:
| 来源 | 用在本项目的部分 | 许可 |
|---|---|---|
| chiimyen/TopPin | 原始项目骨架:托盘常驻、单实例、全局热键、置顶/取消、管理员提权、开机自启 | MIT,© 2026 chiimyen |
Microsoft PowerToys → AlwaysOnTop |
边框几何与默认外观、不透明度调节、游戏模式判定、拖动跟随策略 | MIT,© Microsoft Corporation |
具体对照了 PowerToys 的 src/modules/alwaysontop/AlwaysOnTop/ 下这些文件:WindowBorder.cpp
(GetFrameRect、UpdateBorderPosition、100 ms 间隔)、FrameDrawer.cpp(描边内缩 thickness/2+1、
圆环由内外圆角矩形做差)、Settings.h(全部默认值)、WindowCornersUtil.cpp(圆角半径映射)、
AlwaysOnTop.cpp(不透明度步进与 layered 状态还原、EVENT_OBJECT_LOCATIONCHANGE 订阅),
以及 src/common/utils/game_mode.h(游戏判定)。
C 代码是本分支自行编写的,没有从 PowerToys 复制 C++ 源文件;对齐的是几何规则、默认参数和交互语义。 渲染管线也不同:PowerToys 用 Direct2D,本分支用 GDI 位图 + 圆角矩形距离场自算抗锯齿。
上游 TopPin 与 PowerToys 均为 MIT 许可;完整许可文本与免责声明见 ATTRIBUTION.md。
在上游 chiimyen/TopPin 基础上加了这些功能:
- 热键可配置:不再写死
Ctrl+Alt+T,改TopPin.ini即可,托盘菜单可直接打开/重载配置。 - PowerToys 同款置顶边框:几何、默认外观、圆角规则全部照搬 PowerToys
AlwaysOnTop模块(见下方“边框是怎么画的”)。 - 窗口不透明度调节:默认
Ctrl+Win+=提高、Ctrl+Win+-降低,每次 10%,范围 20%–100%,只对已置顶窗口生效,取消置顶时自动还原。 - 游戏时不激活:独占全屏(D3D fullscreen)运行中不响应置顶,默认开启。
系统要求:Windows 10/11 x64。
- 从 Releases 下载
TopPin.exe,或从 Actions 取最新构建产物。 - 运行后,TopPin 会进入右下角系统托盘。
- 点击需要置顶的窗口。
- 按快捷键(默认
Ctrl + Alt + T)置顶;再次按下即可取消。
也可以双击托盘图标切换最近使用的窗口,或者右键托盘图标管理已经置顶的窗口。
TopPin 是本地编译的开源程序,目前没有商业代码签名证书。Windows 可能显示“未知发布者”,你可以从本仓库检查源码并自行编译。
- 单个便携 EXE,不需要安装。
- 全局快捷键默认
Ctrl + Alt + T,可在TopPin.ini里改成任意组合。 - 置顶窗口周围显示一圈 PowerToys 风格的边框:默认跟随系统主题色、4px、随窗口圆角、DPI 自适应。
- 可调已置顶窗口的不透明度(20%–100%,步长 10%),取消置顶自动还原。
- 独占全屏游戏运行时不激活,默认开启。
- 托盘菜单可一键「关闭通知 / 开启通知」,状态写回配置。
- 托盘菜单查看和取消已置顶窗口。
- 可选开机自动启动,默认关闭。
- 遇到管理员窗口时按需请求 Windows UAC 权限。
- 单实例运行;目标窗口关闭后自动清理。
- 退出 TopPin 时恢复由它置顶的窗口。
- 不读写用户文档、不联网、不收集数据。
首次运行时自动在 TopPin.exe 同目录生成(UTF-16 LE,带 BOM,记事本可直接编辑):
[TopPin]
Hotkey=Ctrl+Alt+T
OpacityUpHotkey=Ctrl+Win+=
OpacityDownHotkey=Ctrl+Win+-
Border=1
BorderColor=auto
BorderOpacity=100
BorderThickness=4
BorderCorner=1
BlockInGameMode=1
Notify=1| 键 | 说明 | PowerToys 默认 |
|---|---|---|
Hotkey |
置顶/取消热键。修饰键 Ctrl/Alt/Shift/Win 至少一个,加一个主键 |
Win+Ctrl+T(本分支沿用 Ctrl+Alt+T) |
OpacityUpHotkey |
提高不透明度 | Ctrl+Win+= |
OpacityDownHotkey |
降低不透明度 | Ctrl+Win+- |
Border |
1 显示边框,0 关闭 |
1 |
BorderColor |
auto 跟随系统主题色;也可写 #RRGGBB |
主题色(拿不到时 #00ADEF) |
BorderOpacity |
边框不透明度,1–100 | 100 |
BorderThickness |
边框粗细(像素,会乘 DPI 缩放),1–32 | 4 |
BorderCorner |
1 跟随窗口圆角,0 直角 |
1 |
BlockInGameMode |
1 独占全屏游戏时不激活 |
1 |
Notify |
1 显示托盘气泡提示,0 关闭;也可直接用托盘菜单的「关闭通知」切换(会自动写回本文件) |
1 |
热键主键支持 A-Z、0-9、F1-F24、Space、Tab、Enter、Esc、Insert、Delete、Home、End、PageUp、PageDown、Up、Down、Left、Right、Num0-Num9、PrintScreen、Pause,以及 - = , . ; / [ \ ] ' 和反引号。大小写不敏感,空格会被忽略。
改完在托盘菜单点 重新加载配置 即可生效,不用重启;写错了会自动退回默认值并在托盘气泡里提示。
关掉
Border后连边框定时器都不会启动,回归“零额外开销”的上游行为。
全部照搬 PowerToys src/modules/alwaysontop/AlwaysOnTop:
- 取
DWMWA_EXTENDED_FRAME_BOUNDS(窗口可见边框),向外各扩BorderThickness,这就是边框窗口的矩形——所以圆环画在窗口外面,只压住 1px,不遮内容。 - 描边中心线 = 客户区向内
thickness / 2 + 1的圆角矩形,描边宽度 =thickness;圆角半径取窗口的DWMWA_WINDOW_CORNER_PREFERENCE(ROUND=8 / ROUNDSMALL=4 / 其它=0)再乘 DPI 缩放。 - 逐像素用圆角矩形有符号距离场算覆盖率做抗锯齿,写进 32 位预乘 ARGB 位图,再用
UpdateLayeredWindow贴上去——和 PowerToys 用 D2D 画出来的结果一致。 - 只遍历靠近四边的“边框带”,中间像素直接跳过,所以即使 4K 窗口渲染开销也可忽略。
- 边框窗口是
WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,点击完全穿透、不进任务栏和 Alt-Tab。
边框跟随窗口位置用的是 Windows 事件,不是提高定时器频率:
- 注册
SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, ...)(外加EVENT_SYSTEM_MOVESIZEEND),拿到事件后先用 hwnd 过滤(只认OBJID_WINDOW且在置顶列表里的窗口); - 命中就只做一次
SetWindowPos(边框窗口, 新坐标, SWP_NOSIZE | SWP_NOREDRAW)——只挪,不重画,单次开销微秒级; - 100 ms 定时器仍然保留,负责重新渲染内容和校正(尺寸变了也走这条完整路径)。
所以拖动时边框跟着每一个位置事件走(接近屏幕刷新率),而重绘仍然只有 10 Hz,CPU 不会因为"更顺"而上涨。
主题色只在启动和「重新加载配置」时读取一次并缓存,避免每个拖动事件都去读注册表;运行中改了系统主题色需要重新加载配置才会更新。
- 调节只作用在已置顶窗口上,内部用的是
WS_EX_LAYERED+SetLayeredWindowAttributes,并会缓存窗口原本的 layered/alpha/colorkey 状态,取消置顶或退出程序时原样还原。 - 游戏判定与 PowerToys 相同:
SHQueryUserNotificationState() == QUNS_RUNNING_D3D_FULL_SCREEN(独占全屏)。命中时置顶热键直接不响应,透明度和退出的热键不受影响。
- 切换当前窗口置顶:与快捷键相同,右括号里显示当前配置的组合键。
- 已置顶窗口:查看并单独取消当前置顶窗口。
- 取消全部置顶:一次恢复所有窗口。
- 重新加载配置:重新读取
TopPin.ini并重注册快捷键。 - 打开配置文件…:用默认编辑器打开
TopPin.ini。 - 关闭通知 / 开启通知:一键开运气泡提示,状态会写回
TopPin.ini的Notify。 - 开机自动启动:写入或删除当前用户的 Windows
Run启动项。 - 以管理员身份重新启动:通过标准 UAC 流程控制管理员窗口。
- 退出 TopPin:恢复窗口后退出。
TopPin 默认以普通权限运行,因此不会每次开机都弹出 UAC。目标程序以管理员身份运行时,TopPin 会询问是否继续;确认后,普通实例先恢复当前窗口状态,再由管理员实例接管并重试置顶。
“开机自动启动”默认关闭,不会创建服务或计划任务。启用后请不要随意移动 TopPin.exe;如果移动了文件,在新位置重新勾选一次即可更新启动路径。
- 管理员提权必须经过 Windows UAC 确认,不能静默绕过。
- Windows 只保证置顶窗口位于普通窗口之上;多个置顶窗口之间没有唯一的最高层。
- 独占全屏游戏不属于普通桌面窗口,无法保证覆盖。
- 游戏判定与 PowerToys 相同,只认「独占全屏(D3D fullscreen)」;无边框全屏窗口不会被判定为游戏。
- 调节不透明度的原理是给目标窗口加
WS_EX_LAYERED,个别硬件加速/自绘界面的程序可能出现短暂闪烁或完全无效;取消置顶时会把原始 layered 状态还原。 - 直角边框(
BorderCorner=0)走的是矩形抗锯齿分支,视觉效果与 PowerToys 的 D2D 描边一致,但不是同一套渲染管线。
推送到 main 或手动触发 .github/workflows/build.yml,GitHub Actions 会在 windows-latest 上用 MSYS2 UCRT64 的 MinGW-w64 编译,产物作为 TopPin-exe artifact 上传;打 v* tag 会自动发布到 Releases。
安装 MinGW-w64 GCC,并确保 gcc.exe 与 windres.exe 位于 PATH,然后运行:
build.cmd成品位于 dist\TopPin.exe。
图标的矢量母版是 Assets/TopPin.svg。只有重新生成 ICO 时才需要 Python 和 Pillow:
python tools\build_icon.pytests\build-smoke.cmd
build\TopPinSmoke.exe烟雾测试会短暂创建一个窗口,验证:
- 单实例运行
- 开机启动开启与撤销
- 真实快捷键置顶与取消
- 退出后恢复窗口
注意:烟雾测试固定发送默认的 Ctrl+Alt+T,所以它要求 TopPin.ini 里保持默认 Hotkey(或者直接删掉 ini 文件)。
测试开始前如果发现 TopPin 正在运行,会通过正常退出消息关闭它。
TopPin.c:全部程序逻辑。TopPin.rc、app.manifest:图标、版本信息和 Windows 权限清单。Assets/TopPin.svg、Assets/TopPin.ico:图标源文件与多尺寸资源。tools/build_icon.py:图标生成脚本。tests/TopPinSmoke.c:原生烟雾测试。