- 桌面应用
- AI 应用
- 插件系统
【免费下载链接】Wox
A cross-platform launcher that simply works
Wox 在启动器窗口内直接内置了倒计时功能,不需要安装任何第三方插件,只需输入timer加时长即可开始计时,还能把倒计时浮层钉到桌面上、在 Wox 重启后继续计时。本文将围绕这一系统内置插件,从查询语法、操作方式到源码级的持久化与浮层渲染实现,完整讲解其使用与工作原理。
它是什么:与启动应用同一窗口的倒计时
Wox 把倒计时做成了系统内置插件TimerPlugin,注册在 timer.go 中,触发关键字为timer(见 GetMetadata 中的 TriggerKeywords)。它的定位与打开应用是同一体验:你可以在同一个查询窗口里,既启动应用,也启动一个倒计时。
基本用法只有一行:
timer 5m timer 1h meeting timer 1h5m there is a meeting语法规则如下:
timer后面跟一个或多个时长 token,格式为<数字><单位>,单位支持h(小时)、m(分钟)、s(秒),token 之间可以用空格分隔,也可以紧挨着写(如1h5m);- 时长解析完毕后,剩余的文字自动成为计时器备注(note),显示在倒计时标题下方,方便你区分多个计时器,例如
timer 25m focus的备注就是focus; - 时长 token 必须出现在输入最前面,如果以文字开头(如
cooking 5m),将无法被识别为时长。
解析逻辑由 parseTimerQuery 实现:它用正则(\d+)\s*([hms])逐个吞掉开头的时长 token,累加为总时长,并把剩余输入作为备注。timer_test.go中的 TestParseTimerQuery 覆盖了完整语法矩阵,包括1h 15m、1h15m两种写法等价,以及0m、5x、cooking 5m这类非法输入返回失败:
{"1h 15m", time.Hour + 15*time.Minute, "1h 15m", "", true}, {"1h15m", time.Hour + 15*time.Minute, "1h 15m", "", true}, {"5m cooking", 5 * time.Minute, "5m", "cooking", true}, {"1m这只是一个说明", time.Minute, "1m", "这只是一个说明", true}, {"cooking 5m", 0, "", "", false},注意:解析器支持中英文混排备注(如1m这只是一个说明),这也意味着时长单位必须使用英文的 h/m/s,中文的“分”“秒”不会被识别为时长 token。
怎么用:三步完成一次番茄钟
- 输入
timer 25m focus。 - 按
Enter开始并显示在桌面(浮层钉住),或打开操作面板(Action Panel)选择在后台开始(不显示浮层)。 - 之后随时输入
timer,已运行的计时器会出现在结果列表中,可以暂停 / 继续、编辑备注、钉住浮层或删除。
当查询框内没有任何活动计时器时,插件会给出“No active timers”的空状态提示(见 Query 中的空结果分支)。
动作一览
| 动作 | 用途 |
|---|---|
| 开始并显示在桌面 | 开始计时并钉住桌面浮层 |
| 在后台开始 | 开始计时但不显示浮层 |
| 暂停 / 继续 | 保留剩余时间,稍后从暂停处继续 |
| 钉住 | 显示或隐藏桌面浮层 |
| 编辑备注 | 修改计时器描述文字 |
| 删除 | 结束并移除该计时器 |
这些动作定义在 buildTimerActions 中:
- 暂停/继续是默认动作(
IsDefault: true),按Enter即触发,动作执行后PreventHideAfterAction: true保证查询窗口不隐藏,方便连续操作; - 钉住/取消钉住绑定
Primary+Enter热键(util.PrimaryHotkey("enter")),执行后同样不隐藏窗口; - 编辑备注是一个表单动作(
Type: QueryResultActionTypeForm),弹出一个文本框,提交后通过t.api.RefreshQuery刷新结果列表,让副标题和表单默认值保持同步; - 删除会关闭浮层并从持久化存储中移除该计时器。
每个结果行的排序由 listTimersSorted 保证:剩余时间越少,排得越靠前,暂停中的计时器按剩余时长参与排序;同时结果行通过ScoreKey: "timer:" + entry.ID保持身份稳定,剩余时间变化时行不会被误判为新结果。
重启后继续计时:绝对截止时间与暂停剩余时间
正在运行的计时器在 Wox 重启后会保留,这是该功能最具实用价值的一点。其实现核心是持久化策略的精心设计(见 timerPersisted 的注释):
- 运行中的计时器保存的是绝对截止时间戳
DeadlineUnixMs。重启后直接用Deadline - now计算剩余时间,所以即使你在 Wox 关闭期间过了 10 分钟,重启后倒计时依然是正确的,而不是从上次保存的剩余时间继续走; - 暂停中的计时器保存的是剩余时长
RemainingMs,因为暂停状态下没有截止时间的概念; - 备注、时长标签、暂停标志一并持久化。
持久化数据通过插件设置接口保存,key 为activeTimers(timerPersistedSettingKey),保存时带platformScoped=true(saveTimers),代码注释明确:倒计时的截止时间属于本设备本会话,不应跨平台同步。
恢复逻辑在 loadTimers:
- 启动时从设置里读取 JSON 数组并反序列化;
- 重启前已经过期的运行中计时器不会继续挂着,而是直接触发一次“计时结束”通知然后被丢弃;
- 无效条目(ID 为空或时长非正)会被跳过;
- 恢复完成后如果有过期或丢弃的条目,会重新写回存储保持数据干净。
对应地,timerEntryToPersisted 与 timerEntryFromPersisted 负责内存对象与持久化快照的双向转换,TestTimerPersistedRoundTrip 用固定截止时间戳验证了往返转换的一致性。
需要特别说明的是:浮层本身不会持久化。重启后若还需要桌面浮层,重新输入timer找到该计时器再钉一次即可——这与原文档的说明一致,属于刻意的设计取舍(持久化注释中写明 Pin/overlay 状态刻意不保存)。
秒级心跳:计时、结束通知与结果实时刷新
TimerPlugin在 Init 中启动了一个每秒触发一次的 ticker 协程,驱动三件事:
- 收集到期计时器并收尾:
collectFinished找出所有未暂停且截止时间已到的条目,finishTimer将它们从内存移除、关闭浮层、持久化更新,并通过系统通知弹出“Timer finished: xxx”(notifyTimerFinished 同时走 Wox 应用内通知与系统级notifier.Notify,确保即使 Wox 不在前台也能收到提醒); - 刷新钉住的桌面浮层:
refreshOverlays遍历所有OverlayVisible的计时器,调用showOverlay更新浮层上的倒计时文字; - 实时更新查询结果:
pushTimerResultUpdate通过UpdateResult把剩余时间、副标题、图标、动作推送给正在显示的结果行。为了避免查询结果尚未送达 UI 时的瞬态丢失,代码特意保留了trackedResults映射,下个 tick 会重试(见 tick 的注释),TestTimerTickRetriesTransientResultMiss 验证了该重试行为。
剩余时间的格式化由 formatTimerRemaining 完成:不足 1 小时显示MM:SS(如04:59),满 1 小时显示1h 02m 03s风格,负数会被钳制为00:00;TestFormatTimerRemaining 覆盖了这些边界。
暂停/继续的实现要点在 pauseTimer 与 resumeTimer:暂停时把Deadline快照为Remaining,继续时用Now + Remaining重建新的截止时间,二者都立即持久化。TestTimerPauseResumeRemaining 验证了暂停后剩余时间保持稳定、继续后按剩余时长重新起算。
桌面浮层:可拖动、置顶、悬停展开的 HUD
钉在桌面上的倒计时浮层由 timeroverlay.go 渲染,它不是一个普通窗口,而是基于 Wox overlay 机制实现的 HUD:
- 默认锚点在屏幕底部中央,向上偏移 80px,置顶显示且可拖动(showOverlay 中的 WindowOptions);
- 浮层采用紧凑设计:平时只显示粗体倒计时数字(默认字号 22),鼠标悬停时才展开显示备注(字号 11)与右上角关闭按钮(见 buildTimerOverlay),宽度上限 316px,保证不遮挡视野;
- 关闭按钮与倒计时文本都带有无障碍语义标签和
LiveRegion,并声明了自动化 ID(timer-overlay-countdown、timer-overlay-note、timer-overlay-close),可供屏幕阅读器与自动化测试访问; - 用户在浮层上点关闭按钮时,
OnClose回调会把内存中的OverlayVisible与OverlayPlaced复位,保持状态一致; - 删除计时器时,代码特意先移除内存条目再关闭浮层,避免并发 tick 在窗口关闭后重建已删除的浮层(deleteTimer 的注释),TestDeleteTimerStopsStaleOverlayRefresh 专门回归了该竞态场景。
小结
Wox 内置倒计时是一个小而完整的系统插件:查询语法支持多 token 时长组合与备注,结果行提供暂停/继续、钉住、编辑备注、删除等完整动作;运行中的计时器以绝对截止时间持久化,保证重启后剩余时间依然准确;每秒的 tick 协程驱动浮层刷新、结果实时更新与结束通知;桌面浮层则是一个可拖动、可关闭、悬停展开的置顶 HUD。对普通用户来说,它就是“输入timer 25m focus开始一个番茄钟”这么简单;对开发者而言,timer.go、timer_test.go 与 timeroverlay.go 三份文件构成了一套可借鉴的“轻量插件 + 秒级任务调度 + 非持久化 UI 状态”设计范本。
- 桌面应用
- AI 应用
- 插件系统
【免费下载链接】Wox
A cross-platform launcher that simply works
相关推荐
Wox 倒计时定时器(timer 命令)使用指南:启动、桌面置顶与跨重启持久化完全解析
Wox 倒计时定时器(timer 命令)使用指南:启动、桌面置顶与跨重启持久化完全解析 Wox 内置了一套倒计时定时器功能,你无需安装任何额外插件,就能直接在启
桌面应用AI 应用插件系统Wox 内置浮动笔记(Notes)完全指南:启动器内富文本笔记的查询、保存、导出与云同步
Wox 内置浮动笔记(Notes)完全指南:启动器内富文本笔记的查询、保存、导出与云同步 Wox 内置了一套完整的浮动笔记功能,让你不必切换到其他笔记应用,就能
桌面应用AI 应用插件系统Home Assistant timer.start 动作详解:启动与重启 Timer 倒计时的完整指南(UI + YAML)
Home Assistant timer.start 动作详解:启动与重启 Timer 倒计时的完整指南(UI + YAML) 本篇技术指南围绕 Home As
文档教程智能家居物联网
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考