HoldNote:在 Ubuntu 上长按 Super,把选中文字存进 Memos

每天读论坛、技术文章和聊天消息,总会遇到想留下的一句话。过去我需要复制、切窗口、粘贴,再回到原来的内容。这次做了一个更短的动作:按住 Windows/Super 键,拖选文字,松开,自动保存。

这个小工具叫 HoldNote。第一版只做文字,不做截图,先把最常用的交互做稳。源码已用 MIT 许可证开源:lizi-learn/holdnote-linux。

一个动作,留下当前这段文字

  1. 按住左或右 Super 键约 450 毫秒,等绿色提示出现。
  2. 保持按住,用鼠标左键拖选想记录的文字。
  3. 松开 Super,客户端提交文字;服务器确认保存后,桌面显示通知。

Esc 可以取消;短按 Super 仍然打开或关闭 GNOME 概览。组合键、空选区、没有重新选择的旧内容不会被发送。所选换行与缩进保留,默认追加 #inbox #holdnote,方便在 Memos 中筛选。

这里有一个明确的取舍:GNOME 默认的 Super+拖动会移动窗口,和文本拖选冲突。因此工具运行时把窗口移动改成 Alt+拖动,停止服务会恢复原设置。

网站用成熟的 Memos,放在腾讯云

记录入口是 memos.bismih.cn,使用官方 Memos 界面,支持搜索、标签、归档和编辑。它是私人实例,不开放公众注册;网址能打开,不代表访客能看到笔记。

服务部署在腾讯云的 Docker 容器中。当前锁定 Memos 0.31.0,以非 root 用户运行,根文件系统只读,数据卷持久化,内存上限 512MiB。应用端口仅监听服务器回环地址,由 Caddy 提供 HTTPS。

客户端用普通用户的独立个人访问令牌(PAT),不使用管理员密码或浏览器 Cookie。API 路径按这个版本实现,升级 Memos 时需要重新核对接口。

GET  /api/v1/auth/me
POST /api/v1/memos?memoId=<本次采集 UUID>
GET  /api/v1/memos/<本次采集 UUID>

{"content":"选中的文字", "visibility":"PRIVATE"}

参考:Memos API 访问说明、0.31.0 接口定义。不要把本项目的 /api/v1 路径直接套到其他版本。

客户端不是一个持续上传剪贴板的程序

Ubuntu 桌面端使用 Python、GTK3 和 python-xlib,后台由 systemd 用户服务管理,不需要 root 守护进程。它根据 Super 手势判断是否采集,普通打字事件立即丢弃,不解码成文字,不保存键盘日志,也不持续上传剪贴板。

文字来自 X11 的 PRIMARY 选区,不自动模拟 Ctrl+C,不覆盖原来的复制剪贴板。部分应用不提供 PRIMARY,这些应用暂时不能直接拖选保存;可主动复制后运行 holdnote send --clipboard。

目前支持范围:Ubuntu 22.04、GNOME、X11。Wayland 和其他桌面环境未实现,不能因为单元测试通过就声称所有 Linux 桌面都能用。

断网不会直接丢掉刚选的文字

选中的文字先进入本机加密待发队列,再提交给 Memos。队列正文使用 Fernet 加密,令牌和加密密钥放在 GNOME Secret Service;拒绝回退到明文钥匙串。配置不包含令牌,私有目录与队列文件权限分别为 0700、0600。

网络失败会退避重试;认证失败会暂停,保留加密内容等待处理。同一次采集始终使用相同的 Memos ID,避免请求成功但回执丢失时重复入库。发送成功后清掉本地队列正文,只留下状态和回执。通知不展示正文,降低锁屏时泄露所选内容的风险。

这不是端到端加密。HTTPS 保护传输,队列加密保护本机暂存;Memos 服务器仍然能读取笔记。主机管理员权限、服务器安全、数据库备份,以及同一 X11 会话内其他应用的权限,仍是需要认真对待的边界。个人数据和密钥不进入公开 GitHub 仓库。

安装与日常维护

sudo apt install python3-gi gir1.2-gtk-3.0 python3-xlib \
  python3-keyring python3-cryptography python3-requests python3-venv python3-wheel libnotify-bin
git clone https://github.com/lizi-learn/holdnote-linux.git
cd holdnote-linux
bash install.sh
~/.local/bin/holdnote configure --url https://YOUR-MEMOS-HOST
~/.local/bin/holdnote session-start

configure 会隐藏输入 PAT,不要把令牌拼进命令参数。自建 Memos 的 Docker Compose、Caddy 配置、完整 API 实现和测试都在仓库里。首次管理员初始化建议通过 SSH 隧道完成,再公开网站,避免初始化界面被别人抢先注册。

holdnote doctor                     # 检查认证与队列
holdnote status                     # 查看待发状态
holdnote retry                      # 重新尝试失败项
systemctl --user stop holdnote      # 停用并恢复桌面设置
systemctl --user restart holdnote   # 重启客户端

令牌和队列密钥只保存在自己的钥匙串中。卸载前先处理待发内容,不要直接删除队列或重置密钥,否则尚未送达的文字可能无法恢复。

这次实际验证了什么

24 项单元测试通过,覆盖手势、取消、认证失败、私密写入、禁止凭据重定向、加密队列、并发领取和稳定 ID 重试。随后在 Ubuntu 22.04 / GNOME 42.9 / X11 的真实桌面上完成了左右 Super 拖选保存、Esc 取消不入库、短按概览、停用恢复设置测试。Memos 网页也能看到新记录,保存结果是 PRIVATE。

测试期间客户端后台内存约 37MiB,这是当前机器的观测值,不是所有环境的性能承诺。空闲时阻塞等待事件,不轮询读取所有剪贴板内容,也不持续调用服务器 API。

后续扩展,但不把“接口”说成“已完成”

项目预留 TextDestination.send(text, capture_id) 发送目标接口,后续可以接 Telegram Saved Messages 或已有授权的微信 ClawBot 桥接。Telegram 收藏夹需要用户自己的 MTProto 会话,普通 Bot 不能代替。这两项目前尚未接入,截图也未实现。第一版只把文字可靠地存到自己的 Memos。

对我来说,这个项目最重要的价值是减少记录的阻力:遇到值得留的内容,做一个动作就留下;后面再慢慢搜索、整理和分析。

上一篇
下一篇