Skip to content

Add scrolling capture of the window under the cursor - #2097

Open
x1xhlol wants to merge 11 commits into
CapSoftware:mainfrom
x1xhlol:feat/scrolling-capture
Open

Add scrolling capture of the window under the cursor#2097
x1xhlol wants to merge 11 commits into
CapSoftware:mainfrom
x1xhlol:feat/scrolling-capture

Conversation

@x1xhlol

@x1xhlol x1xhlol commented Aug 6, 2026

Copy link
Copy Markdown

Summary

Adds scrolling capture: a new hotkey action ("Scrolling capture of window under cursor", unbound by default) that captures an entire scrollable window — not just the visible part — by scrolling it and stitching the frames into one tall screenshot, saved as a normal Cap screenshot project.

How it works (scrolling_capture.rs):

capture window frame
loop (≤60 steps, ≤16000px):
    inject 2 wheel notches at the cursor (SendInput on Windows,
    CGEventCreateScrollWheelEvent2 on macOS) → wait 600ms for
    smooth-scroll to settle → capture next frame
    → detect vertical offset: minimal mean-absolute-difference over
      overlapping rows (top 20% skipped for sticky headers, ≥25%
      overlap required, 1px granularity)
    → offset == 0 (bottom reached) or no match → stop
    → append the frame's new bottom rows to the stitched image
  • The hotkey targets the window under the cursor (same pattern as the existing "Screenshot current window" action), so the injected wheel events reach the right window.
  • The stitched image goes through the normal screenshot-project save path: same toast, automations, editor-open behavior, library entry.
  • No new dependencies; the stitching is a few dozen lines over image buffers.
  • Known cosmetic limitation: sticky side columns (e.g. Wikipedia's TOC panel) repeat down the image — only top-anchored sticky content is compensated.

Showcase

A 60-section page captured into one 1280x7404 image:

Stitched 7404px-tall capture

Bottom of the stitch — capture stops at the page footer with no repeated content:

Footer reached, no repeats

Testing (Windows, end-to-end on a live dev build)

Test Result
60-section long page → 1280x7404 stitch, all sections in order, zero seam artifacts
Stops at page bottom (footer present, nothing repeated)
Wikipedia article → 1280x12680 continuous stitch (hit the 60-frame cap on a very long article)
Non-scrolling window → single frame in ~5s, no hang
Toast + normal .cap screenshot project on every run
Regression: normal screenshot flow unaffected

macOS compiles the same capture/stitch path with a CoreGraphics scroll-event injector; runtime-tested on Windows only.

Builds on #2095 (OCR text capture — shares its capture/save helpers); the scrolling-capture change itself is the top two commits.

Greptile Summary

This PR adds window scrolling capture, OCR area capture, associated hotkeys and settings, and refactors screenshot capture/saving into reusable backend helpers.

  • Adds platform-specific synthetic scrolling and frame stitching for whole-window screenshots.
  • Adds OCR selection, clipboard, notification, and optional screenshot-preservation flows.
  • Extends persisted settings, hotkey actions, target-selection UI, window handling, and Tauri IPC bindings.

Confidence Score: 3/5

The PR should not merge until scrolling captures are capped before appending oversized strips and the Linux action is either implemented or disabled.

Near-limit captures can produce images rejected by the screenshot editor, while Linux exposes an action whose scroll injector performs no operation and therefore cannot capture off-screen content.

Files Needing Attention: apps/desktop/src-tauri/src/scrolling_capture.rs, apps/desktop/src/routes/(window-chrome)/settings/hotkeys.tsx, apps/desktop/src/utils/tauri.ts

Important Files Changed

Filename Overview
apps/desktop/src-tauri/src/scrolling_capture.rs Implements scrolling and stitching, but can exceed the image-height cap and silently degenerates to a single-frame capture on Linux.
apps/desktop/src-tauri/src/hotkeys.rs Adds OCR and scrolling-capture actions plus default OCR hotkey seeding; the scrolling action reaches the unsupported Linux implementation.
apps/desktop/src-tauri/src/recording.rs Refactors image capture and project saving and adds OCR capture while preserving the existing asynchronous PNG-save behavior.
apps/desktop/src/routes/target-select-overlay.tsx Adds OCR area-selection capture and explicit success/error overlay lifecycle handling.
apps/desktop/src/utils/tauri.ts Updates generated IPC bindings, contrary to the repository rule prohibiting direct changes to generated tauri.ts files.
apps/desktop/src-tauri/src/general_settings.rs Adds backward-compatible defaulted OCR preferences.
apps/desktop/src-tauri/src/lib.rs Correctly registers the new commands and scrolling-capture module.
Prompt To Fix All With AI
### Issue 1
apps/desktop/src-tauri/src/scrolling_capture.rs:74-83
**Height cap checked too late**

When a capture is near 16,000 pixels, the full next strip is appended before the cap is checked, allowing the result to exceed the screenshot editor's 16,384-pixel limit and fail to open.

```suggestion
        let remaining_height = MAX_STITCHED_HEIGHT.saturating_sub(stitched_height);
        let new_rows = offset.min(frame_height).min(remaining_height);
        if new_rows == 0 {
            debug!("Stitched image reached the height cap; stopping");
            break;
        }

        let strip = frame.crop_imm(0, frame_height - new_rows, frame_width, new_rows);
        stitched.push(strip);
        stitched_height += new_rows;
        prev = cur;

        if stitched_height >= MAX_STITCHED_HEIGHT {
            debug!("Stitched image reached the height cap; stopping");
            break;
        }
```

### Issue 2
apps/desktop/src-tauri/src/scrolling_capture.rs:158-187
**Linux scroll injection is absent**

When a Linux user invokes the exposed scrolling-capture hotkey, `inject_scroll` performs no operation, so the loop waits once and saves only the initially visible frame instead of capturing off-screen content.

### Issue 3
apps/desktop/src/utils/tauri.ts:59-70
**Generated bindings changed directly**

This directly modifies the generated `tauri.ts` IPC surface and includes unrelated generated type churn. These changes can be overwritten during regeneration and leave the checked-in bindings out of sync; regenerate the file from the Rust command definitions instead.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "Tune scrolling capture stepping and matc..." | Re-trigger Greptile

Greptile also left 3 inline comments on this PR.

Context used (3)

Comment thread apps/desktop/src-tauri/src/scrolling_capture.rs Outdated
Comment thread apps/desktop/src-tauri/src/scrolling_capture.rs
Comment thread apps/desktop/src/utils/tauri.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant