Add scrolling capture of the window under the cursor - #2097
Conversation
…notification setting, avoid revealing main window after OCR, restore macOS diagnostics bindings
| let new_rows = offset.min(frame_height); | ||
| 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; | ||
| } |
There was a problem hiding this comment.
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.
| let new_rows = offset.min(frame_height); | |
| 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; | |
| } | |
| 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; | |
| } |
Knowledge Base Used: Desktop Tauri App (Rust Backend)
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/scrolling_capture.rs
Line: 74-83
Comment:
**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;
}
```
**Knowledge Base Used:** [Desktop Tauri App (Rust Backend)](https://app.greptile.com/cap/-/custom-context/knowledge-base/capsoftware/cap/-/docs/desktop-tauri-app.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| #[allow(unused_variables)] | ||
| fn inject_scroll(notches: i32) { | ||
| #[cfg(windows)] | ||
| { | ||
| use ::windows::Win32::UI::Input::KeyboardAndMouse::{ | ||
| INPUT, INPUT_0, INPUT_MOUSE, MOUSEEVENTF_WHEEL, MOUSEINPUT, SendInput, | ||
| }; | ||
|
|
||
| const WHEEL_DELTA: i32 = 120; | ||
|
|
||
| let input = INPUT { | ||
| r#type: INPUT_MOUSE, | ||
| Anonymous: INPUT_0 { | ||
| mi: MOUSEINPUT { | ||
| dx: 0, | ||
| dy: 0, | ||
| mouseData: (notches * WHEEL_DELTA) as u32, | ||
| dwFlags: MOUSEEVENTF_WHEEL, | ||
| time: 0, | ||
| dwExtraInfo: 0, | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| unsafe { | ||
| SendInput(&[input], std::mem::size_of::<INPUT>() as i32); | ||
| } | ||
| } | ||
|
|
||
| #[cfg(target_os = "macos")] |
There was a problem hiding this comment.
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.
Knowledge Base Used: Desktop Tauri App (Rust Backend)
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/scrolling_capture.rs
Line: 158-187
Comment:
**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.
**Knowledge Base Used:** [Desktop Tauri App (Rust Backend)](https://app.greptile.com/cap/-/custom-context/knowledge-base/capsoftware/cap/-/docs/desktop-tauri-app.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| async takeScreenshot(target: ScreenCaptureTarget) : Promise<string> { | ||
| return await TAURI_INVOKE("take_screenshot", { target }); | ||
| }, | ||
| async captureOcrText(target: ScreenCaptureTarget) : Promise<string> { | ||
| return await TAURI_INVOKE("capture_ocr_text", { target }); | ||
| }, | ||
| async captureScrollingWindow(windowId: WindowId) : Promise<string> { | ||
| return await TAURI_INVOKE("capture_scrolling_window", { windowId }); | ||
| }, | ||
| async importCurrentDesktopBackground(projectPath: string) : Promise<string> { | ||
| return await TAURI_INVOKE("import_current_desktop_background", { projectPath }); | ||
| }, |
There was a problem hiding this comment.
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.
Context Used: AGENTS.md (source)
Knowledge Base Used: Desktop Frontend (apps/desktop/src)
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/utils/tauri.ts
Line: 59-70
Comment:
**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.
**Context Used:** AGENTS.md ([source](https://github.com/capsoftware/cap/blob/main/AGENTS.md))
**Knowledge Base Used:** [Desktop Frontend (apps/desktop/src)](https://app.greptile.com/cap/-/custom-context/knowledge-base/capsoftware/cap/-/docs/desktop-frontend.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
There was a problem hiding this comment.
These bindings match what specta regenerates from the Rust command definitions - the dev build regenerated tauri.ts after the capture_scrolling_window command was added and the checked-in file is byte-identical to the regenerated output, so it's in sync, not hand-drifted.
There was a problem hiding this comment.
That makes sense — if the file is byte-identical to the specta output after adding capture_scrolling_window, checking it in is the right move. The concern was about hand-drifted bindings, which doesn't apply here. This comment is resolved.
Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.
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):imagebuffers.Showcase
A 60-section page captured into one 1280x7404 image:
Bottom of the stitch — capture stops at the page footer with no repeated content:
Testing (Windows, end-to-end on a live dev build)
.capscreenshot project on every runmacOS 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.
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
Prompt To Fix All With AI
Reviews (1): Last reviewed commit: "Tune scrolling capture stepping and matc..." | Re-trigger Greptile
Context used (3)