DeskPest(Vibe Coding)

发布时间:2026/10/29 11:08:30
DeskPest(Vibe Coding) 本地Windows剪贴板的持久化扩展操作支持持久化记录复制到剪贴板的内容记录其来源以及按照类别存储主要核心就是监听电脑本身的剪贴板然后记录内容。主要支持的格式文本、图像、html、文件路径项目结构saveUserAction\├─ clipboard_monitor/ ← 监听端捕获剪贴板并落盘│ ├─ __main__.py 命令行入口│ ├─ monitor.py 窗口消息循环 保存线程│ ├─ reader.py 按格式识别并读取剪贴板│ ├─ storage.py ClipboardStore写文件 追加索引│ └─ __init__.py 对外导出├─ server/ ← 查看端Flask Web 服务│ ├─ web_server.py 路由与 HTTP 接口│ ├─ storage.py 读取层索引、搜索、星标、删除、统计│ └─ templates/│ └─ index.html 单页前端浅色主题├─ clipboard_data/ ← 数据目录两端共用│ ├─ 2026-10-28/│ │ ├─ text/ html/ image/ files/ 按类型分目录│ │ └─ index.json 当日索引│ └─ stars.json首次收藏时才生成├─ requirements.txt pywin32 / Pillow / flask监听端定义monitor.py监听 Windows 剪贴板变化并触发保存。 使用 AddClipboardFormatListener 接收 WM_CLIPBOARDUPDATE不做轮询 读取动作放到独立线程避免阻塞窗口消息循环导致事件丢失。 from __future__ import annotations import ctypes import queue import threading import time from typing import Callable import win32api import win32clipboard import win32gui from .reader import read_clipboard from .storage import ClipboardStore WM_CLIPBOARDUPDATE 0x031D def get_foreground_title() - str: 记录复制发生时所在窗口便于回溯来源。 try: return win32gui.GetWindowText(win32gui.GetForegroundWindow()) or 未知窗口 except Exception: return 未知窗口 class ClipboardMonitor: 启动后常驻任何复制动作都会按类型保存到磁盘。 def __init__( self, store: ClipboardStore, on_saved: Callable[[dict], None] | None None, ): self.store store self.on_saved on_saved or print_entry self._queue: queue.Queue[None] queue.Queue() self._worker threading.Thread( targetself._consume, nameclipboard-saver, daemonTrue ) self._hwnd: int | None None self._class_atom: int | None None self._last_seq -1 self._running True def start(self) - None: self._worker.start() hinst win32api.GetModuleHandle(None) wc win32gui.WNDCLASS() wc.lpfnWndProc self._wnd_proc wc.lpszClassName fClipboardMonitor_{id(self)} wc.hInstance hinst self._class_atom win32gui.RegisterClass(wc) self._hwnd win32gui.CreateWindowEx( 0, self._class_atom, ClipboardMonitor, 0, 0, 0, 0, 0, 0, 0, hinst, None ) if not ctypes.windll.user32.AddClipboardFormatListener(self._hwnd): raise ctypes.WinError() # print(f剪贴板监听已启动存储目录: {self.store.root.resolve()}) try: # 用短间隔泵消息保证 CtrlC 能及时响应同时不轮询剪贴板本身 while self._running: win32gui.PumpWaitingMessages() time.sleep(0.05) except KeyboardInterrupt: pass finally: self.stop() def stop(self) - None: self._running False if self._hwnd: ctypes.windll.user32.RemoveClipboardFormatListener(self._hwnd) win32gui.DestroyWindow(self._hwnd) self._hwnd None def _wnd_proc(self, hwnd, msg, wparam, lparam): if msg WM_CLIPBOARDUPDATE: self._queue.put(None) return win32gui.DefWindowProc(hwnd, msg, wparam, lparam) def _consume(self) - None: while True: self._queue.get() try: self._save_current() except Exception as exc: # 单次失败不影响后续监听 print(f[警告] 读取剪贴板失败: {exc}) def _save_current(self) - None: seq win32clipboard.GetClipboardSequenceNumber() if seq self._last_seq: return item read_clipboard() if item is None: return self._last_seq seq entry self.store.save(item, sourceget_foreground_title()) if entry: self.on_saved(entry) def print_entry(entry: dict) - None: stamp entry[timestamp].replace(T, ) print(f[{stamp}] {entry[type]:5s} {entry[path]}) print(f 来源: {entry[source_app]}) print(f 预览: {entry[preview][:80]})monitor的简单解释关于监听部分的注册# 负责开启对应的消费线程又self.queue()触发这个触发逻辑是当有新的消息会进行回调函数_wnd_proc的调用然后向队列写入消息然后对应的线程发现队列有新的数据会结束阻塞取出数据进行后面的消费 self._worker.start() # 这个地方的核心意义就是向Windows注册一个独立于剪贴板的信箱定义回调函数监听剪贴板变化 hinst win32api.GetModuleHandle(None) wc win32gui.WNDCLASS() wc.lpfnWndProc self._wnd_proc wc.lpszClassName fClipboardMonitor_{id(self)} wc.hInstance hinst self._class_atom win32gui.RegisterClass(wc) self._hwnd win32gui.CreateWindowEx( 0, self._class_atom, ClipboardMonitor, 0, 0, 0, 0, 0, 0, 0, hinst, None) if not ctypes.windll.user32.AddClipboardFormatListener(self._hwnd): raise ctypes.WinError() # 这个地方是从定义的信箱取出数据的核心所以需要常驻用一个while循环保证 # 这个地方隔一段时间取出数据然后会清除执行对应的回调函数回调函数触发消费流程进行存储 try: # 用短间隔泵消息保证 CtrlC 能及时响应同时不轮询剪贴板本身 while self._running: win32gui.PumpWaitingMessages() time.sleep(0.05) except KeyboardInterrupt: pass finally: self.stop()关于触发消费# 回调函数向队列插入数据解除_consume的阻塞状态 def _wnd_proc(self, hwnd, msg, wparam, lparam): if msg WM_CLIPBOARDUPDATE: self._queue.put(None) return win32gui.DefWindowProc(hwnd, msg, wparam, lparam) def _consume(self) - None: while True: self._queue.get() try: self._save_current() except Exception as exc: # 单次失败不影响后续监听 print(f[警告] 读取剪贴板失败: {exc}) def _save_current(self) - None: seq win32clipboard.GetClipboardSequenceNumber() if seq self._last_seq: return item read_clipboard() if item is None: return self._last_seq seq entry self.store.save(item, sourceget_foreground_title()) if entry: self.on_saved(entry)其中read_clipboard()取出数据对应的是reader.pyself.store.save(item, sourceget_foreground_title())对应的是storage.py剩余的代码这个地方主要核心就是为了记录比较不好理解的注册与消费部分的逻辑其他的就是正常的前后端相关curd操作gitee链接https://gitee.com/xie-da-da/saveUserAction.git如果有啥问题可以交流。其次这个本身是为了本地使用的没有太多的性能或安全考虑

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询