DEV Community

Akif Mansoor
Akif Mansoor

Posted on

I built a tray app that captures highlights from any Windows app into a local SQLite database

The problem

I do a lot of reading for research — PDFs in one window, Word docs in another, a dozen browser tabs I swore I'd get back to. Every workflow I tried for capturing highlights involved the same tax: alt-tab to Notion, paste, retype the source, retype the tags, alt-tab back. By the third paper of the day I'd just stopped bothering, and six months later I had no idea which PDF a quote came from.

So I built NotesDB — a small Python app that lives in the Windows system tray and captures text, screenshots, and notes from any application without you ever leaving what you're reading.

What it actually does

Three ways to capture, all landing in the same local database:

  1. Global hotkey. Select text anywhere — Word, a PDF reader, Chrome — and hit Ctrl+Shift+V. A save dialog pops up instantly, pre-filled with the source app, window title, and file path.
  2. Clipboard watcher. Copy normally with Ctrl+C. A small toast appears near your cursor for a few seconds; click it to save, ignore it and it disappears. No dialog if you don't want one.
  3. Browser extension. Right-click selected text or an image in Chrome/Edge → "Save to NotesDB."

Everything lands in a single SQLite file (notes.db) with tags, colour-coding, project grouping, and auto-matched "connected notes" between related captures. There's also a built-in PDF reader with a snapshot tool (drag a rectangle, grab a region as an image), a highlighter, and text selection — so I stopped needing Adobe open at all.

How it's put together

The core is Python + Tkinter — no Electron, no web framework for the main UI, which keeps the installed footprint small (the whole PyInstaller build comes in under 30MB). A few pieces worth calling out:

The clipboard watcher runs as a daemon thread polling every 500ms:

class ClipboardWatcher(threading.Thread):
    def run(self):
        last = None
        while True:
            current = get_clipboard_content()  # text or image
            if current != last:
                pos = win32api.GetCursorPos()
                capture_queue.put({"content": current, "cursor": pos, "_clipboard": True})
                last = current
            time.sleep(0.5)
Enter fullscreen mode Exit fullscreen mode

The main app polls that queue every 200ms and hands items off to a capture handler — deliberately decoupled so a bad capture never kills the watcher thread.

Theming is done through module-level colour globals, not a class or CSS-like system. There are six built-in themes (Dark, Light, Ocean, Midnight, Forest, Warm), and switching one calls _apply_theme_globals(), which reassigns every colour constant (BG, FG, ACCENT, etc.) app-wide, then triggers a redraw. Every custom-drawn widget — cards, the floating capture dialog, the PDF reader overlays — reads from the same globals, so nothing gets out of sync.

Citations are pulled live from CrossRef. If a captured source has a DOI (or one can be inferred from the URL), a "Get Citation" button formats it as APA on the spot — genuinely one of the more satisfying small features to ship.

Source detection uses win32gui + psutil to figure out which app and, where possible, which file a selection came from — so a highlight from a PDF gets tagged with the actual filename and full path, not just "some PDF reader."

What I'd do differently

If I started over I'd probably reach for a proper widget toolkit sooner — hand-rolling rounded-corner cards on a Tkinter Canvas works, but it's a lot of geometry math for something a real UI framework gives you for free. The tradeoff was a genuinely tiny, dependency-light executable, which for a tray app I'm fine with.

Where it's at now

It's a real, working Windows app today — installer, tray icon, PDF reader, exports to DOCX/PDF/TXT, the whole thing. Local-only by design: your data is one SQLite file, there's no account, no sync service, nothing phoning home.

If capturing research across PDFs/browser/Word without breaking flow is a problem you also have, I'd love feedback — happy to answer questions about the clipboard-polling approach, the theming system, or anything else in the comments.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.