Tendedero 源码剖析(一):用 kqueue 捕获每张新截图,ScreenshotWatcher 监听原理全解
Tendedero 源码剖析一用 kqueue 捕获每张新截图ScreenshotWatcher 监听原理全解【免费下载链接】tendederoScreenshots, hung out to dry. A tiny native macOS app that hangs every screenshot on a line at the top of your screen.项目地址: https://gitcode.com/gh_mirrors/te/tendederoTendedero 是一个免费开源的 macOS 小工具你截取的每一张截图都会自动挂到屏幕顶部的晾衣绳上。它从不自己截屏而是靠 ScreenshotWatcher.swift 中的ScreenshotWatcher类用 macOS 的 kqueue 文件系统事件监听截图保存目录实时捡起每一张新截图。本文带你逐行看懂这套截图监听的完整原理。先看看它长什么样下面这张图展示了 Tendedero 的核心交互光标停在菜单栏附近晾衣绳就带着挂着的截图滑落下来点击可复制拖到文件夹可保存离开即收起。挂上去之后能做什么点一下复制按住打开系统 Markup 标注拖进 App 发送副本拖进文件夹保存——所有截图都在本地处理没有网络、没有账号。核心在哪ScreenshotWatcher.swift 的定位整个项目的源码在 Sources/Tendedero/ 下按文件分工很清晰完整的文件职责表见 README.md 的 Inside the app 小节。与本文主题直接相关的只有三处文件职责ScreenshotWatcher.swift监听截图目录发现新截图就回调onNewInbox.swift把系统截图保存位置改到 Tendedero 自己的文件夹收件箱模式AppDelegate.swift创建并启动监视器把新截图挂上绳ScreenshotWatcher全文只有一百多行但设计非常讲究。它的设计哲学写在文件开头的注释里Tendedero 永远不自己截屏——你继续用 CmdShift3/4或者用 CleanShot 之类的任何工具它只管捡结果。第一步找到截图到底保存在哪监视之前得先知道目录。screenshotFolder()不猜、不硬编码而是直接读系统设置先通过CFPreferencesAppSynchronize同步com.apple.screencapture偏好域确保读到最新值ScreenshotWatcher.swift#L29-L43依次尝试两个键macOS 27 起叫location-screenshot更早版本叫location——这两个键正好对应 CmdShift5 里选项 → 存储位置的设置读到的路径有效就返回否则回退到桌面这样做的妙处用户在系统设置里改了截图位置Tendedero 下次启动就自动跟上无需任何配置界面。第二步kqueue 目录监听原理真正的监听逻辑在start()方法里ScreenshotWatcher.swift#L50-L68拆开看是四步1️⃣ 打开目录的文件描述符。关键参数是O_EVTONLY——这是 kqueue 专用的标志位表示这个 fd 只用来收事件不用来读写数据。2️⃣ 创建 GCD 文件监视源。核心一行DispatchSource.makeFileSystemObjectSource( fileDescriptor: fd, eventMask: [.write, .rename, .delete], queue: .main)DispatchSource.makeFileSystemObjectSource是 GCD 对 kqueue 文件事件的高层封装它在底层向内核 kqueue 注册了这个目录的NOTE_WRITE、NOTE_RENAME、NOTE_DELETE三种事件。目录内任何文件的创建、写入、改名、删除都会唤醒监视源。3️⃣ 事件触发后不立即处理而是预约一次扫描见下文。4️⃣ 注册取消回调。setCancelHandler { close(fd) }保证监视停止时文件描述符一定被释放不留资源泄漏。为什么监听目录而不是监听某个具体文件因为每次截图的文件名都是全新的截屏 2026-10-09 16.05.34.png……根本不知道下一个文件叫什么名字而目录级事件能捕获一切变化是最稳妥的监听粒度。第三步0.2 秒防抖为什么不能收到事件就处理事件回调并不直接扫描目录而是走scheduleScan()ScreenshotWatcher.swift#L76-L82DispatchQueue.main.asyncAfter(deadline: .now() 0.2, execute: work)每次事件触发都会先取消上一次还没执行的扫描再延迟 0.2 秒重新预约。这是典型的防抖而且注释点明了原因macOS 截图是先写一个隐藏临时文件再原子改名成最终文件名——一次截图往往连发多个事件写 改名立刻扫描很可能读到半成品。0.2 秒的窗口让文件落定多次事件也只合并成一次扫描省掉无谓的目录遍历。扫描本身scan()ScreenshotWatcher.swift#L84-L91逻辑直白列出目录内所有文件和已知的known集合比对凡是不认识且符合条件的就回调onNew最后把整个列表刷新进known。第四步如何判定一张真截图不是目录里冒出图片就算截图——桌面上随手存个 jpg 不该被挂上绳。isCandidate()做了两层过滤ScreenshotWatcher.swift#L103-L113扩展名白名单png、jpg、heic、tiff、gif、webp 等图片格式场景区分监视的是桌面时文件必须带 macOS 给真截图打的扩展属性com.apple.metadata:kMDItemIsScreenCapture用getxattr检查——系统截图都带这个标记手工存的图片没有监视的是专用截图文件夹收件箱模式时任何图片都算另外还有个细节known集合初始化时只收录启动时间之前就存在的文件并用文件创建时间判定ScreenshotWatcher.swift#L45-L56。这样即使应用在等待桌面访问权限期间截图已经落地启动后也不会漏捡。收件箱模式的双保险默认情况下截图保存在桌面ScreenshotWatcher就监视桌面。开启收件箱模式后Inbox.swift 会把系统截图存储位置改到Application Support/Tendedero/Screenshots并关掉系统那个要等五秒的浮动缩略图——截图写完文件就直接被捡走。但作者仍多留了一层保险AppDelegate.swift#L119-L138 中若收件箱模式生效且目标不是桌面会额外再启一个监视桌面的安全监视器——万一某个 macOS 版本没遵守存储位置设置截图落回桌面也照样能挂上绳。而且所有系统设置的改动在应用退出时都会被还原macOS 永远不会指向一个没人监视的文件夹。小结一条清晰的调用链把本文内容串起来一张新截图的旅程是macOS 把文件写进截图目录临时文件 → 原子改名kqueue 报NOTE_WRITE/NOTE_RENAMEGCD 监视源在主线程被唤醒0.2 秒防抖后scan()遍历目录与known集合比对通过扩展名 kMDItemIsScreenCapture双重校验回调onNew→AppDelegate.hangCapture()生成缩略图截图从截屏区域飞到晾衣绳上想动手读源码的话建议路径是ScreenshotWatcher.swift本文主角→ Inbox.swift系统设置读写→ AppDelegate.swift装配与动画触发。下一篇我们来看 Line.swift 和 PeggedView.swift截图是怎么飞上绳、又怎么随风轻摆的。【免费下载链接】tendederoScreenshots, hung out to dry. A tiny native macOS app that hangs every screenshot on a line at the top of your screen.项目地址: https://gitcode.com/gh_mirrors/te/tendedero创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

刚性问题误差容限设置技巧

刚性问题误差容限设置技巧

刚性问题中如何设置合理误差容限 1. 误差容限的定义与作用 1.1 误差容限的分类 在 ODE 数值求解中,通常设置两种误差容限: 相对误差容限(rtol):用于衡量解的相对误差。绝对误差容限(atol)&a…

2026/10/12 18:59:18 阅读更多 →
操作系统实验避坑指南:从fork管道到strace调试

操作系统实验避坑指南:从fork管道到strace调试

简介:面向操作系统课程学习者的山东大学实验资料包,聚焦进程控制、管道通信、进程同步与调度等核心主题,适合本科阶段操作系统实验、课程设计及考研复习参考。压缩包共416个文件,以C/C源码、CMake/Makefile构建脚本、可直接运行的…

2026/10/11 18:58:03 阅读更多 →
GSEA基因集富集分析:从原理到实战的完整指南

GSEA基因集富集分析:从原理到实战的完整指南

1. 为什么我们需要GSEA:从“单打独斗”到“团队作战”的思维转变做过表达谱分析的人都有过这种经历:辛辛苦苦跑完差异表达分析,拿到一张几千个基因的列表,然后呢?盯着满屏的基因名发呆,试图从里面看出点生物…

2026/10/11 19:00:39 阅读更多 →

最新新闻

个人站长AI可见性监测:Python+Playwright自动化采集实战

个人站长AI可见性监测:Python+Playwright自动化采集实战

个人站长最怕的一件事,不是服务器宕机,也不是流量下滑,而是某天你搜自己的品牌词,发现首页全是别人的内容,自己的站点连影子都找不到。更麻烦的是,你根本不知道是哪个环节出了问题——是内容没被收录&#…

2026/10/15 8:43:52 阅读更多 →
Babel核心原理与前端工程实践指南

Babel核心原理与前端工程实践指南

1. 为什么我们需要Babel前端开发者们一定都经历过这样的困境:当你兴冲冲地写下一段优雅的ES6代码,却发现它在老版本浏览器中完全无法运行。这种兼容性问题就像一道无形的墙,阻碍着我们使用最新的语言特性。而Babel,就是打破这堵墙…

2026/10/15 8:43:52 阅读更多 →
基于.NET MAUI手搓零信任套壳浏览器:从身份认证到流量拦截的落地实践

基于.NET MAUI手搓零信任套壳浏览器:从身份认证到流量拦截的落地实践

“套壳浏览器”在不少开发者耳朵里,多少带点贬义——无非是WebView包一层,加载远程页面,连个原生功能都没有。但真在一线做过企业移动办公类项目的朋友应该懂,这种“壳”恰恰是很多业务系统绕不开的交付形态:HTML5业务…

2026/10/15 8:43:52 阅读更多 →
COMSOL模拟优化煤矿瓦斯抽采的混合气体注入技术

COMSOL模拟优化煤矿瓦斯抽采的混合气体注入技术

1. 项目背景与核心价值在煤矿开采领域,瓦斯抽采效率直接关系到井下作业安全与资源回收率。传统单一气体抽采往往面临渗透率低、抽采周期长等问题。我们团队通过COMSOL Multiphysics数值模拟发现,N₂和CO₂混合气体注入可显著改善煤层瓦斯解吸-渗流特性。…

2026/10/15 8:43:52 阅读更多 →
OffscreenCanvas+Web Worker优化图片处理性能

OffscreenCanvas+Web Worker优化图片处理性能

1. 项目背景与痛点解析上周在优化公司电商小程序时,遇到一个棘手问题:用户上传的图片需要支持本地旋转和格式转换,但实测发现当图片超过2MB时,操作延迟高达3-4秒,部分低端机型甚至直接卡死。通过性能分析发现&#xff…

2026/10/15 8:43:52 阅读更多 →
高校论文AI检测率飙升:技术、政策与应对策略

高校论文AI检测率飙升:技术、政策与应对策略

1. 论文AI检测率飙升现象观察最近一年来,高校论文检测系统中AI生成内容的识别率呈现显著上升趋势。以某985高校文科院系为例,2023年秋季学期毕业论文初检中,约38%的论文被系统标记为"疑似AI生成内容",这个数字较去年同期…

2026/10/15 8:42:52 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →